downstream: Multiseat support for drm/wayland backends
[profile/ivi/weston-ivi-shell.git] / src / compositor-drm.c
index c34fc1c..d558f7d 100644 (file)
 #include <drm_fourcc.h>
 
 #include <gbm.h>
-#include <libbacklight.h>
 #include <libudev.h>
 
+#include "libbacklight.h"
 #include "compositor.h"
 #include "gl-renderer.h"
 #include "pixman-renderer.h"
-#include "udev-seat.h"
+#include "udev-input.h"
 #include "launcher-util.h"
 #include "vaapi-recorder.h"
 
 #define DRM_CAP_TIMESTAMP_MONOTONIC 0x6
 #endif
 
+#ifndef DRM_CAP_CURSOR_WIDTH
+#define DRM_CAP_CURSOR_WIDTH 0x8
+#endif
+
+#ifndef DRM_CAP_CURSOR_HEIGHT
+#define DRM_CAP_CURSOR_HEIGHT 0x9
+#endif
+
+#ifndef GBM_BO_USE_CURSOR
+#define GBM_BO_USE_CURSOR GBM_BO_USE_CURSOR_64X64
+#endif
+
 static int option_current_mode = 0;
 
 enum output_config {
@@ -108,6 +120,10 @@ struct drm_compositor {
 
        clockid_t clock;
        struct udev_input input;
+       char *main_seat;
+
+       uint32_t cursor_width;
+       uint32_t cursor_height;
 };
 
 struct drm_mode {
@@ -147,10 +163,12 @@ struct drm_output {
        drmModeCrtcPtr original_crtc;
        struct drm_edid edid;
        drmModePropertyPtr dpms_prop;
+       uint32_t format;
 
        int vblank_pending;
        int page_flip_pending;
        int destroy_pending;
+       int force_modeset;
 
        struct gbm_surface *surface;
        struct gbm_bo *cursor_bo[2];
@@ -420,8 +438,6 @@ static uint32_t
 drm_output_check_scanout_format(struct drm_output *output,
                                struct weston_surface *es, struct gbm_bo *bo)
 {
-       struct drm_compositor *c =
-               (struct drm_compositor *) output->base.compositor;
        uint32_t format;
        pixman_region32_t r;
 
@@ -431,9 +447,10 @@ drm_output_check_scanout_format(struct drm_output *output,
                /* We can scanout an ARGB buffer if the surface's
                 * opaque region covers the whole output, but we have
                 * to use XRGB as the KMS format code. */
-               pixman_region32_init(&r);
-               pixman_region32_subtract(&r, &output->base.region,
-                                        &es->opaque);
+               pixman_region32_init_rect(&r, 0, 0,
+                                         output->base.width,
+                                         output->base.height);
+               pixman_region32_subtract(&r, &r, &es->opaque);
 
                if (!pixman_region32_not_empty(&r))
                        format = GBM_FORMAT_XRGB8888;
@@ -441,7 +458,7 @@ drm_output_check_scanout_format(struct drm_output *output,
                pixman_region32_fini(&r);
        }
 
-       if (c->format == format)
+       if (output->format == format)
                return format;
 
        return 0;
@@ -455,6 +472,7 @@ drm_output_prepare_scanout_view(struct weston_output *_output,
        struct drm_compositor *c =
                (struct drm_compositor *) output->base.compositor;
        struct weston_buffer *buffer = ev->surface->buffer_ref.buffer;
+       struct weston_buffer_viewport *viewport = &ev->surface->buffer_viewport;
        struct gbm_bo *bo;
        uint32_t format;
 
@@ -463,7 +481,7 @@ drm_output_prepare_scanout_view(struct weston_output *_output,
            buffer == NULL || c->gbm == NULL ||
            buffer->width != output->base.current_mode->width ||
            buffer->height != output->base.current_mode->height ||
-           output->base.transform != ev->surface->buffer_viewport.transform ||
+           output->base.transform != viewport->buffer.transform ||
            ev->transform.enabled)
                return NULL;
 
@@ -506,7 +524,7 @@ drm_output_render_gl(struct drm_output *output, pixman_region32_t *damage)
                return;
        }
 
-       output->next = drm_fb_get_from_bo(bo, c, c->format);
+       output->next = drm_fb_get_from_bo(bo, c, output->format);
        if (!output->next) {
                weston_log("failed to get drm_fb for bo\n");
                gbm_surface_release_buffer(output->surface, bo);
@@ -597,7 +615,8 @@ drm_output_repaint(struct weston_output *output_base,
 
        mode = container_of(output->base.current_mode, struct drm_mode, base);
        if (!output->current ||
-           output->current->stride != output->next->stride) {
+           output->current->stride != output->next->stride ||
+           output->force_modeset) {
                ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
                                     output->next->fb_id, 0, 0,
                                     &output->connector_id, 1,
@@ -607,6 +626,7 @@ drm_output_repaint(struct weston_output *output_base,
                        goto err_pageflip;
                }
                output_base->set_dpms(output_base, WESTON_DPMS_ON);
+               output->force_modeset = 0;
        }
 
        if (drmModePageFlip(compositor->drm.fd, output->crtc_id,
@@ -668,6 +688,7 @@ drm_output_repaint(struct weston_output *output_base,
        return 0;
 
 err_pageflip:
+       output->cursor_view = NULL;
        if (output->next) {
                drm_output_release_fb(output, output->next);
                output->next = NULL;
@@ -777,8 +798,8 @@ drm_output_check_sprite_format(struct drm_sprite *s,
                pixman_region32_t r;
 
                pixman_region32_init_rect(&r, 0, 0,
-                                         ev->geometry.width,
-                                         ev->geometry.height);
+                                         ev->surface->width,
+                                         ev->surface->height);
                pixman_region32_subtract(&r, &r, &ev->surface->opaque);
 
                if (!pixman_region32_not_empty(&r))
@@ -807,6 +828,7 @@ drm_output_prepare_overlay_view(struct weston_output *output_base,
 {
        struct weston_compositor *ec = output_base->compositor;
        struct drm_compositor *c =(struct drm_compositor *) ec;
+       struct weston_buffer_viewport *viewport = &ev->surface->buffer_viewport;
        struct drm_sprite *s;
        int found = 0;
        struct gbm_bo *bo;
@@ -818,10 +840,10 @@ drm_output_prepare_overlay_view(struct weston_output *output_base,
        if (c->gbm == NULL)
                return NULL;
 
-       if (ev->surface->buffer_viewport.transform != output_base->transform)
+       if (viewport->buffer.transform != output_base->transform)
                return NULL;
 
-       if (ev->surface->buffer_viewport.scale != output_base->current_scale)
+       if (viewport->buffer.scale != output_base->current_scale)
                return NULL;
 
        if (c->sprites_are_broken)
@@ -882,7 +904,7 @@ drm_output_prepare_overlay_view(struct weston_output *output_base,
 
        /*
         * Calculate the source & dest rects properly based on actual
-        * position (note the caller has called weston_surface_update_transform()
+        * position (note the caller has called weston_view_update_transform()
         * for us already).
         */
        pixman_region32_init(&dest_rect);
@@ -919,20 +941,20 @@ drm_output_prepare_overlay_view(struct weston_output *output_base,
                sx1 = 0;
        if (sy1 < 0)
                sy1 = 0;
-       if (sx2 > wl_fixed_from_int(ev->geometry.width))
-               sx2 = wl_fixed_from_int(ev->geometry.width);
-       if (sy2 > wl_fixed_from_int(ev->geometry.height))
-               sy2 = wl_fixed_from_int(ev->geometry.height);
+       if (sx2 > wl_fixed_from_int(ev->surface->width))
+               sx2 = wl_fixed_from_int(ev->surface->width);
+       if (sy2 > wl_fixed_from_int(ev->surface->height))
+               sy2 = wl_fixed_from_int(ev->surface->height);
 
        tbox.x1 = sx1;
        tbox.y1 = sy1;
        tbox.x2 = sx2;
        tbox.y2 = sy2;
 
-       tbox = weston_transformed_rect(wl_fixed_from_int(ev->geometry.width),
-                                      wl_fixed_from_int(ev->geometry.height),
-                                      ev->surface->buffer_viewport.transform,
-                                      ev->surface->buffer_viewport.scale,
+       tbox = weston_transformed_rect(wl_fixed_from_int(ev->surface->width),
+                                      wl_fixed_from_int(ev->surface->height),
+                                      viewport->buffer.transform,
+                                      viewport->buffer.scale,
                                       tbox);
 
        s->src_x = tbox.x1 << 8;
@@ -950,12 +972,15 @@ drm_output_prepare_cursor_view(struct weston_output *output_base,
 {
        struct drm_compositor *c =
                (struct drm_compositor *) output_base->compositor;
+       struct weston_buffer_viewport *viewport = &ev->surface->buffer_viewport;
        struct drm_output *output = (struct drm_output *) output_base;
 
        if (c->gbm == NULL)
                return NULL;
        if (output->base.transform != WL_OUTPUT_TRANSFORM_NORMAL)
                return NULL;
+       if (viewport->buffer.scale != output_base->current_scale)
+               return NULL;
        if (output->cursor_view)
                return NULL;
        if (ev->output_mask != (1u << output_base->id))
@@ -964,7 +989,7 @@ drm_output_prepare_cursor_view(struct weston_output *output_base,
                return NULL;
        if (ev->surface->buffer_ref.buffer == NULL ||
            !wl_shm_buffer_get(ev->surface->buffer_ref.buffer->resource) ||
-           ev->geometry.width > 64 || ev->geometry.height > 64)
+           ev->surface->width > 64 || ev->surface->height > 64)
                return NULL;
 
        output->cursor_view = ev;
@@ -981,7 +1006,7 @@ drm_output_set_cursor(struct drm_output *output)
                (struct drm_compositor *) output->base.compositor;
        EGLint handle, stride;
        struct gbm_bo *bo;
-       uint32_t buf[64 * 64];
+       uint32_t buf[c->cursor_width * c->cursor_height];
        unsigned char *s;
        int i, x, y;
 
@@ -1003,17 +1028,17 @@ drm_output_set_cursor(struct drm_output *output)
                stride = wl_shm_buffer_get_stride(buffer->shm_buffer);
                s = wl_shm_buffer_get_data(buffer->shm_buffer);
                wl_shm_buffer_begin_access(buffer->shm_buffer);
-               for (i = 0; i < ev->geometry.height; i++)
-                       memcpy(buf + i * 64, s + i * stride,
-                              ev->geometry.width * 4);
+               for (i = 0; i < ev->surface->height; i++)
+                       memcpy(buf + i * c->cursor_width, s + i * stride,
+                              ev->surface->width * 4);
                wl_shm_buffer_end_access(buffer->shm_buffer);
 
                if (gbm_bo_write(bo, buf, sizeof buf) < 0)
                        weston_log("failed update cursor: %m\n");
 
                handle = gbm_bo_get_handle(bo).s32;
-               if (drmModeSetCursor(c->drm.fd,
-                                    output->crtc_id, handle, 64, 64)) {
+               if (drmModeSetCursor(c->drm.fd, output->crtc_id, handle,
+                               c->cursor_width, c->cursor_height)) {
                        weston_log("failed to set cursor: %m\n");
                        c->cursors_are_broken = 1;
                }
@@ -1071,7 +1096,7 @@ drm_assign_planes(struct weston_output *output)
                if (c->use_pixman ||
                    (es->buffer_ref.buffer &&
                    (!wl_shm_buffer_get(es->buffer_ref.buffer->resource) ||
-                    (ev->geometry.width <= 64 && ev->geometry.height <= 64))))
+                    (ev->surface->width <= 64 && ev->surface->height <= 64))))
                        es->keep_buffer = 1;
                else
                        es->keep_buffer = 0;
@@ -1146,7 +1171,6 @@ drm_output_destroy(struct weston_output *output_base)
        weston_plane_release(&output->cursor_plane);
 
        weston_output_destroy(&output->base);
-       wl_list_remove(&output->base.link);
 
        free(output);
 }
@@ -1291,6 +1315,18 @@ init_drm(struct drm_compositor *ec, struct udev_device *device)
        else
                ec->clock = CLOCK_REALTIME;
 
+       ret = drmGetCap(fd, DRM_CAP_CURSOR_WIDTH, &cap);
+       if (ret == 0)
+               ec->cursor_width = cap;
+       else
+               ec->cursor_width = 64;
+
+       ret = drmGetCap(fd, DRM_CAP_CURSOR_HEIGHT, &cap);
+       if (ret == 0)
+               ec->cursor_height = cap;
+       else
+               ec->cursor_height = 64;
+
        return 0;
 }
 
@@ -1527,12 +1563,13 @@ find_crtc_for_connector(struct drm_compositor *ec,
 static int
 drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec)
 {
+       EGLint format = output->format;
        int i, flags;
 
        output->surface = gbm_surface_create(ec->gbm,
                                             output->base.current_mode->width,
                                             output->base.current_mode->height,
-                                            ec->format,
+                                            format,
                                             GBM_BO_USE_SCANOUT |
                                             GBM_BO_USE_RENDERING);
        if (!output->surface) {
@@ -1540,21 +1577,23 @@ drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec)
                return -1;
        }
 
-       if (gl_renderer->output_create(&output->base, output->surface) < 0) {
+       if (gl_renderer->output_create(&output->base, output->surface,
+                                      gl_renderer->opaque_attribs,
+                                      &format) < 0) {
                weston_log("failed to create gl renderer output state\n");
                gbm_surface_destroy(output->surface);
                return -1;
        }
 
-       flags = GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE;
+       flags = GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE;
 
        for (i = 0; i < 2; i++) {
                if (output->cursor_bo[i])
                        continue;
 
                output->cursor_bo[i] =
-                       gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
-                                     flags);
+                       gbm_bo_create(ec->gbm, ec->cursor_width, ec->cursor_height,
+                               GBM_FORMAT_ARGB8888, flags);
        }
 
        if (output->cursor_bo[0] == NULL || output->cursor_bo[1] == NULL) {
@@ -1841,14 +1880,50 @@ setup_output_seat_constraint(struct drm_compositor *ec,
                struct udev_seat *seat;
 
                seat = udev_seat_get_named(&ec->base, s);
-               if (seat)
-                       seat->base.output = output;
-
-               if (seat && seat->base.pointer)
-                       weston_pointer_clamp(seat->base.pointer,
+               if (seat) {
+                       udev_seat_link_output(seat, output);
+#if HAVE_MULTISEAT
+                       if (!seat->input.libinput)
+                               udev_input_init(&seat->input, &ec->base,
+                                               ec->udev, s);
+                       else if (seat->input.suspended)
+                               udev_input_enable(&seat->input);
+#endif
+                       if (seat->base.pointer)
+                               weston_pointer_clamp(seat->base.pointer,
                                             &seat->base.pointer->x,
                                             &seat->base.pointer->y);
+               }
+       }
+}
+
+static int
+get_gbm_format_from_section(struct weston_config_section *section,
+                           uint32_t default_value,
+                           uint32_t *format)
+{
+       char *s;
+       int ret = 0;
+
+       weston_config_section_get_string(section,
+                                        "gbm-format", &s, NULL);
+
+       if (s == NULL)
+               *format = default_value;
+       else if (strcmp(s, "xrgb8888") == 0)
+               *format = GBM_FORMAT_XRGB8888;
+       else if (strcmp(s, "rgb565") == 0)
+               *format = GBM_FORMAT_RGB565;
+       else if (strcmp(s, "xrgb2101010") == 0)
+               *format = GBM_FORMAT_XRGB2101010;
+       else {
+               weston_log("fatal: unrecognized pixel format: %s\n", s);
+               ret = -1;
        }
+
+       free(s);
+
+       return ret;
 }
 
 static int
@@ -1858,7 +1933,7 @@ create_output_for_connector(struct drm_compositor *ec,
                            int x, int y, struct udev_device *drm_device)
 {
        struct drm_output *output;
-       struct drm_mode *drm_mode, *next, *preferred, *current, *configured;
+       struct drm_mode *drm_mode, *next, *preferred, *current, *configured, *best;
        struct weston_mode *m;
        struct weston_config_section *section;
        drmModeEncoder *encoder;
@@ -1869,6 +1944,7 @@ create_output_for_connector(struct drm_compositor *ec,
        const char *type_name;
        enum output_config config;
        uint32_t transform;
+       int default_output;
 
        i = find_crtc_for_connector(ec, resources, connector);
        if (i < 0) {
@@ -1917,8 +1993,18 @@ create_output_for_connector(struct drm_compositor *ec,
        weston_config_section_get_string(section, "transform", &s, "normal");
        transform = parse_transform(s, output->base.name);
        free(s);
+       weston_config_section_get_int(section, "default_output",
+                                     &default_output, 0);
+
+       if (get_gbm_format_from_section(section,
+                                       ec->format,
+                                       &output->format) == -1)
+               output->format = ec->format;
 
        weston_config_section_get_string(section, "seat", &s, "");
+       output->base.seat_data.seatname = strdup(s);
+       weston_log("output %p belongs to seat '%s'\n", output,
+                       output->base.seat_data.seatname);
        setup_output_seat_constraint(ec, &output->base, s);
        free(s);
 
@@ -1961,6 +2047,7 @@ create_output_for_connector(struct drm_compositor *ec,
        preferred = NULL;
        current = NULL;
        configured = NULL;
+       best = NULL;
 
        wl_list_for_each_reverse(drm_mode, &output->base.mode_list, base.link) {
                if (config == OUTPUT_CONFIG_MODE &&
@@ -1971,6 +2058,7 @@ create_output_for_connector(struct drm_compositor *ec,
                        current = drm_mode;
                if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
                        preferred = drm_mode;
+               best = drm_mode;
        }
 
        if (config == OUTPUT_CONFIG_MODELINE) {
@@ -1996,6 +2084,8 @@ create_output_for_connector(struct drm_compositor *ec,
                output->base.current_mode = &preferred->base;
        else if (current)
                output->base.current_mode = &current->base;
+       else if (best)
+               output->base.current_mode = &best->base;
 
        if (output->base.current_mode == NULL) {
                weston_log("no available modes for %s\n", output->base.name);
@@ -2030,6 +2120,8 @@ create_output_for_connector(struct drm_compositor *ec,
        }
 
        wl_list_insert(ec->base.output_list.prev, &output->base.link);
+       if (default_output)
+               ec->base.default_output = &output->base;
 
        find_and_parse_output_edid(ec, output, connector);
        if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)
@@ -2055,7 +2147,7 @@ create_output_for_connector(struct drm_compositor *ec,
        weston_log("Output %s, (connector %d, crtc %d)\n",
                   output->base.name, output->connector_id, output->crtc_id);
        wl_list_for_each(m, &output->base.mode_list, link)
-               weston_log_continue("  mode %dx%d@%.1f%s%s%s\n",
+               weston_log_continue(STAMP_SPACE "mode %dx%d@%.1f%s%s%s\n",
                                    m->width, m->height, m->refresh / 1000.0,
                                    m->flags & WL_OUTPUT_MODE_PREFERRED ?
                                    ", preferred" : "",
@@ -2108,7 +2200,7 @@ create_sprites(struct drm_compositor *ec)
                if (!sprite) {
                        weston_log("%s: out of memory\n",
                                __func__);
-                       free(plane);
+                       drmModeFreePlane(plane);
                        continue;
                }
 
@@ -2223,7 +2315,6 @@ update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
        drmModeRes *resources;
        struct drm_output *output, *next;
        int x = 0, y = 0;
-       int x_offset = 0, y_offset = 0;
        uint32_t connected = 0, disconnects = 0;
        int i;
 
@@ -2273,17 +2364,10 @@ update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
        if (disconnects) {
                wl_list_for_each_safe(output, next, &ec->base.output_list,
                                      base.link) {
-                       if (x_offset != 0 || y_offset != 0) {
-                               weston_output_move(&output->base,
-                                                output->base.x - x_offset,
-                                                output->base.y - y_offset);
-                       }
-
                        if (disconnects & (1 << output->connector_id)) {
                                disconnects &= ~(1 << output->connector_id);
                                weston_log("connector %d disconnected\n",
                                       output->connector_id);
-                               x_offset += output->base.width;
                                drm_output_destroy(&output->base);
                        }
                }
@@ -2338,15 +2422,11 @@ drm_destroy(struct weston_compositor *ec)
 {
        struct drm_compositor *d = (struct drm_compositor *) ec;
 
-       udev_input_destroy(&d->input);
-
        wl_event_source_remove(d->udev_drm_source);
        wl_event_source_remove(d->drm_source);
 
        destroy_sprites(d);
 
-       ec->renderer->destroy(ec);
-
        weston_compositor_shutdown(ec);
 
        if (d->gbm)
@@ -2355,7 +2435,7 @@ drm_destroy(struct weston_compositor *ec)
        weston_launcher_destroy(d->base.launcher);
 
        close(d->drm.fd);
-
+       free (d->main_seat);
        free(d);
 }
 
@@ -2398,16 +2478,24 @@ session_notify(struct wl_listener *listener, void *data)
        struct drm_compositor *ec = data;
        struct drm_sprite *sprite;
        struct drm_output *output;
+       struct udev_seat *useat;
+       struct weston_seat *seat, *next;
 
        if (ec->base.session_active) {
                weston_log("activating session\n");
                compositor->state = ec->prev_state;
                drm_compositor_set_modes(ec);
                weston_compositor_damage_all(compositor);
-               udev_input_enable(&ec->input, ec->udev);
+               wl_list_for_each_safe(seat, next, &ec->base.seat_list, link) {
+                   useat = container_of(seat, struct udev_seat, base);
+                   udev_input_enable(&useat->input);
+               }
        } else {
                weston_log("deactivating session\n");
-               udev_input_disable(&ec->input);
+               wl_list_for_each_safe(seat, next, &ec->base.seat_list, link) {
+                   useat = container_of(seat, struct udev_seat, base);
+                   udev_input_disable(&useat->input);
+               }
 
                ec->prev_state = compositor->state;
                weston_compositor_offscreen(compositor);
@@ -2522,6 +2610,18 @@ planes_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *data
 
 #ifdef BUILD_VAAPI_RECORDER
 static void
+recorder_destroy(struct drm_output *output)
+{
+       vaapi_recorder_destroy(output->recorder);
+       output->recorder = NULL;
+
+       output->base.disable_planes--;
+
+       wl_list_remove(&output->recorder_frame_listener.link);
+       weston_log("[libva recorder] done\n");
+}
+
+static void
 recorder_frame_notify(struct wl_listener *listener, void *data)
 {
        struct drm_output *output;
@@ -2543,7 +2643,12 @@ recorder_frame_notify(struct wl_listener *listener, void *data)
                return;
        }
 
-       vaapi_recorder_frame(output->recorder, fd, output->current->stride / 4);
+       ret = vaapi_recorder_frame(output->recorder, fd,
+                                  output->current->stride);
+       if (ret < 0) {
+               weston_log("[libva recorder] aborted: %m\n");
+               recorder_destroy(output);
+       }
 }
 
 static void *
@@ -2575,6 +2680,12 @@ recorder_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
                              struct drm_output, base.link);
 
        if (!output->recorder) {
+               if (output->format != GBM_FORMAT_XRGB8888) {
+                       weston_log("failed to start vaapi recorder: "
+                                  "output format not supported\n");
+                       return;
+               }
+
                width = output->base.current_mode->width;
                height = output->base.current_mode->height;
 
@@ -2595,13 +2706,7 @@ recorder_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
 
                weston_log("[libva recorder] initialized\n");
        } else {
-               vaapi_recorder_destroy(output->recorder);
-               output->recorder = NULL;
-
-               output->base.disable_planes--;
-
-               wl_list_remove(&output->recorder_frame_listener.link);
-               weston_log("[libva recorder] done\n");
+               recorder_destroy(output);
        }
 }
 #else
@@ -2642,8 +2747,11 @@ switch_to_gl_renderer(struct drm_compositor *c)
                assert(0);
        }
 
-       wl_list_for_each(output, &c->base.output_list, base.link)
+       wl_list_for_each(output, &c->base.output_list, base.link) {
+               /* Workaround page flip not setting the tiling mode on BYT */
+               output->force_modeset = 1;
                drm_output_init_egl(output, c);
+       }
 
        c->use_pixman = 0;
 }
@@ -2657,6 +2765,23 @@ renderer_switch_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
        switch_to_gl_renderer(c);
 }
 
+static int
+create_seats(struct drm_compositor *ec, int connector,
+               struct udev_device *drm_device)
+{
+       struct udev_seat *seat = udev_seat_get_named(&ec->base, ec->main_seat);
+       if (seat && udev_input_init(&seat->input, &ec->base,
+           ec->udev, ec->main_seat) < 0) {
+               weston_log("failed to create input devices\n");
+               return -1;
+       }
+
+       if (create_outputs(ec, connector, drm_device) < 0)
+               return -1;
+
+       return 0;
+}
+
 static struct weston_compositor *
 drm_compositor_create(struct wl_display *display,
                      struct drm_parameters *param,
@@ -2668,7 +2793,6 @@ drm_compositor_create(struct wl_display *display,
        struct udev_device *drm_device;
        struct wl_event_loop *loop;
        const char *path;
-       char *s;
        uint32_t key;
 
        weston_log("initializing drm backend\n");
@@ -2682,20 +2806,10 @@ drm_compositor_create(struct wl_display *display,
        ec->sprites_are_broken = 1;
 
        section = weston_config_get_section(config, "core", NULL, NULL);
-       weston_config_section_get_string(section,
-                                        "gbm-format", &s, "xrgb8888");
-       if (strcmp(s, "xrgb8888") == 0)
-               ec->format = GBM_FORMAT_XRGB8888;
-       else if (strcmp(s, "rgb565") == 0)
-               ec->format = GBM_FORMAT_RGB565;
-       else if (strcmp(s, "xrgb2101010") == 0)
-               ec->format = GBM_FORMAT_XRGB2101010;
-       else {
-               weston_log("fatal: unrecognized pixel format: %s\n", s);
-               free(s);
+       if (get_gbm_format_from_section(section,
+                                       GBM_FORMAT_XRGB8888,
+                                       &ec->format) == -1)
                goto err_base;
-       }
-       free(s);
 
        ec->use_pixman = param->use_pixman;
 
@@ -2761,18 +2875,18 @@ drm_compositor_create(struct wl_display *display,
        wl_list_init(&ec->sprite_list);
        create_sprites(ec);
 
-       if (create_outputs(ec, param->connector, drm_device) < 0) {
+       ec->main_seat = strdup(param->seat_id);
+       if (create_seats(ec, param->connector, drm_device) < 0) {
                weston_log("failed to create output for %s\n", path);
                goto err_sprite;
        }
 
-       path = NULL;
+       /* A this point we have some idea of whether or not we have a working
+        * cursor plane. */
+       if (!ec->cursors_are_broken)
+               ec->base.capabilities |= WESTON_CAP_CURSOR_PLANE;
 
-       if (udev_input_init(&ec->input,
-                           &ec->base, ec->udev, param->seat_id) < 0) {
-               weston_log("failed to create input devices\n");
-               goto err_sprite;
-       }
+       path = NULL;
 
        loop = wl_display_get_event_loop(ec->base.wl_display);
        ec->drm_source =
@@ -2816,7 +2930,6 @@ err_udev_monitor:
        udev_monitor_unref(ec->udev_monitor);
 err_drm_source:
        wl_event_source_remove(ec->drm_source);
-       udev_input_destroy(&ec->input);
 err_sprite:
        ec->base.renderer->destroy(&ec->base);
        gbm_device_destroy(ec->gbm);
@@ -2830,6 +2943,7 @@ err_udev:
 err_compositor:
        weston_compositor_shutdown(&ec->base);
 err_base:
+       free(ec->main_seat);
        free(ec);
        return NULL;
 }