downstream: Multiseat support for drm/wayland backends
[profile/ivi/weston-ivi-shell.git] / src / compositor-drm.c
index 3f584a6..d558f7d 100644 (file)
@@ -47,7 +47,7 @@
 #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 {
@@ -152,6 +168,7 @@ struct drm_output {
        int vblank_pending;
        int page_flip_pending;
        int destroy_pending;
+       int force_modeset;
 
        struct gbm_surface *surface;
        struct gbm_bo *cursor_bo[2];
@@ -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;
 
@@ -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,
@@ -808,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;
@@ -819,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)
@@ -883,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);
@@ -932,8 +953,8 @@ drm_output_prepare_overlay_view(struct weston_output *output_base,
 
        tbox = weston_transformed_rect(wl_fixed_from_int(ev->surface->width),
                                       wl_fixed_from_int(ev->surface->height),
-                                      ev->surface->buffer_viewport.transform,
-                                      ev->surface->buffer_viewport.scale,
+                                      viewport->buffer.transform,
+                                      viewport->buffer.scale,
                                       tbox);
 
        s->src_x = tbox.x1 << 8;
@@ -951,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))
@@ -982,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;
 
@@ -1005,7 +1029,7 @@ drm_output_set_cursor(struct drm_output *output)
                s = wl_shm_buffer_get_data(buffer->shm_buffer);
                wl_shm_buffer_begin_access(buffer->shm_buffer);
                for (i = 0; i < ev->surface->height; i++)
-                       memcpy(buf + i * 64, s + i * stride,
+                       memcpy(buf + i * c->cursor_width, s + i * stride,
                               ev->surface->width * 4);
                wl_shm_buffer_end_access(buffer->shm_buffer);
 
@@ -1013,8 +1037,8 @@ drm_output_set_cursor(struct drm_output *output)
                        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;
                }
@@ -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;
 }
 
@@ -1549,15 +1585,15 @@ drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec)
                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) {
@@ -1844,13 +1880,20 @@ 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);
+               }
        }
 }
 
@@ -1901,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) {
@@ -1949,6 +1993,8 @@ 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,
@@ -1956,6 +2002,9 @@ create_output_for_connector(struct drm_compositor *ec,
                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);
 
@@ -2071,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)
@@ -2371,8 +2422,6 @@ 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);
 
@@ -2386,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);
 }
 
@@ -2429,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);
@@ -2553,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;
@@ -2574,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 *
@@ -2606,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;
 
@@ -2626,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
@@ -2673,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;
 }
@@ -2688,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,
@@ -2781,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 =
@@ -2836,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);
@@ -2850,6 +2943,7 @@ err_udev:
 err_compositor:
        weston_compositor_shutdown(&ec->base);
 err_base:
+       free(ec->main_seat);
        free(ec);
        return NULL;
 }