blob: e7c0f0550604d8caa7c87206c7ac819d16133766 [file] [log] [blame]
rjw1f884582022-01-06 17:20:42 +08001From 6ff0106dc3fc3e9e442d634cb8e5dc0ef792416b Mon Sep 17 00:00:00 2001
2From: Jia Rong <jia.rong@mediatek.com>
3Date: Fri, 20 Apr 2018 20:43:48 +0800
4Subject: [PATCH 6/9] weston: porting atomic drm from weston4.0
5
6porting atomic drm from weston4.0
7Test: build pass
8
9Change-Id: I37829d8a4815117d4b8bac8d2f8d21f666f83104
10Signed-off-by: Jia Rong <jia.rong@mediatek.com>
11CR-Id: AUTO00016576
12---
13 Makefile.am | 2 +
14 libweston/compositor-drm.c | 3922 +++++++++++++++++++++++++++++++--------
15 libweston/compositor-drm.h | 16 +-
16 libweston/compositor-fbdev.c | 5 +-
17 libweston/compositor-headless.c | 3 +-
18 libweston/compositor-rdp.c | 3 +-
19 libweston/compositor-wayland.c | 6 +-
20 libweston/compositor-x11.c | 6 +-
21 libweston/compositor.c | 177 +-
22 libweston/compositor.h | 59 +-
23 libweston/pixel-formats.c | 430 +++++
24 libweston/pixel-formats.h | 194 ++
25 shared/timespec-util.h | 184 ++
26 13 files changed, 4221 insertions(+), 786 deletions(-)
27 create mode 100644 libweston/pixel-formats.c
28 create mode 100644 libweston/pixel-formats.h
29
30diff --git a/Makefile.am b/Makefile.am
31index e23b03b..238cd2f 100644
32--- a/Makefile.am
33+++ b/Makefile.am
34@@ -105,6 +105,8 @@ libweston_@LIBWESTON_MAJOR@_la_SOURCES = \
35 libweston/timeline-object.h \
36 libweston/linux-dmabuf.c \
37 libweston/linux-dmabuf.h \
38+ libweston/pixel-formats.c \
39+ libweston/pixel-formats.h \
40 shared/helpers.h \
41 shared/matrix.c \
42 shared/matrix.h \
43diff --git a/libweston/compositor-drm.c b/libweston/compositor-drm.c
44index 4a5cd67..bba22b3 100644
45--- a/libweston/compositor-drm.c
46+++ b/libweston/compositor-drm.c
47@@ -54,6 +54,7 @@
48 #include "gl-renderer.h"
49 #include "weston-egl-ext.h"
50 #include "pixman-renderer.h"
51+#include "pixel-formats.h"
52 #include "libbacklight.h"
53 #include "libinput-seat.h"
54 #include "launcher-util.h"
55@@ -62,10 +63,16 @@
56 #include "linux-dmabuf.h"
57 #include "linux-dmabuf-unstable-v1-server-protocol.h"
58
59+#define HAVE_DRM_ATOMIC
60+
61 #ifndef DRM_CAP_TIMESTAMP_MONOTONIC
62 #define DRM_CAP_TIMESTAMP_MONOTONIC 0x6
63 #endif
64
65+#ifndef DRM_CLIENT_CAP_UNIVERSAL_PLANES
66+#define DRM_CLIENT_CAP_UNIVERSAL_PLANES 2
67+#endif
68+
69 #ifndef DRM_CAP_CURSOR_WIDTH
70 #define DRM_CAP_CURSOR_WIDTH 0x8
71 #endif
72@@ -78,6 +85,139 @@
73 #define GBM_BO_USE_CURSOR GBM_BO_USE_CURSOR_64X64
74 #endif
75
76+/**
77+ * Represents the values of an enum-type KMS property
78+ */
79+struct drm_property_enum_info {
80+ const char *name; /**< name as string (static, not freed) */
81+ bool valid; /**< true if value is supported; ignore if false */
82+ uint64_t value; /**< raw value */
83+};
84+
85+/**
86+ * Holds information on a DRM property, including its ID and the enum
87+ * values it holds.
88+ *
89+ * DRM properties are allocated dynamically, and maintained as DRM objects
90+ * within the normal object ID space; they thus do not have a stable ID
91+ * to refer to. This includes enum values, which must be referred to by
92+ * integer values, but these are not stable.
93+ *
94+ * drm_property_info allows a cache to be maintained where Weston can use
95+ * enum values internally to refer to properties, with the mapping to DRM
96+ * ID values being maintained internally.
97+ */
98+struct drm_property_info {
99+ const char *name; /**< name as string (static, not freed) */
100+ uint32_t prop_id; /**< KMS property object ID */
101+ unsigned int num_enum_values; /**< number of enum values */
102+ struct drm_property_enum_info *enum_values; /**< array of enum values */
103+};
104+
105+/**
106+ * List of properties attached to DRM planes
107+ */
108+enum wdrm_plane_property {
109+ WDRM_PLANE_TYPE = 0,
110+ WDRM_PLANE_SRC_X,
111+ WDRM_PLANE_SRC_Y,
112+ WDRM_PLANE_SRC_W,
113+ WDRM_PLANE_SRC_H,
114+ WDRM_PLANE_CRTC_X,
115+ WDRM_PLANE_CRTC_Y,
116+ WDRM_PLANE_CRTC_W,
117+ WDRM_PLANE_CRTC_H,
118+ WDRM_PLANE_FB_ID,
119+ WDRM_PLANE_CRTC_ID,
120+ WDRM_PLANE__COUNT
121+};
122+
123+/**
124+ * Possible values for the WDRM_PLANE_TYPE property.
125+ */
126+enum wdrm_plane_type {
127+ WDRM_PLANE_TYPE_PRIMARY = 0,
128+ WDRM_PLANE_TYPE_CURSOR,
129+ WDRM_PLANE_TYPE_OVERLAY,
130+ WDRM_PLANE_TYPE__COUNT
131+};
132+
133+static struct drm_property_enum_info plane_type_enums[] = {
134+ [WDRM_PLANE_TYPE_PRIMARY] = {
135+ .name = "Primary",
136+ },
137+ [WDRM_PLANE_TYPE_OVERLAY] = {
138+ .name = "Overlay",
139+ },
140+ [WDRM_PLANE_TYPE_CURSOR] = {
141+ .name = "Cursor",
142+ },
143+};
144+
145+static const struct drm_property_info plane_props[] = {
146+ [WDRM_PLANE_TYPE] = {
147+ .name = "type",
148+ .enum_values = plane_type_enums,
149+ .num_enum_values = WDRM_PLANE_TYPE__COUNT,
150+ },
151+ [WDRM_PLANE_SRC_X] = { .name = "SRC_X", },
152+ [WDRM_PLANE_SRC_Y] = { .name = "SRC_Y", },
153+ [WDRM_PLANE_SRC_W] = { .name = "SRC_W", },
154+ [WDRM_PLANE_SRC_H] = { .name = "SRC_H", },
155+ [WDRM_PLANE_CRTC_X] = { .name = "CRTC_X", },
156+ [WDRM_PLANE_CRTC_Y] = { .name = "CRTC_Y", },
157+ [WDRM_PLANE_CRTC_W] = { .name = "CRTC_W", },
158+ [WDRM_PLANE_CRTC_H] = { .name = "CRTC_H", },
159+ [WDRM_PLANE_FB_ID] = { .name = "FB_ID", },
160+ [WDRM_PLANE_CRTC_ID] = { .name = "CRTC_ID", },
161+};
162+
163+/**
164+ * List of properties attached to a DRM connector
165+ */
166+enum wdrm_connector_property {
167+ WDRM_CONNECTOR_EDID = 0,
168+ WDRM_CONNECTOR_DPMS,
169+ WDRM_CONNECTOR_CRTC_ID,
170+ WDRM_CONNECTOR__COUNT
171+};
172+
173+static const struct drm_property_info connector_props[] = {
174+ [WDRM_CONNECTOR_EDID] = { .name = "EDID" },
175+ [WDRM_CONNECTOR_DPMS] = { .name = "DPMS" },
176+ [WDRM_CONNECTOR_CRTC_ID] = { .name = "CRTC_ID", },
177+};
178+
179+/**
180+ * List of properties attached to DRM CRTCs
181+ */
182+enum wdrm_crtc_property {
183+ WDRM_CRTC_MODE_ID = 0,
184+ WDRM_CRTC_ACTIVE,
185+ WDRM_CRTC__COUNT
186+};
187+
188+static const struct drm_property_info crtc_props[] = {
189+ [WDRM_CRTC_MODE_ID] = { .name = "MODE_ID", },
190+ [WDRM_CRTC_ACTIVE] = { .name = "ACTIVE", },
191+};
192+
193+/**
194+ * Mode for drm_output_state_duplicate.
195+ */
196+enum drm_output_state_duplicate_mode {
197+ DRM_OUTPUT_STATE_CLEAR_PLANES, /**< reset all planes to off */
198+ DRM_OUTPUT_STATE_PRESERVE_PLANES, /**< preserve plane state */
199+};
200+
201+/**
202+ * Mode for drm_pending_state_apply and co.
203+ */
204+enum drm_state_apply_mode {
205+ DRM_STATE_APPLY_SYNC, /**< state fully processed */
206+ DRM_STATE_APPLY_ASYNC, /**< state pending event delivery */
207+};
208+
209 struct drm_backend {
210 struct weston_backend base;
211 struct weston_compositor *compositor;
212@@ -103,14 +243,24 @@ struct drm_backend {
213 */
214 int min_width, max_width;
215 int min_height, max_height;
216- int no_addfb2;
217
218- struct wl_list sprite_list;
219+ struct wl_list plane_list;
220 int sprites_are_broken;
221 int sprites_hidden;
222
223+ void *repaint_data;
224+
225+ bool state_invalid;
226+
227+ /* Connector and CRTC IDs not used by any enabled output. */
228+ struct wl_array unused_connectors;
229+ struct wl_array unused_crtcs;
230+
231 int cursors_are_broken;
232
233+ bool universal_planes;
234+ bool atomic_modeset;
235+
236 int use_pixman;
237
238 struct udev_input input;
239@@ -118,23 +268,39 @@ struct drm_backend {
240 int32_t cursor_width;
241 int32_t cursor_height;
242
243- uint32_t connector;
244+ uint32_t pageflip_timeout;
245+
246+ bool shutting_down;
247 };
248
249 struct drm_mode {
250 struct weston_mode base;
251 drmModeModeInfo mode_info;
252+ uint32_t blob_id;
253+};
254+
255+enum drm_fb_type {
256+ BUFFER_INVALID = 0, /**< never used */
257+ BUFFER_CLIENT, /**< directly sourced from client */
258+ BUFFER_PIXMAN_DUMB, /**< internal Pixman rendering */
259+ BUFFER_GBM_SURFACE, /**< internal EGL rendering */
260+ BUFFER_CURSOR, /**< internal cursor buffer */
261 };
262
263 struct drm_fb {
264+ enum drm_fb_type type;
265+
266+ int refcnt;
267+
268 uint32_t fb_id, stride, handle, size;
269+ const struct pixel_format_info *format;
270 int width, height;
271 int fd;
272- int is_client_buffer;
273 struct weston_buffer_reference buffer_ref;
274
275 /* Used by gbm fbs */
276 struct gbm_bo *bo;
277+ struct gbm_surface *gbm_surface;
278
279 /* Used by dumb fbs */
280 void *map;
281@@ -147,6 +313,95 @@ struct drm_edid {
282 char serial_number[13];
283 };
284
285+/**
286+ * Pending state holds one or more drm_output_state structures, collected from
287+ * performing repaint. This pending state is transient, and only lives between
288+ * beginning a repaint group and flushing the results: after flush, each
289+ * output state will complete and be retired separately.
290+ */
291+struct drm_pending_state {
292+ struct drm_backend *backend;
293+ struct wl_list output_list;
294+};
295+
296+/*
297+ * Output state holds the dynamic state for one Weston output, i.e. a KMS CRTC,
298+ * plus >= 1 each of encoder/connector/plane. Since everything but the planes
299+ * is currently statically assigned per-output, we mainly use this to track
300+ * plane state.
301+ *
302+ * pending_state is set when the output state is owned by a pending_state,
303+ * i.e. when it is being constructed and has not yet been applied. When the
304+ * output state has been applied, the owning pending_state is freed.
305+ */
306+struct drm_output_state {
307+ struct drm_pending_state *pending_state;
308+ struct drm_output *output;
309+ struct wl_list link;
310+ enum dpms_enum dpms;
311+ struct wl_list plane_list;
312+};
313+
314+/**
315+ * Plane state holds the dynamic state for a plane: where it is positioned,
316+ * and which buffer it is currently displaying.
317+ *
318+ * The plane state is owned by an output state, except when setting an initial
319+ * state. See drm_output_state for notes on state object lifetime.
320+ */
321+struct drm_plane_state {
322+ struct drm_plane *plane;
323+ struct drm_output *output;
324+ struct drm_output_state *output_state;
325+
326+ struct drm_fb *fb;
327+
328+ int32_t src_x, src_y;
329+ uint32_t src_w, src_h;
330+ int32_t dest_x, dest_y;
331+ uint32_t dest_w, dest_h;
332+
333+ bool complete;
334+
335+ struct wl_list link; /* drm_output_state::plane_list */
336+};
337+
338+/**
339+ * A plane represents one buffer, positioned within a CRTC, and stacked
340+ * relative to other planes on the same CRTC.
341+ *
342+ * Each CRTC has a 'primary plane', which use used to display the classic
343+ * framebuffer contents, as accessed through the legacy drmModeSetCrtc
344+ * call (which combines setting the CRTC's actual physical mode, and the
345+ * properties of the primary plane).
346+ *
347+ * The cursor plane also has its own alternate legacy API.
348+ *
349+ * Other planes are used opportunistically to display content we do not
350+ * wish to blit into the primary plane. These non-primary/cursor planes
351+ * are referred to as 'sprites'.
352+ */
353+struct drm_plane {
354+ struct weston_plane base;
355+
356+ struct drm_backend *backend;
357+
358+ enum wdrm_plane_type type;
359+
360+ uint32_t possible_crtcs;
361+ uint32_t plane_id;
362+ uint32_t count_formats;
363+
364+ struct drm_property_info props[WDRM_PLANE__COUNT];
365+
366+ /* The last state submitted to the kernel for this plane. */
367+ struct drm_plane_state *state_cur;
368+
369+ struct wl_list link;
370+
371+ uint32_t formats[];
372+};
373+
374 struct drm_output {
375 struct weston_output base;
376 drmModeConnector *connector;
377@@ -154,26 +409,38 @@ struct drm_output {
378 uint32_t crtc_id; /* object ID to pass to DRM functions */
379 int pipe; /* index of CRTC in resource array / bitmasks */
380 uint32_t connector_id;
381- drmModeCrtcPtr original_crtc;
382 struct drm_edid edid;
383- drmModePropertyPtr dpms_prop;
384- uint32_t gbm_format;
385
386- enum dpms_enum dpms;
387+ /* Holds the properties for the connector */
388+ struct drm_property_info props_conn[WDRM_CONNECTOR__COUNT];
389+ /* Holds the properties for the CRTC */
390+ struct drm_property_info props_crtc[WDRM_CRTC__COUNT];
391+
392+ struct backlight *backlight;
393
394 int vblank_pending;
395 int page_flip_pending;
396+ int atomic_complete_pending;
397 int destroy_pending;
398 int disable_pending;
399+ int dpms_off_pending;
400
401- struct gbm_surface *gbm_surface;
402- struct gbm_bo *gbm_cursor_bo[2];
403- struct weston_plane cursor_plane;
404- struct weston_plane fb_plane;
405+ struct drm_fb *gbm_cursor_fb[2];
406+ struct drm_plane *cursor_plane;
407 struct weston_view *cursor_view;
408 int current_cursor;
409- struct drm_fb *current, *next;
410- struct backlight *backlight;
411+
412+ struct gbm_surface *gbm_surface;
413+ uint32_t gbm_format;
414+
415+ /* Plane being displayed directly on the CRTC */
416+ struct drm_plane *scanout_plane;
417+
418+ /* The last state submitted to the kernel for this CRTC. */
419+ struct drm_output_state *state_cur;
420+ /* The previously-submitted state, where the hardware has not
421+ * yet acknowledged completion of state_cur. */
422+ struct drm_output_state *state_last;
423
424 struct drm_fb *dumb[2];
425 pixman_image_t *image[2];
426@@ -182,36 +449,33 @@ struct drm_output {
427
428 struct vaapi_recorder *recorder;
429 struct wl_listener recorder_frame_listener;
430-};
431
432-/*
433- * An output has a primary display plane plus zero or more sprites for
434- * blending display contents.
435- */
436-struct drm_sprite {
437- struct wl_list link;
438+ struct wl_event_source *pageflip_timer;
439+};
440
441- struct weston_plane plane;
442+static struct gl_renderer_interface *gl_renderer;
443
444- struct drm_fb *current, *next;
445- struct drm_output *output;
446- struct drm_backend *backend;
447+static const char default_seat[] = "seat0";
448
449- uint32_t possible_crtcs;
450- uint32_t plane_id;
451- uint32_t count_formats;
452+static void
453+wl_array_remove_uint32(struct wl_array *array, uint32_t elm)
454+{
455+ uint32_t *pos, *end;
456
457- int32_t src_x, src_y;
458- uint32_t src_w, src_h;
459- uint32_t dest_x, dest_y;
460- uint32_t dest_w, dest_h;
461+ end = (uint32_t *) ((char *) array->data + array->size);
462
463- uint32_t formats[];
464-};
465+ wl_array_for_each(pos, array) {
466+ if (*pos != elm)
467+ continue;
468
469-static struct gl_renderer_interface *gl_renderer;
470+ array->size -= sizeof(*pos);
471+ if (pos + 1 == end)
472+ break;
473
474-static const char default_seat[] = "seat0";
475+ memmove(pos, pos + 1, (char *) end - (char *) (pos + 1));
476+ break;
477+ }
478+}
479
480 static inline struct drm_output *
481 to_drm_output(struct weston_output *base)
482@@ -225,16 +489,286 @@ to_drm_backend(struct weston_compositor *base)
483 return container_of(base->backend, struct drm_backend, base);
484 }
485
486+static int
487+pageflip_timeout(void *data) {
488+ /*
489+ * Our timer just went off, that means we're not receiving drm
490+ * page flip events anymore for that output. Let's gracefully exit
491+ * weston with a return value so devs can debug what's going on.
492+ */
493+ struct drm_output *output = data;
494+ struct weston_compositor *compositor = output->base.compositor;
495+
496+ weston_log("Pageflip timeout reached on output %s, your "
497+ "driver is probably buggy! Exiting.\n",
498+ output->base.name);
499+ weston_compositor_exit_with_code(compositor, EXIT_FAILURE);
500+
501+ return 0;
502+}
503+
504+/* Creates the pageflip timer. Note that it isn't armed by default */
505+static int
506+drm_output_pageflip_timer_create(struct drm_output *output)
507+{
508+ struct wl_event_loop *loop = NULL;
509+ struct weston_compositor *ec = output->base.compositor;
510+
511+ loop = wl_display_get_event_loop(ec->wl_display);
512+ assert(loop);
513+ output->pageflip_timer = wl_event_loop_add_timer(loop,
514+ pageflip_timeout,
515+ output);
516+
517+ if (output->pageflip_timer == NULL) {
518+ weston_log("creating drm pageflip timer failed: %m\n");
519+ return -1;
520+ }
521+
522+ return 0;
523+}
524+
525+static inline struct drm_mode *
526+to_drm_mode(struct weston_mode *base)
527+{
528+ return container_of(base, struct drm_mode, base);
529+}
530+
531+/**
532+ * Get the current value of a KMS property
533+ *
534+ * Given a drmModeObjectGetProperties return, as well as the drm_property_info
535+ * for the target property, return the current value of that property,
536+ * with an optional default. If the property is a KMS enum type, the return
537+ * value will be translated into the appropriate internal enum.
538+ *
539+ * If the property is not present, the default value will be returned.
540+ *
541+ * @param info Internal structure for property to look up
542+ * @param props Raw KMS properties for the target object
543+ * @param def Value to return if property is not found
544+ */
545+static uint64_t
546+drm_property_get_value(struct drm_property_info *info,
547+ drmModeObjectPropertiesPtr props,
548+ uint64_t def)
549+{
550+ unsigned int i;
551+
552+ if (info->prop_id == 0)
553+ return def;
554+
555+ for (i = 0; i < props->count_props; i++) {
556+ unsigned int j;
557+
558+ if (props->props[i] != info->prop_id)
559+ continue;
560+
561+ /* Simple (non-enum) types can return the value directly */
562+ if (info->num_enum_values == 0)
563+ return props->prop_values[i];
564+
565+ /* Map from raw value to enum value */
566+ for (j = 0; j < info->num_enum_values; j++) {
567+ if (!info->enum_values[j].valid)
568+ continue;
569+ if (info->enum_values[j].value != props->prop_values[i])
570+ continue;
571+
572+ return j;
573+ }
574+
575+ /* We don't have a mapping for this enum; return default. */
576+ break;
577+ }
578+
579+ return def;
580+}
581+
582+/**
583+ * Cache DRM property values
584+ *
585+ * Update a per-object array of drm_property_info structures, given the
586+ * DRM properties of the object.
587+ *
588+ * Call this every time an object newly appears (note that only connectors
589+ * can be hotplugged), the first time it is seen, or when its status changes
590+ * in a way which invalidates the potential property values (currently, the
591+ * only case for this is connector hotplug).
592+ *
593+ * This updates the property IDs and enum values within the drm_property_info
594+ * array.
595+ *
596+ * DRM property enum values are dynamic at runtime; the user must query the
597+ * property to find out the desired runtime value for a requested string
598+ * name. Using the 'type' field on planes as an example, there is no single
599+ * hardcoded constant for primary plane types; instead, the property must be
600+ * queried at runtime to find the value associated with the string "Primary".
601+ *
602+ * This helper queries and caches the enum values, to allow us to use a set
603+ * of compile-time-constant enums portably across various implementations.
604+ * The values given in enum_names are searched for, and stored in the
605+ * same-indexed field of the map array.
606+ *
607+ * @param b DRM backend object
608+ * @param src DRM property info array to source from
609+ * @param info DRM property info array to copy into
610+ * @param num_infos Number of entries in the source array
611+ * @param props DRM object properties for the object
612+ */
613+static void
614+drm_property_info_populate(struct drm_backend *b,
615+ const struct drm_property_info *src,
616+ struct drm_property_info *info,
617+ unsigned int num_infos,
618+ drmModeObjectProperties *props)
619+{
620+ drmModePropertyRes *prop;
621+ unsigned i, j;
622+
623+ for (i = 0; i < num_infos; i++) {
624+ unsigned int j;
625+
626+ info[i].name = src[i].name;
627+ info[i].prop_id = 0;
628+ info[i].num_enum_values = src[i].num_enum_values;
629+
630+ if (src[i].num_enum_values == 0)
631+ continue;
632+
633+ info[i].enum_values =
634+ malloc(src[i].num_enum_values *
635+ sizeof(*info[i].enum_values));
636+ assert(info[i].enum_values);
637+ for (j = 0; j < info[i].num_enum_values; j++) {
638+ info[i].enum_values[j].name = src[i].enum_values[j].name;
639+ info[i].enum_values[j].valid = false;
640+ }
641+ }
642+
643+ for (i = 0; i < props->count_props; i++) {
644+ unsigned int k;
645+
646+ prop = drmModeGetProperty(b->drm.fd, props->props[i]);
647+ if (!prop)
648+ continue;
649+
650+ for (j = 0; j < num_infos; j++) {
651+ if (!strcmp(prop->name, info[j].name))
652+ break;
653+ }
654+
655+ /* We don't know/care about this property. */
656+ if (j == num_infos) {
657+#ifdef DEBUG
658+ weston_log("DRM debug: unrecognized property %u '%s'\n",
659+ prop->prop_id, prop->name);
660+#endif
661+ drmModeFreeProperty(prop);
662+ continue;
663+ }
664+
665+ if (info[j].num_enum_values == 0 &&
666+ (prop->flags & DRM_MODE_PROP_ENUM)) {
667+ weston_log("DRM: expected property %s to not be an"
668+ " enum, but it is; ignoring\n", prop->name);
669+ drmModeFreeProperty(prop);
670+ continue;
671+ }
672+
673+ info[j].prop_id = props->props[i];
674+
675+ if (info[j].num_enum_values == 0) {
676+ drmModeFreeProperty(prop);
677+ continue;
678+ }
679+
680+ if (!(prop->flags & DRM_MODE_PROP_ENUM)) {
681+ weston_log("DRM: expected property %s to be an enum,"
682+ " but it is not; ignoring\n", prop->name);
683+ drmModeFreeProperty(prop);
684+ info[j].prop_id = 0;
685+ continue;
686+ }
687+
688+ for (k = 0; k < info[j].num_enum_values; k++) {
689+ int l;
690+
691+ for (l = 0; l < prop->count_enums; l++) {
692+ if (!strcmp(prop->enums[l].name,
693+ info[j].enum_values[k].name))
694+ break;
695+ }
696+
697+ if (l == prop->count_enums)
698+ continue;
699+
700+ info[j].enum_values[k].valid = true;
701+ info[j].enum_values[k].value = prop->enums[l].value;
702+ }
703+
704+ drmModeFreeProperty(prop);
705+ }
706+
707+#ifdef DEBUG
708+ for (i = 0; i < num_infos; i++) {
709+ if (info[i].prop_id == 0)
710+ weston_log("DRM warning: property '%s' missing\n",
711+ info[i].name);
712+ }
713+#endif
714+}
715+
716+/**
717+ * Free DRM property information
718+ *
719+ * Frees all memory associated with a DRM property info array and zeroes
720+ * it out, leaving it usable for a further drm_property_info_update() or
721+ * drm_property_info_free().
722+ *
723+ * @param info DRM property info array
724+ * @param num_props Number of entries in array to free
725+ */
726+static void
727+drm_property_info_free(struct drm_property_info *info, int num_props)
728+{
729+ int i;
730+
731+ for (i = 0; i < num_props; i++)
732+ free(info[i].enum_values);
733+
734+ memset(info, 0, sizeof(*info) * num_props);
735+}
736+
737 static void
738-drm_output_set_cursor(struct drm_output *output);
739+drm_output_set_cursor(struct drm_output_state *output_state);
740
741 static void
742 drm_output_update_msc(struct drm_output *output, unsigned int seq);
743
744-static int
745-drm_sprite_crtc_supported(struct drm_output *output, struct drm_sprite *sprite)
746+static void
747+drm_output_destroy(struct weston_output *output_base);
748+
749+/**
750+ * Returns true if the plane can be used on the given output for its current
751+ * repaint cycle.
752+ */
753+static bool
754+drm_plane_is_available(struct drm_plane *plane, struct drm_output *output)
755 {
756- return !!(sprite->possible_crtcs & (1 << output->pipe));
757+ assert(plane->state_cur);
758+
759+ /* The plane still has a request not yet completed by the kernel. */
760+ if (!plane->state_cur->complete)
761+ return false;
762+
763+ /* The plane is still active on another output. */
764+ if (plane->state_cur->output && plane->state_cur->output != output)
765+ return false;
766+
767+ /* Check whether the plane can be used with this CRTC; possible_crtcs
768+ * is a bitmask of CRTC indices (pipe), rather than CRTC object ID. */
769+ return !!(plane->possible_crtcs & (1 << output->pipe));
770 }
771
772 static struct drm_output *
773@@ -276,16 +810,39 @@ drm_output_find_by_connector(struct drm_backend *b, uint32_t connector_id)
774 }
775
776 static void
777-drm_fb_destroy_callback(struct gbm_bo *bo, void *data)
778+drm_fb_destroy(struct drm_fb *fb)
779 {
780- struct drm_fb *fb = data;
781-
782- if (fb->fb_id)
783+ if (fb->fb_id != 0)
784 drmModeRmFB(fb->fd, fb->fb_id);
785-
786 weston_buffer_reference(&fb->buffer_ref, NULL);
787+ free(fb);
788+}
789+
790+static void
791+drm_fb_destroy_dumb(struct drm_fb *fb)
792+{
793+ struct drm_mode_destroy_dumb destroy_arg;
794
795- free(data);
796+ assert(fb->type == BUFFER_PIXMAN_DUMB);
797+
798+ if (fb->map && fb->size > 0)
799+ munmap(fb->map, fb->size);
800+
801+ memset(&destroy_arg, 0, sizeof(destroy_arg));
802+ destroy_arg.handle = fb->handle;
803+ drmIoctl(fb->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
804+
805+ drm_fb_destroy(fb);
806+}
807+
808+static void
809+drm_fb_destroy_gbm(struct gbm_bo *bo, void *data)
810+{
811+ struct drm_fb *fb = data;
812+
813+ assert(fb->type == BUFFER_GBM_SURFACE || fb->type == BUFFER_CLIENT ||
814+ fb->type == BUFFER_CURSOR);
815+ drm_fb_destroy(fb);
816 }
817
818 static struct drm_fb *
819@@ -294,30 +851,33 @@ drm_fb_create_dumb(struct drm_backend *b, int width, int height,
820 {
821 struct drm_fb *fb;
822 int ret;
823- uint32_t bpp, depth;
824
825 struct drm_mode_create_dumb create_arg;
826 struct drm_mode_destroy_dumb destroy_arg;
827 struct drm_mode_map_dumb map_arg;
828+ uint32_t handles[4] = { 0 }, pitches[4] = { 0 }, offsets[4] = { 0 };
829
830 fb = zalloc(sizeof *fb);
831 if (!fb)
832 return NULL;
833
834- switch (format) {
835- case GBM_FORMAT_XRGB8888:
836- bpp = 32;
837- depth = 24;
838- break;
839- case GBM_FORMAT_RGB565:
840- bpp = depth = 16;
841- break;
842- default:
843- return NULL;
844+ fb->refcnt = 1;
845+
846+ fb->format = pixel_format_get_info(format);
847+ if (!fb->format) {
848+ weston_log("failed to look up format 0x%lx\n",
849+ (unsigned long) format);
850+ goto err_fb;
851+ }
852+
853+ if (!fb->format->depth || !fb->format->bpp) {
854+ weston_log("format 0x%lx is not compatible with dumb buffers\n",
855+ (unsigned long) format);
856+ goto err_fb;
857 }
858
859 memset(&create_arg, 0, sizeof create_arg);
860- create_arg.bpp = bpp;
861+ create_arg.bpp = fb->format->bpp;
862 create_arg.width = width;
863 create_arg.height = height;
864
865@@ -325,6 +885,7 @@ drm_fb_create_dumb(struct drm_backend *b, int width, int height,
866 if (ret)
867 goto err_fb;
868
869+ fb->type = BUFFER_PIXMAN_DUMB;
870 fb->handle = create_arg.handle;
871 fb->stride = create_arg.pitch;
872 fb->size = create_arg.size;
873@@ -332,26 +893,15 @@ drm_fb_create_dumb(struct drm_backend *b, int width, int height,
874 fb->height = height;
875 fb->fd = b->drm.fd;
876
877- ret = -1;
878-
879- if (!b->no_addfb2) {
880- uint32_t handles[4] = { 0 }, pitches[4] = { 0 }, offsets[4] = { 0 };
881-
882- handles[0] = fb->handle;
883- pitches[0] = fb->stride;
884- offsets[0] = 0;
885-
886- ret = drmModeAddFB2(b->drm.fd, width, height,
887- format, handles, pitches, offsets,
888- &fb->fb_id, 0);
889- if (ret) {
890- weston_log("addfb2 failed: %m\n");
891- b->no_addfb2 = 1;
892- }
893- }
894+ handles[0] = fb->handle;
895+ pitches[0] = fb->stride;
896+ offsets[0] = 0;
897
898+ ret = drmModeAddFB2(b->drm.fd, width, height, fb->format->format,
899+ handles, pitches, offsets, &fb->fb_id, 0);
900 if (ret) {
901- ret = drmModeAddFB(b->drm.fd, width, height, depth, bpp,
902+ ret = drmModeAddFB(b->drm.fd, width, height,
903+ fb->format->depth, fb->format->bpp,
904 fb->stride, fb->handle, &fb->fb_id);
905 }
906
907@@ -382,52 +932,50 @@ err_fb:
908 return NULL;
909 }
910
911-static void
912-drm_fb_destroy_dumb(struct drm_fb *fb)
913+static struct drm_fb *
914+drm_fb_ref(struct drm_fb *fb)
915 {
916- struct drm_mode_destroy_dumb destroy_arg;
917-
918- if (!fb->map)
919- return;
920-
921- if (fb->fb_id)
922- drmModeRmFB(fb->fd, fb->fb_id);
923-
924- weston_buffer_reference(&fb->buffer_ref, NULL);
925-
926- munmap(fb->map, fb->size);
927-
928- memset(&destroy_arg, 0, sizeof(destroy_arg));
929- destroy_arg.handle = fb->handle;
930- drmIoctl(fb->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
931-
932- free(fb);
933+ fb->refcnt++;
934+ return fb;
935 }
936
937 static struct drm_fb *
938-drm_fb_get_from_bo(struct gbm_bo *bo,
939- struct drm_backend *backend, uint32_t format)
940+drm_fb_get_from_bo(struct gbm_bo *bo, struct drm_backend *backend,
941+ uint32_t format, enum drm_fb_type type)
942 {
943 struct drm_fb *fb = gbm_bo_get_user_data(bo);
944 uint32_t handles[4] = { 0 }, pitches[4] = { 0 }, offsets[4] = { 0 };
945 int ret;
946
947- if (fb)
948- return fb;
949+ if (fb) {
950+ assert(fb->type == type);
951+ return drm_fb_ref(fb);
952+ }
953+
954+ assert(format != 0);
955
956 fb = zalloc(sizeof *fb);
957 if (fb == NULL)
958 return NULL;
959
960+ fb->type = type;
961+ fb->refcnt = 1;
962 fb->bo = bo;
963
964 fb->width = gbm_bo_get_width(bo);
965 fb->height = gbm_bo_get_height(bo);
966 fb->stride = gbm_bo_get_stride(bo);
967 fb->handle = gbm_bo_get_handle(bo).u32;
968+ fb->format = pixel_format_get_info(format);
969 fb->size = fb->stride * fb->height;
970 fb->fd = backend->drm.fd;
971
972+ if (!fb->format) {
973+ weston_log("couldn't look up format 0x%lx\n",
974+ (unsigned long) format);
975+ goto err_free;
976+ }
977+
978 if (backend->min_width > fb->width ||
979 fb->width > backend->max_width ||
980 backend->min_height > fb->height ||
981@@ -436,33 +984,24 @@ drm_fb_get_from_bo(struct gbm_bo *bo,
982 goto err_free;
983 }
984
985- ret = -1;
986-
987- if (format && !backend->no_addfb2) {
988- handles[0] = fb->handle;
989- pitches[0] = fb->stride;
990- offsets[0] = 0;
991+ handles[0] = fb->handle;
992+ pitches[0] = fb->stride;
993+ offsets[0] = 0;
994
995- ret = drmModeAddFB2(backend->drm.fd, fb->width, fb->height,
996- format, handles, pitches, offsets,
997- &fb->fb_id, 0);
998- if (ret) {
999- weston_log("addfb2 failed: %m\n");
1000- backend->no_addfb2 = 1;
1001- backend->sprites_are_broken = 1;
1002- }
1003- }
1004-
1005- if (ret)
1006+ ret = drmModeAddFB2(backend->drm.fd, fb->width, fb->height,
1007+ fb->format->format, handles, pitches, offsets,
1008+ &fb->fb_id, 0);
1009+ if (ret && fb->format->depth && fb->format->bpp)
1010 ret = drmModeAddFB(backend->drm.fd, fb->width, fb->height,
1011- 24, 32, fb->stride, fb->handle, &fb->fb_id);
1012+ fb->format->depth, fb->format->bpp,
1013+ fb->stride, fb->handle, &fb->fb_id);
1014
1015 if (ret) {
1016 weston_log("failed to create kms fb: %m\n");
1017 goto err_free;
1018 }
1019
1020- gbm_bo_set_user_data(bo, fb, drm_fb_destroy_callback);
1021+ gbm_bo_set_user_data(bo, fb, drm_fb_destroy_gbm);
1022
1023 return fb;
1024
1025@@ -475,28 +1014,496 @@ static void
1026 drm_fb_set_buffer(struct drm_fb *fb, struct weston_buffer *buffer)
1027 {
1028 assert(fb->buffer_ref.buffer == NULL);
1029+ assert(fb->type == BUFFER_CLIENT);
1030+ weston_buffer_reference(&fb->buffer_ref, buffer);
1031+}
1032+
1033+static void
1034+drm_fb_unref(struct drm_fb *fb)
1035+{
1036+ if (!fb)
1037+ return;
1038+
1039+ assert(fb->refcnt > 0);
1040+ if (--fb->refcnt > 0)
1041+ return;
1042+
1043+ switch (fb->type) {
1044+ case BUFFER_PIXMAN_DUMB:
1045+ drm_fb_destroy_dumb(fb);
1046+ break;
1047+ case BUFFER_CURSOR:
1048+ case BUFFER_CLIENT:
1049+ gbm_bo_destroy(fb->bo);
1050+ break;
1051+ case BUFFER_GBM_SURFACE:
1052+ gbm_surface_release_buffer(fb->gbm_surface, fb->bo);
1053+ break;
1054+ default:
1055+ assert(NULL);
1056+ break;
1057+ }
1058+}
1059+
1060+/**
1061+ * Allocate a new, empty, plane state.
1062+ */
1063+static struct drm_plane_state *
1064+drm_plane_state_alloc(struct drm_output_state *state_output,
1065+ struct drm_plane *plane)
1066+{
1067+ struct drm_plane_state *state = zalloc(sizeof(*state));
1068+
1069+ assert(state);
1070+ state->output_state = state_output;
1071+ state->plane = plane;
1072+
1073+ /* Here we only add the plane state to the desired link, and not
1074+ * set the member. Having an output pointer set means that the
1075+ * plane will be displayed on the output; this won't be the case
1076+ * when we go to disable a plane. In this case, it must be part of
1077+ * the commit (and thus the output state), but the member must be
1078+ * NULL, as it will not be on any output when the state takes
1079+ * effect.
1080+ */
1081+ if (state_output)
1082+ wl_list_insert(&state_output->plane_list, &state->link);
1083+ else
1084+ wl_list_init(&state->link);
1085+
1086+ return state;
1087+}
1088+
1089+/**
1090+ * Free an existing plane state. As a special case, the state will not
1091+ * normally be freed if it is the current state; see drm_plane_set_state.
1092+ */
1093+static void
1094+drm_plane_state_free(struct drm_plane_state *state, bool force)
1095+{
1096+ if (!state)
1097+ return;
1098+
1099+ wl_list_remove(&state->link);
1100+ wl_list_init(&state->link);
1101+ state->output_state = NULL;
1102+
1103+ if (force || state != state->plane->state_cur) {
1104+ drm_fb_unref(state->fb);
1105+ free(state);
1106+ }
1107+}
1108+
1109+/**
1110+ * Duplicate an existing plane state into a new plane state, storing it within
1111+ * the given output state. If the output state already contains a plane state
1112+ * for the drm_plane referenced by 'src', that plane state is freed first.
1113+ */
1114+static struct drm_plane_state *
1115+drm_plane_state_duplicate(struct drm_output_state *state_output,
1116+ struct drm_plane_state *src)
1117+{
1118+ struct drm_plane_state *dst = malloc(sizeof(*dst));
1119+ struct drm_plane_state *old, *tmp;
1120+
1121+ assert(src);
1122+ assert(dst);
1123+ *dst = *src;
1124+ wl_list_init(&dst->link);
1125+
1126+ wl_list_for_each_safe(old, tmp, &state_output->plane_list, link) {
1127+ /* Duplicating a plane state into the same output state, so
1128+ * it can replace itself with an identical copy of itself,
1129+ * makes no sense. */
1130+ assert(old != src);
1131+ if (old->plane == dst->plane)
1132+ drm_plane_state_free(old, false);
1133+ }
1134+
1135+ wl_list_insert(&state_output->plane_list, &dst->link);
1136+ if (src->fb)
1137+ dst->fb = drm_fb_ref(src->fb);
1138+ dst->output_state = state_output;
1139+ dst->complete = false;
1140+
1141+ return dst;
1142+}
1143+
1144+/**
1145+ * Remove a plane state from an output state; if the plane was previously
1146+ * enabled, then replace it with a disabling state. This ensures that the
1147+ * output state was untouched from it was before the plane state was
1148+ * modified by the caller of this function.
1149+ *
1150+ * This is required as drm_output_state_get_plane may either allocate a
1151+ * new plane state, in which case this function will just perform a matching
1152+ * drm_plane_state_free, or it may instead repurpose an existing disabling
1153+ * state (if the plane was previously active), in which case this function
1154+ * will reset it.
1155+ */
1156+static void
1157+drm_plane_state_put_back(struct drm_plane_state *state)
1158+{
1159+ struct drm_output_state *state_output;
1160+ struct drm_plane *plane;
1161+
1162+ if (!state)
1163+ return;
1164+
1165+ state_output = state->output_state;
1166+ plane = state->plane;
1167+ drm_plane_state_free(state, false);
1168+
1169+ /* Plane was previously disabled; no need to keep this temporary
1170+ * state around. */
1171+ if (!plane->state_cur->fb)
1172+ return;
1173+
1174+ (void) drm_plane_state_alloc(state_output, plane);
1175+}
1176+
1177+/**
1178+ * Return a plane state from a drm_output_state.
1179+ */
1180+static struct drm_plane_state *
1181+drm_output_state_get_existing_plane(struct drm_output_state *state_output,
1182+ struct drm_plane *plane)
1183+{
1184+ struct drm_plane_state *ps;
1185+
1186+ wl_list_for_each(ps, &state_output->plane_list, link) {
1187+ if (ps->plane == plane)
1188+ return ps;
1189+ }
1190+
1191+ return NULL;
1192+}
1193+
1194+/**
1195+ * Return a plane state from a drm_output_state, either existing or
1196+ * freshly allocated.
1197+ */
1198+static struct drm_plane_state *
1199+drm_output_state_get_plane(struct drm_output_state *state_output,
1200+ struct drm_plane *plane)
1201+{
1202+ struct drm_plane_state *ps;
1203+
1204+ ps = drm_output_state_get_existing_plane(state_output, plane);
1205+ if (ps)
1206+ return ps;
1207+
1208+ return drm_plane_state_alloc(state_output, plane);
1209+}
1210+
1211+/**
1212+ * Allocate a new, empty drm_output_state. This should not generally be used
1213+ * in the repaint cycle; see drm_output_state_duplicate.
1214+ */
1215+static struct drm_output_state *
1216+drm_output_state_alloc(struct drm_output *output,
1217+ struct drm_pending_state *pending_state)
1218+{
1219+ struct drm_output_state *state = zalloc(sizeof(*state));
1220+
1221+ assert(state);
1222+ state->output = output;
1223+ state->dpms = WESTON_DPMS_OFF;
1224+ state->pending_state = pending_state;
1225+ if (pending_state)
1226+ wl_list_insert(&pending_state->output_list, &state->link);
1227+ else
1228+ wl_list_init(&state->link);
1229+
1230+ wl_list_init(&state->plane_list);
1231+
1232+ return state;
1233+}
1234+
1235+/**
1236+ * Duplicate an existing drm_output_state into a new one. This is generally
1237+ * used during the repaint cycle, to capture the existing state of an output
1238+ * and modify it to create a new state to be used.
1239+ *
1240+ * The mode determines whether the output will be reset to an a blank state,
1241+ * or an exact mirror of the current state.
1242+ */
1243+static struct drm_output_state *
1244+drm_output_state_duplicate(struct drm_output_state *src,
1245+ struct drm_pending_state *pending_state,
1246+ enum drm_output_state_duplicate_mode plane_mode)
1247+{
1248+ struct drm_output_state *dst = malloc(sizeof(*dst));
1249+ struct drm_plane_state *ps;
1250+
1251+ assert(dst);
1252+
1253+ /* Copy the whole structure, then individually modify the
1254+ * pending_state, as well as the list link into our pending
1255+ * state. */
1256+ *dst = *src;
1257+
1258+ dst->pending_state = pending_state;
1259+ if (pending_state)
1260+ wl_list_insert(&pending_state->output_list, &dst->link);
1261+ else
1262+ wl_list_init(&dst->link);
1263+
1264+ wl_list_init(&dst->plane_list);
1265+
1266+ wl_list_for_each(ps, &src->plane_list, link) {
1267+ /* Don't carry planes which are now disabled; these should be
1268+ * free for other outputs to reuse. */
1269+ if (!ps->output)
1270+ continue;
1271+
1272+ if (plane_mode == DRM_OUTPUT_STATE_CLEAR_PLANES)
1273+ (void) drm_plane_state_alloc(dst, ps->plane);
1274+ else
1275+ (void) drm_plane_state_duplicate(dst, ps);
1276+ }
1277+
1278+ return dst;
1279+}
1280+
1281+/**
1282+ * Free an unused drm_output_state.
1283+ */
1284+static void
1285+drm_output_state_free(struct drm_output_state *state)
1286+{
1287+ struct drm_plane_state *ps, *next;
1288+
1289+ if (!state)
1290+ return;
1291+
1292+ wl_list_for_each_safe(ps, next, &state->plane_list, link)
1293+ drm_plane_state_free(ps, false);
1294+
1295+ wl_list_remove(&state->link);
1296+
1297+ free(state);
1298+}
1299+
1300+/**
1301+ * Get output state to disable output
1302+ *
1303+ * Returns a pointer to an output_state object which can be used to disable
1304+ * an output (e.g. DPMS off).
1305+ *
1306+ * @param pending_state The pending state object owning this update
1307+ * @param output The output to disable
1308+ * @returns A drm_output_state to disable the output
1309+ */
1310+static struct drm_output_state *
1311+drm_output_get_disable_state(struct drm_pending_state *pending_state,
1312+ struct drm_output *output)
1313+{
1314+ struct drm_output_state *output_state;
1315+
1316+ output_state = drm_output_state_duplicate(output->state_cur,
1317+ pending_state,
1318+ DRM_OUTPUT_STATE_CLEAR_PLANES);
1319+ output_state->dpms = WESTON_DPMS_OFF;
1320+
1321+ return output_state;
1322+}
1323+
1324+/**
1325+ * Allocate a new drm_pending_state
1326+ *
1327+ * Allocate a new, empty, 'pending state' structure to be used across a
1328+ * repaint cycle or similar.
1329+ *
1330+ * @param backend DRM backend
1331+ * @returns Newly-allocated pending state structure
1332+ */
1333+static struct drm_pending_state *
1334+drm_pending_state_alloc(struct drm_backend *backend)
1335+{
1336+ struct drm_pending_state *ret;
1337+
1338+ ret = calloc(1, sizeof(*ret));
1339+ if (!ret)
1340+ return NULL;
1341+
1342+ ret->backend = backend;
1343+ wl_list_init(&ret->output_list);
1344+
1345+ return ret;
1346+}
1347+
1348+/**
1349+ * Free a drm_pending_state structure
1350+ *
1351+ * Frees a pending_state structure, as well as any output_states connected
1352+ * to this pending state.
1353+ *
1354+ * @param pending_state Pending state structure to free
1355+ */
1356+static void
1357+drm_pending_state_free(struct drm_pending_state *pending_state)
1358+{
1359+ struct drm_output_state *output_state, *tmp;
1360+
1361+ if (!pending_state)
1362+ return;
1363+
1364+ wl_list_for_each_safe(output_state, tmp, &pending_state->output_list,
1365+ link) {
1366+ drm_output_state_free(output_state);
1367+ }
1368+
1369+ free(pending_state);
1370+}
1371+
1372+/**
1373+ * Find an output state in a pending state
1374+ *
1375+ * Given a pending_state structure, find the output_state for a particular
1376+ * output.
1377+ *
1378+ * @param pending_state Pending state structure to search
1379+ * @param output Output to find state for
1380+ * @returns Output state if present, or NULL if not
1381+ */
1382+static struct drm_output_state *
1383+drm_pending_state_get_output(struct drm_pending_state *pending_state,
1384+ struct drm_output *output)
1385+{
1386+ struct drm_output_state *output_state;
1387+
1388+ wl_list_for_each(output_state, &pending_state->output_list, link) {
1389+ if (output_state->output == output)
1390+ return output_state;
1391+ }
1392+
1393+ return NULL;
1394+}
1395+
1396+static int drm_pending_state_apply_sync(struct drm_pending_state *state);
1397+
1398+/**
1399+ * Mark a drm_output_state (the output's last state) as complete. This handles
1400+ * any post-completion actions such as updating the repaint timer, disabling the
1401+ * output, and finally freeing the state.
1402+ */
1403+static void
1404+drm_output_update_complete(struct drm_output *output, uint32_t flags,
1405+ unsigned int sec, unsigned int usec)
1406+{
1407+ struct drm_backend *b = to_drm_backend(output->base.compositor);
1408+ struct drm_plane_state *ps;
1409+ struct timespec ts;
1410+
1411+ /* Stop the pageflip timer instead of rearming it here */
1412+ if (output->pageflip_timer)
1413+ wl_event_source_timer_update(output->pageflip_timer, 0);
1414+
1415+ wl_list_for_each(ps, &output->state_cur->plane_list, link)
1416+ ps->complete = true;
1417+
1418+ drm_output_state_free(output->state_last);
1419+ output->state_last = NULL;
1420+
1421+ if (output->destroy_pending) {
1422+ output->destroy_pending = 0;
1423+ output->disable_pending = 0;
1424+ output->dpms_off_pending = 0;
1425+ drm_output_destroy(&output->base);
1426+ return;
1427+ } else if (output->disable_pending) {
1428+ output->disable_pending = 0;
1429+ output->dpms_off_pending = 0;
1430+ weston_output_disable(&output->base);
1431+ return;
1432+ } else if (output->dpms_off_pending) {
1433+ struct drm_pending_state *pending = drm_pending_state_alloc(b);
1434+ output->dpms_off_pending = 0;
1435+ drm_output_get_disable_state(pending, output);
1436+ drm_pending_state_apply_sync(pending);
1437+ return;
1438+ } else if (output->state_cur->dpms == WESTON_DPMS_OFF &&
1439+ output->base.repaint_status != REPAINT_AWAITING_COMPLETION) {
1440+ /* DPMS can happen to us either in the middle of a repaint
1441+ * cycle (when we have painted fresh content, only to throw it
1442+ * away for DPMS off), or at any other random point. If the
1443+ * latter is true, then we cannot go through finish_frame,
1444+ * because the repaint machinery does not expect this. */
1445+ return;
1446+ }
1447+
1448+ ts.tv_sec = sec;
1449+ ts.tv_nsec = usec * 1000;
1450+ weston_output_finish_frame(&output->base, &ts, flags);
1451+
1452+ /* We can't call this from frame_notify, because the output's
1453+ * repaint needed flag is cleared just after that */
1454+ if (output->recorder)
1455+ weston_output_schedule_repaint(&output->base);
1456+}
1457+
1458+/**
1459+ * Mark an output state as current on the output, i.e. it has been
1460+ * submitted to the kernel. The mode argument determines whether this
1461+ * update will be applied synchronously (e.g. when calling drmModeSetCrtc),
1462+ * or asynchronously (in which case we wait for events to complete).
1463+ */
1464+static void
1465+drm_output_assign_state(struct drm_output_state *state,
1466+ enum drm_state_apply_mode mode)
1467+{
1468+ struct drm_output *output = state->output;
1469+ struct drm_backend *b = to_drm_backend(output->base.compositor);
1470+ struct drm_plane_state *plane_state;
1471+
1472+ assert(!output->state_last);
1473+
1474+ if (mode == DRM_STATE_APPLY_ASYNC)
1475+ output->state_last = output->state_cur;
1476+ else
1477+ drm_output_state_free(output->state_cur);
1478+
1479+ wl_list_remove(&state->link);
1480+ wl_list_init(&state->link);
1481+ state->pending_state = NULL;
1482+
1483+ output->state_cur = state;
1484+
1485+ if (b->atomic_modeset && mode == DRM_STATE_APPLY_ASYNC)
1486+ output->atomic_complete_pending = 1;
1487+
1488+ /* Replace state_cur on each affected plane with the new state, being
1489+ * careful to dispose of orphaned (but only orphaned) previous state.
1490+ * If the previous state is not orphaned (still has an output_state
1491+ * attached), it will be disposed of by freeing the output_state. */
1492+ wl_list_for_each(plane_state, &state->plane_list, link) {
1493+ struct drm_plane *plane = plane_state->plane;
1494+
1495+ if (plane->state_cur && !plane->state_cur->output_state)
1496+ drm_plane_state_free(plane->state_cur, true);
1497+ plane->state_cur = plane_state;
1498
1499- fb->is_client_buffer = 1;
1500+ if (mode != DRM_STATE_APPLY_ASYNC) {
1501+ plane_state->complete = true;
1502+ continue;
1503+ }
1504
1505- weston_buffer_reference(&fb->buffer_ref, buffer);
1506+ if (b->atomic_modeset)
1507+ continue;
1508+
1509+ if (plane->type == WDRM_PLANE_TYPE_OVERLAY)
1510+ output->vblank_pending++;
1511+ else if (plane->type == WDRM_PLANE_TYPE_PRIMARY)
1512+ output->page_flip_pending = 1;
1513+ }
1514 }
1515
1516-static void
1517-drm_output_release_fb(struct drm_output *output, struct drm_fb *fb)
1518+static int
1519+drm_view_transform_supported(struct weston_view *ev)
1520 {
1521- if (!fb)
1522- return;
1523-
1524- if (fb->map &&
1525- (fb != output->dumb[0] && fb != output->dumb[1])) {
1526- drm_fb_destroy_dumb(fb);
1527- } else if (fb->bo) {
1528- if (fb->is_client_buffer)
1529- gbm_bo_destroy(fb->bo);
1530- else
1531- gbm_surface_release_buffer(output->gbm_surface,
1532- fb->bo);
1533- }
1534+ return !ev->transform.enabled ||
1535+ (ev->transform.matrix.type < WESTON_MATRIX_TRANSFORM_ROTATE);
1536 }
1537
1538 static uint32_t
1539@@ -530,36 +1537,61 @@ drm_output_check_scanout_format(struct drm_output *output,
1540 }
1541
1542 static struct weston_plane *
1543-drm_output_prepare_scanout_view(struct drm_output *output,
1544+drm_output_prepare_scanout_view(struct drm_output_state *output_state,
1545 struct weston_view *ev)
1546 {
1547+ struct drm_output *output = output_state->output;
1548 struct drm_backend *b = to_drm_backend(output->base.compositor);
1549+ struct drm_plane *scanout_plane = output->scanout_plane;
1550+ struct drm_plane_state *state;
1551 struct weston_buffer *buffer = ev->surface->buffer_ref.buffer;
1552 struct weston_buffer_viewport *viewport = &ev->surface->buffer_viewport;
1553 struct gbm_bo *bo;
1554 uint32_t format;
1555
1556+ /* Don't import buffers which span multiple outputs. */
1557+ if (ev->output_mask != (1u << output->base.id))
1558+ return NULL;
1559+
1560 /* We use GBM to import buffers. */
1561 if (b->gbm == NULL)
1562 return NULL;
1563
1564 if (buffer == NULL)
1565 return NULL;
1566+ if (wl_shm_buffer_get(buffer->resource))
1567+ return NULL;
1568
1569 /* Make sure our view is exactly compatible with the output. */
1570 if (ev->geometry.x != output->base.x ||
1571 ev->geometry.y != output->base.y)
1572 return NULL;
1573+ if (buffer->width != output->base.current_mode->width ||
1574+ buffer->height != output->base.current_mode->height)
1575+ return NULL;
1576+
1577 if (ev->transform.enabled)
1578 return NULL;
1579 if (ev->geometry.scissor_enabled)
1580 return NULL;
1581+ if (viewport->buffer.transform != output->base.transform)
1582+ return NULL;
1583+ if (viewport->buffer.scale != output->base.current_scale)
1584+ return NULL;
1585+ if (!drm_view_transform_supported(ev))
1586+ return NULL;
1587
1588- if (buffer->width != output->base.current_mode->width ||
1589- buffer->height != output->base.current_mode->height)
1590+ if (ev->alpha != 1.0f)
1591 return NULL;
1592- if (viewport->buffer.transform != output->base.transform)
1593+
1594+ state = drm_output_state_get_plane(output_state, scanout_plane);
1595+ if (state->fb) {
1596+ /* If there is already a framebuffer on the scanout plane,
1597+ * a client view has already been placed on the scanout
1598+ * view. In that case, do not free or put back the state,
1599+ * but just leave it in place and quietly exit. */
1600 return NULL;
1601+ }
1602
1603 bo = gbm_bo_import(b->gbm, GBM_BO_IMPORT_WL_BUFFER,
1604 buffer->resource, GBM_BO_USE_SCANOUT);
1605@@ -570,26 +1602,42 @@ drm_output_prepare_scanout_view(struct drm_output *output,
1606
1607 format = drm_output_check_scanout_format(output, ev->surface, bo);
1608 if (format == 0) {
1609+ drm_plane_state_put_back(state);
1610 gbm_bo_destroy(bo);
1611 return NULL;
1612 }
1613
1614- output->next = drm_fb_get_from_bo(bo, b, format);
1615- if (!output->next) {
1616+ state->fb = drm_fb_get_from_bo(bo, b, format, BUFFER_CLIENT);
1617+ if (!state->fb) {
1618+ drm_plane_state_put_back(state);
1619 gbm_bo_destroy(bo);
1620 return NULL;
1621 }
1622
1623- drm_fb_set_buffer(output->next, buffer);
1624+ drm_fb_set_buffer(state->fb, buffer);
1625+
1626+ state->output = output;
1627+
1628+ state->src_x = 0;
1629+ state->src_y = 0;
1630+ state->src_w = state->fb->width << 16;
1631+ state->src_h = state->fb->height << 16;
1632
1633- return &output->fb_plane;
1634+ state->dest_x = 0;
1635+ state->dest_y = 0;
1636+ state->dest_w = output->base.current_mode->width;
1637+ state->dest_h = output->base.current_mode->height;
1638+
1639+ return &scanout_plane->base;
1640 }
1641
1642-static void
1643-drm_output_render_gl(struct drm_output *output, pixman_region32_t *damage)
1644+static struct drm_fb *
1645+drm_output_render_gl(struct drm_output_state *state, pixman_region32_t *damage)
1646 {
1647+ struct drm_output *output = state->output;
1648 struct drm_backend *b = to_drm_backend(output->base.compositor);
1649 struct gbm_bo *bo;
1650+ struct drm_fb *ret;
1651
1652 output->base.compositor->renderer->repaint_output(&output->base,
1653 damage);
1654@@ -597,20 +1645,25 @@ drm_output_render_gl(struct drm_output *output, pixman_region32_t *damage)
1655 bo = gbm_surface_lock_front_buffer(output->gbm_surface);
1656 if (!bo) {
1657 weston_log("failed to lock front buffer: %m\n");
1658- return;
1659+ return NULL;
1660 }
1661
1662- output->next = drm_fb_get_from_bo(bo, b, output->gbm_format);
1663- if (!output->next) {
1664+ ret = drm_fb_get_from_bo(bo, b, output->gbm_format, BUFFER_GBM_SURFACE);
1665+ if (!ret) {
1666 weston_log("failed to get drm_fb for bo\n");
1667 gbm_surface_release_buffer(output->gbm_surface, bo);
1668- return;
1669+ return NULL;
1670 }
1671+ ret->gbm_surface = output->gbm_surface;
1672+
1673+ return ret;
1674 }
1675
1676-static void
1677-drm_output_render_pixman(struct drm_output *output, pixman_region32_t *damage)
1678+static struct drm_fb *
1679+drm_output_render_pixman(struct drm_output_state *state,
1680+ pixman_region32_t *damage)
1681 {
1682+ struct drm_output *output = state->output;
1683 struct weston_compositor *ec = output->base.compositor;
1684 pixman_region32_t total_damage, previous_damage;
1685
1686@@ -624,7 +1677,6 @@ drm_output_render_pixman(struct drm_output *output, pixman_region32_t *damage)
1687
1688 output->current_image ^= 1;
1689
1690- output->next = output->dumb[output->current_image];
1691 pixman_renderer_output_set_buffer(&output->base,
1692 output->image[output->current_image]);
1693
1694@@ -632,18 +1684,60 @@ drm_output_render_pixman(struct drm_output *output, pixman_region32_t *damage)
1695
1696 pixman_region32_fini(&total_damage);
1697 pixman_region32_fini(&previous_damage);
1698+
1699+ return drm_fb_ref(output->dumb[output->current_image]);
1700 }
1701
1702 static void
1703-drm_output_render(struct drm_output *output, pixman_region32_t *damage)
1704+drm_output_render(struct drm_output_state *state, pixman_region32_t *damage)
1705 {
1706+ struct drm_output *output = state->output;
1707 struct weston_compositor *c = output->base.compositor;
1708+ struct drm_plane_state *scanout_state;
1709+ struct drm_plane *scanout_plane = output->scanout_plane;
1710 struct drm_backend *b = to_drm_backend(c);
1711+ struct drm_fb *fb;
1712+
1713+ /* If we already have a client buffer promoted to scanout, then we don't
1714+ * want to render. */
1715+ scanout_state = drm_output_state_get_plane(state,
1716+ output->scanout_plane);
1717+ if (scanout_state->fb)
1718+ return;
1719+
1720+ if (!pixman_region32_not_empty(damage) &&
1721+ scanout_plane->state_cur->fb &&
1722+ (scanout_plane->state_cur->fb->type == BUFFER_GBM_SURFACE ||
1723+ scanout_plane->state_cur->fb->type == BUFFER_PIXMAN_DUMB) &&
1724+ scanout_plane->state_cur->fb->width ==
1725+ output->base.current_mode->width &&
1726+ scanout_plane->state_cur->fb->height ==
1727+ output->base.current_mode->height) {
1728+ fb = drm_fb_ref(scanout_plane->state_cur->fb);
1729+ } else if (b->use_pixman) {
1730+ fb = drm_output_render_pixman(state, damage);
1731+ } else {
1732+ fb = drm_output_render_gl(state, damage);
1733+ }
1734+
1735+ if (!fb) {
1736+ drm_plane_state_put_back(scanout_state);
1737+ return;
1738+ }
1739+
1740+ scanout_state->fb = fb;
1741+ scanout_state->output = output;
1742+
1743+ scanout_state->src_x = 0;
1744+ scanout_state->src_y = 0;
1745+ scanout_state->src_w = output->base.current_mode->width << 16;
1746+ scanout_state->src_h = output->base.current_mode->height << 16;
1747+
1748+ scanout_state->dest_x = 0;
1749+ scanout_state->dest_y = 0;
1750+ scanout_state->dest_w = scanout_state->src_w >> 16;
1751+ scanout_state->dest_h = scanout_state->src_h >> 16;
1752
1753- if (b->use_pixman)
1754- drm_output_render_pixman(output, damage);
1755- else
1756- drm_output_render_gl(output, damage);
1757
1758 pixman_region32_subtract(&c->primary_plane.damage,
1759 &c->primary_plane.damage, damage);
1760@@ -661,8 +1755,6 @@ drm_output_set_gamma(struct weston_output *output_base,
1761 /* check */
1762 if (output_base->gamma_size != size)
1763 return;
1764- if (!output->original_crtc)
1765- return;
1766
1767 rc = drmModeCrtcSetGamma(backend->drm.fd,
1768 output->crtc_id,
1769@@ -697,102 +1789,612 @@ drm_waitvblank_pipe(struct drm_output *output)
1770 }
1771
1772 static int
1773-drm_output_repaint(struct weston_output *output_base,
1774- pixman_region32_t *damage)
1775+drm_output_apply_state_legacy(struct drm_output_state *state)
1776 {
1777- struct drm_output *output = to_drm_output(output_base);
1778- struct drm_backend *backend =
1779- to_drm_backend(output->base.compositor);
1780- struct drm_sprite *s;
1781+ struct drm_output *output = state->output;
1782+ struct drm_backend *backend = to_drm_backend(output->base.compositor);
1783+ struct drm_plane *scanout_plane = output->scanout_plane;
1784+ struct drm_property_info *dpms_prop =
1785+ &output->props_conn[WDRM_CONNECTOR_DPMS];
1786+ struct drm_plane_state *scanout_state;
1787+ struct drm_plane_state *ps;
1788+ struct drm_plane *p;
1789 struct drm_mode *mode;
1790+ struct timespec now;
1791 int ret = 0;
1792
1793- if (output->disable_pending || output->destroy_pending)
1794- return -1;
1795+ /* If disable_planes is set then assign_planes() wasn't
1796+ * called for this render, so we could still have a stale
1797+ * cursor plane set up.
1798+ */
1799+ if (output->base.disable_planes) {
1800+ output->cursor_view = NULL;
1801+ if (output->cursor_plane) {
1802+ output->cursor_plane->base.x = INT32_MIN;
1803+ output->cursor_plane->base.y = INT32_MIN;
1804+ }
1805+ }
1806
1807- if (!output->next)
1808- drm_output_render(output, damage);
1809- if (!output->next)
1810- return -1;
1811+ if (state->dpms != WESTON_DPMS_ON) {
1812+ wl_list_for_each(ps, &state->plane_list, link) {
1813+ p = ps->plane;
1814+ assert(ps->fb == NULL);
1815+ assert(ps->output == NULL);
1816+
1817+ if (p->type != WDRM_PLANE_TYPE_OVERLAY)
1818+ continue;
1819+
1820+ ret = drmModeSetPlane(backend->drm.fd, p->plane_id,
1821+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1822+ if (ret)
1823+ weston_log("drmModeSetPlane failed disable: %m\n");
1824+ }
1825+
1826+ if (output->cursor_plane) {
1827+ ret = drmModeSetCursor(backend->drm.fd, output->crtc_id,
1828+ 0, 0, 0);
1829+ if (ret)
1830+ weston_log("drmModeSetCursor failed disable: %m\n");
1831+ }
1832+
1833+ ret = drmModeSetCrtc(backend->drm.fd, output->crtc_id, 0, 0, 0,
1834+ &output->connector_id, 0, NULL);
1835+ if (ret)
1836+ weston_log("drmModeSetCrtc failed disabling: %m\n");
1837+
1838+ drm_output_assign_state(state, DRM_STATE_APPLY_SYNC);
1839+ weston_compositor_read_presentation_clock(output->base.compositor, &now);
1840+ drm_output_update_complete(output,
1841+ WP_PRESENTATION_FEEDBACK_KIND_HW_COMPLETION,
1842+ now.tv_sec, now.tv_nsec / 1000);
1843+
1844+ return 0;
1845+ }
1846
1847- mode = container_of(output->base.current_mode, struct drm_mode, base);
1848- if (!output->current ||
1849- output->current->stride != output->next->stride) {
1850+ scanout_state =
1851+ drm_output_state_get_existing_plane(state, scanout_plane);
1852+
1853+ /* The legacy SetCrtc API doesn't allow us to do scaling, and the
1854+ * legacy PageFlip API doesn't allow us to do clipping either. */
1855+ assert(scanout_state->src_x == 0);
1856+ assert(scanout_state->src_y == 0);
1857+ assert(scanout_state->src_w ==
1858+ (unsigned) (output->base.current_mode->width << 16));
1859+ assert(scanout_state->src_h ==
1860+ (unsigned) (output->base.current_mode->height << 16));
1861+ assert(scanout_state->dest_x == 0);
1862+ assert(scanout_state->dest_y == 0);
1863+ assert(scanout_state->dest_w == scanout_state->src_w >> 16);
1864+ assert(scanout_state->dest_h == scanout_state->src_h >> 16);
1865+
1866+ mode = to_drm_mode(output->base.current_mode);
1867+ if (backend->state_invalid || !scanout_plane->state_cur->fb ||
1868+ scanout_plane->state_cur->fb->stride != scanout_state->fb->stride) {
1869 ret = drmModeSetCrtc(backend->drm.fd, output->crtc_id,
1870- output->next->fb_id, 0, 0,
1871+ scanout_state->fb->fb_id,
1872+ 0, 0,
1873 &output->connector_id, 1,
1874 &mode->mode_info);
1875 if (ret) {
1876 weston_log("set mode failed: %m\n");
1877- goto err_pageflip;
1878+ goto err;
1879 }
1880- output_base->set_dpms(output_base, WESTON_DPMS_ON);
1881 }
1882
1883 if (drmModePageFlip(backend->drm.fd, output->crtc_id,
1884- output->next->fb_id,
1885+ scanout_state->fb->fb_id,
1886 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
1887 weston_log("queueing pageflip failed: %m\n");
1888- goto err_pageflip;
1889+ goto err;
1890 }
1891
1892- output->page_flip_pending = 1;
1893+ assert(!output->page_flip_pending);
1894+
1895+ if (output->pageflip_timer)
1896+ wl_event_source_timer_update(output->pageflip_timer,
1897+ backend->pageflip_timeout);
1898
1899- drm_output_set_cursor(output);
1900+ drm_output_set_cursor(state);
1901
1902 /*
1903 * Now, update all the sprite surfaces
1904 */
1905- wl_list_for_each(s, &backend->sprite_list, link) {
1906+ wl_list_for_each(ps, &state->plane_list, link) {
1907 uint32_t flags = 0, fb_id = 0;
1908 drmVBlank vbl = {
1909 .request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT,
1910 .request.sequence = 1,
1911 };
1912
1913- if ((!s->current && !s->next) ||
1914- !drm_sprite_crtc_supported(output, s))
1915- continue;
1916+ p = ps->plane;
1917+ if (p->type != WDRM_PLANE_TYPE_OVERLAY)
1918+ continue;
1919+
1920+ assert(p->state_cur->complete);
1921+ assert(!!p->state_cur->output == !!p->state_cur->fb);
1922+ assert(!p->state_cur->output || p->state_cur->output == output);
1923+ assert(!ps->complete);
1924+ assert(!ps->output || ps->output == output);
1925+ assert(!!ps->output == !!ps->fb);
1926+
1927+ if (ps->fb && !backend->sprites_hidden)
1928+ fb_id = ps->fb->fb_id;
1929+
1930+ ret = drmModeSetPlane(backend->drm.fd, p->plane_id,
1931+ output->crtc_id, fb_id, flags,
1932+ ps->dest_x, ps->dest_y,
1933+ ps->dest_w, ps->dest_h,
1934+ ps->src_x, ps->src_y,
1935+ ps->src_w, ps->src_h);
1936+ if (ret)
1937+ weston_log("setplane failed: %d: %s\n",
1938+ ret, strerror(errno));
1939+
1940+ vbl.request.type |= drm_waitvblank_pipe(output);
1941+
1942+ /*
1943+ * Queue a vblank signal so we know when the surface
1944+ * becomes active on the display or has been replaced.
1945+ */
1946+ vbl.request.signal = (unsigned long) ps;
1947+ ret = drmWaitVBlank(backend->drm.fd, &vbl);
1948+ if (ret) {
1949+ weston_log("vblank event request failed: %d: %s\n",
1950+ ret, strerror(errno));
1951+ }
1952+ }
1953+
1954+ if (dpms_prop->prop_id && state->dpms != output->state_cur->dpms) {
1955+ ret = drmModeConnectorSetProperty(backend->drm.fd,
1956+ output->connector_id,
1957+ dpms_prop->prop_id,
1958+ state->dpms);
1959+ if (ret) {
1960+ weston_log("DRM: DPMS: failed property set for %s\n",
1961+ output->base.name);
1962+ }
1963+ }
1964+
1965+ drm_output_assign_state(state, DRM_STATE_APPLY_ASYNC);
1966+
1967+ return 0;
1968+
1969+err:
1970+ output->cursor_view = NULL;
1971+ drm_output_state_free(state);
1972+ return -1;
1973+}
1974+
1975+#ifdef HAVE_DRM_ATOMIC
1976+static int
1977+crtc_add_prop(drmModeAtomicReq *req, struct drm_output *output,
1978+ enum wdrm_crtc_property prop, uint64_t val)
1979+{
1980+ struct drm_property_info *info = &output->props_crtc[prop];
1981+ int ret;
1982+
1983+ if (info->prop_id == 0)
1984+ return -1;
1985+
1986+ ret = drmModeAtomicAddProperty(req, output->crtc_id, info->prop_id,
1987+ val);
1988+ return (ret <= 0) ? -1 : 0;
1989+}
1990+
1991+static int
1992+connector_add_prop(drmModeAtomicReq *req, struct drm_output *output,
1993+ enum wdrm_connector_property prop, uint64_t val)
1994+{
1995+ struct drm_property_info *info = &output->props_conn[prop];
1996+ int ret;
1997+
1998+ if (info->prop_id == 0)
1999+ return -1;
2000+
2001+ ret = drmModeAtomicAddProperty(req, output->connector_id,
2002+ info->prop_id, val);
2003+ return (ret <= 0) ? -1 : 0;
2004+}
2005+
2006+static int
2007+plane_add_prop(drmModeAtomicReq *req, struct drm_plane *plane,
2008+ enum wdrm_plane_property prop, uint64_t val)
2009+{
2010+ struct drm_property_info *info = &plane->props[prop];
2011+ int ret;
2012+
2013+ if (info->prop_id == 0)
2014+ return -1;
2015+
2016+ ret = drmModeAtomicAddProperty(req, plane->plane_id, info->prop_id,
2017+ val);
2018+ return (ret <= 0) ? -1 : 0;
2019+}
2020+
2021+static int
2022+drm_mode_ensure_blob(struct drm_backend *backend, struct drm_mode *mode)
2023+{
2024+ int ret;
2025+
2026+ if (mode->blob_id)
2027+ return 0;
2028+
2029+ ret = drmModeCreatePropertyBlob(backend->drm.fd,
2030+ &mode->mode_info,
2031+ sizeof(mode->mode_info),
2032+ &mode->blob_id);
2033+ if (ret != 0)
2034+ weston_log("failed to create mode property blob: %m\n");
2035+
2036+ return ret;
2037+}
2038+
2039+static int
2040+drm_output_apply_state_atomic(struct drm_output_state *state,
2041+ drmModeAtomicReq *req,
2042+ uint32_t *flags)
2043+{
2044+ struct drm_output *output = state->output;
2045+ struct drm_backend *backend = to_drm_backend(output->base.compositor);
2046+ struct drm_plane_state *plane_state;
2047+ struct drm_mode *current_mode = to_drm_mode(output->base.current_mode);
2048+ int ret = 0;
2049+
2050+ if (state->dpms != output->state_cur->dpms)
2051+ *flags |= DRM_MODE_ATOMIC_ALLOW_MODESET;
2052+
2053+ if (state->dpms == WESTON_DPMS_ON) {
2054+ ret = drm_mode_ensure_blob(backend, current_mode);
2055+ if (ret != 0)
2056+ return ret;
2057+
2058+ ret |= crtc_add_prop(req, output, WDRM_CRTC_MODE_ID,
2059+ current_mode->blob_id);
2060+ ret |= crtc_add_prop(req, output, WDRM_CRTC_ACTIVE, 1);
2061+ ret |= connector_add_prop(req, output, WDRM_CONNECTOR_CRTC_ID,
2062+ output->crtc_id);
2063+ } else {
2064+ ret |= crtc_add_prop(req, output, WDRM_CRTC_MODE_ID, 0);
2065+ ret |= crtc_add_prop(req, output, WDRM_CRTC_ACTIVE, 0);
2066+ ret |= connector_add_prop(req, output, WDRM_CONNECTOR_CRTC_ID,
2067+ 0);
2068+ }
2069+
2070+ if (ret != 0) {
2071+ weston_log("couldn't set atomic CRTC/connector state\n");
2072+ return ret;
2073+ }
2074+
2075+ wl_list_for_each(plane_state, &state->plane_list, link) {
2076+ struct drm_plane *plane = plane_state->plane;
2077+
2078+ ret |= plane_add_prop(req, plane, WDRM_PLANE_FB_ID,
2079+ plane_state->fb ? plane_state->fb->fb_id : 0);
2080+ ret |= plane_add_prop(req, plane, WDRM_PLANE_CRTC_ID,
2081+ plane_state->fb ? output->crtc_id : 0);
2082+ ret |= plane_add_prop(req, plane, WDRM_PLANE_SRC_X,
2083+ plane_state->src_x);
2084+ ret |= plane_add_prop(req, plane, WDRM_PLANE_SRC_Y,
2085+ plane_state->src_y);
2086+ ret |= plane_add_prop(req, plane, WDRM_PLANE_SRC_W,
2087+ plane_state->src_w);
2088+ ret |= plane_add_prop(req, plane, WDRM_PLANE_SRC_H,
2089+ plane_state->src_h);
2090+ ret |= plane_add_prop(req, plane, WDRM_PLANE_CRTC_X,
2091+ plane_state->dest_x);
2092+ ret |= plane_add_prop(req, plane, WDRM_PLANE_CRTC_Y,
2093+ plane_state->dest_y);
2094+ ret |= plane_add_prop(req, plane, WDRM_PLANE_CRTC_W,
2095+ plane_state->dest_w);
2096+ ret |= plane_add_prop(req, plane, WDRM_PLANE_CRTC_H,
2097+ plane_state->dest_h);
2098+
2099+ if (ret != 0) {
2100+ weston_log("couldn't set plane state\n");
2101+ return ret;
2102+ }
2103+ }
2104+
2105+ return 0;
2106+}
2107+
2108+/**
2109+ * Helper function used only by drm_pending_state_apply, with the same
2110+ * guarantees and constraints as that function.
2111+ */
2112+static int
2113+drm_pending_state_apply_atomic(struct drm_pending_state *pending_state,
2114+ enum drm_state_apply_mode mode)
2115+{
2116+ struct drm_backend *b = pending_state->backend;
2117+ struct drm_output_state *output_state, *tmp;
2118+ struct drm_plane *plane;
2119+ drmModeAtomicReq *req = drmModeAtomicAlloc();
2120+ uint32_t flags = 0;
2121+ int ret = 0;
2122+
2123+ if (!req)
2124+ return -1;
2125+
2126+ if (b->state_invalid) {
2127+ uint32_t *unused;
2128+ int err;
2129+
2130+ /* If we need to reset all our state (e.g. because we've
2131+ * just started, or just been VT-switched in), explicitly
2132+ * disable all the CRTCs and connectors we aren't using. */
2133+ wl_array_for_each(unused, &b->unused_connectors) {
2134+ struct drm_property_info infos[WDRM_CONNECTOR__COUNT];
2135+ struct drm_property_info *info;
2136+ drmModeObjectProperties *props;
2137+
2138+ memset(infos, 0, sizeof(infos));
2139+
2140+ props = drmModeObjectGetProperties(b->drm.fd,
2141+ *unused,
2142+ DRM_MODE_OBJECT_CONNECTOR);
2143+ if (!props) {
2144+ ret = -1;
2145+ continue;
2146+ }
2147+
2148+ drm_property_info_populate(b, connector_props, infos,
2149+ WDRM_CONNECTOR__COUNT,
2150+ props);
2151+ drmModeFreeObjectProperties(props);
2152+
2153+ info = &infos[WDRM_CONNECTOR_CRTC_ID];
2154+ err = drmModeAtomicAddProperty(req, *unused,
2155+ info->prop_id, 0);
2156+ if (err <= 0)
2157+ ret = -1;
2158+
2159+ info = &infos[WDRM_CONNECTOR_DPMS];
2160+ if (info->prop_id > 0)
2161+ err = drmModeAtomicAddProperty(req, *unused,
2162+ info->prop_id,
2163+ DRM_MODE_DPMS_OFF);
2164+ if (err <= 0)
2165+ ret = -1;
2166+
2167+ drm_property_info_free(infos, WDRM_CONNECTOR__COUNT);
2168+ }
2169+
2170+ wl_array_for_each(unused, &b->unused_crtcs) {
2171+ struct drm_property_info infos[WDRM_CRTC__COUNT];
2172+ struct drm_property_info *info;
2173+ drmModeObjectProperties *props;
2174+ uint64_t active;
2175+
2176+ memset(infos, 0, sizeof(infos));
2177+
2178+ /* We can't emit a disable on a CRTC that's already
2179+ * off, as the kernel will refuse to generate an event
2180+ * for an off->off state and fail the commit.
2181+ */
2182+ props = drmModeObjectGetProperties(b->drm.fd,
2183+ *unused,
2184+ DRM_MODE_OBJECT_CRTC);
2185+ if (!props) {
2186+ ret = -1;
2187+ continue;
2188+ }
2189+
2190+ drm_property_info_populate(b, crtc_props, infos,
2191+ WDRM_CRTC__COUNT,
2192+ props);
2193+
2194+ info = &infos[WDRM_CRTC_ACTIVE];
2195+ active = drm_property_get_value(info, props, 0);
2196+ drmModeFreeObjectProperties(props);
2197+ if (active == 0) {
2198+ drm_property_info_free(infos, WDRM_CRTC__COUNT);
2199+ continue;
2200+ }
2201+
2202+ err = drmModeAtomicAddProperty(req, *unused,
2203+ info->prop_id, 0);
2204+ if (err <= 0)
2205+ ret = -1;
2206+
2207+ info = &infos[WDRM_CRTC_MODE_ID];
2208+ err = drmModeAtomicAddProperty(req, *unused,
2209+ info->prop_id, 0);
2210+ if (err <= 0)
2211+ ret = -1;
2212+
2213+ drm_property_info_free(infos, WDRM_CRTC__COUNT);
2214+ }
2215+
2216+ /* Disable all the planes; planes which are being used will
2217+ * override this state in the output-state application. */
2218+ wl_list_for_each(plane, &b->plane_list, link) {
2219+ plane_add_prop(req, plane, WDRM_PLANE_CRTC_ID, 0);
2220+ plane_add_prop(req, plane, WDRM_PLANE_FB_ID, 0);
2221+ }
2222+
2223+ flags |= DRM_MODE_ATOMIC_ALLOW_MODESET;
2224+ }
2225+
2226+ wl_list_for_each(output_state, &pending_state->output_list, link) {
2227+ if (mode == DRM_STATE_APPLY_SYNC)
2228+ assert(output_state->dpms == WESTON_DPMS_OFF);
2229+ ret |= drm_output_apply_state_atomic(output_state, req, &flags);
2230+ }
2231+
2232+ if (ret != 0) {
2233+ weston_log("atomic: couldn't compile atomic state\n");
2234+ goto out;
2235+ }
2236+
2237+ switch (mode) {
2238+ case DRM_STATE_APPLY_SYNC:
2239+ break;
2240+ case DRM_STATE_APPLY_ASYNC:
2241+ flags |= DRM_MODE_PAGE_FLIP_EVENT | DRM_MODE_ATOMIC_NONBLOCK;
2242+ break;
2243+ }
2244+
2245+ ret = drmModeAtomicCommit(b->drm.fd, req, flags, b);
2246+ if (ret != 0) {
2247+ weston_log("atomic: couldn't commit new state: %m\n");
2248+ goto out;
2249+ }
2250+
2251+ wl_list_for_each_safe(output_state, tmp, &pending_state->output_list,
2252+ link)
2253+ drm_output_assign_state(output_state, mode);
2254+
2255+ b->state_invalid = false;
2256+
2257+ assert(wl_list_empty(&pending_state->output_list));
2258+
2259+out:
2260+ drmModeAtomicFree(req);
2261+ drm_pending_state_free(pending_state);
2262+ return ret;
2263+}
2264+#endif
2265+
2266+/**
2267+ * Applies all of a pending_state asynchronously: the primary entry point for
2268+ * applying KMS state to a device. Updates the state for all outputs in the
2269+ * pending_state, as well as disabling any unclaimed outputs.
2270+ *
2271+ * Unconditionally takes ownership of pending_state, and clears state_invalid.
2272+ */
2273+static int
2274+drm_pending_state_apply(struct drm_pending_state *pending_state)
2275+{
2276+ struct drm_backend *b = pending_state->backend;
2277+ struct drm_output_state *output_state, *tmp;
2278+ uint32_t *unused;
2279+
2280+#ifdef HAVE_DRM_ATOMIC
2281+ if (b->atomic_modeset)
2282+ return drm_pending_state_apply_atomic(pending_state,
2283+ DRM_STATE_APPLY_ASYNC);
2284+#endif
2285+
2286+ if (b->state_invalid) {
2287+ /* If we need to reset all our state (e.g. because we've
2288+ * just started, or just been VT-switched in), explicitly
2289+ * disable all the CRTCs we aren't using. This also disables
2290+ * all connectors on these CRTCs, so we don't need to do that
2291+ * separately with the pre-atomic API. */
2292+ wl_array_for_each(unused, &b->unused_crtcs)
2293+ drmModeSetCrtc(b->drm.fd, *unused, 0, 0, 0, NULL, 0,
2294+ NULL);
2295+ }
2296+
2297+ wl_list_for_each_safe(output_state, tmp, &pending_state->output_list,
2298+ link) {
2299+ struct drm_output *output = output_state->output;
2300+ int ret;
2301+
2302+ ret = drm_output_apply_state_legacy(output_state);
2303+ if (ret != 0) {
2304+ weston_log("Couldn't apply state for output %s\n",
2305+ output->base.name);
2306+ }
2307+ }
2308+
2309+ b->state_invalid = false;
2310+
2311+ assert(wl_list_empty(&pending_state->output_list));
2312+
2313+ drm_pending_state_free(pending_state);
2314+
2315+ return 0;
2316+}
2317+
2318+/**
2319+ * The synchronous version of drm_pending_state_apply. May only be used to
2320+ * disable outputs. Does so synchronously: the request is guaranteed to have
2321+ * completed on return, and the output will not be touched afterwards.
2322+ *
2323+ * Unconditionally takes ownership of pending_state, and clears state_invalid.
2324+ */
2325+static int
2326+drm_pending_state_apply_sync(struct drm_pending_state *pending_state)
2327+{
2328+ struct drm_backend *b = pending_state->backend;
2329+ struct drm_output_state *output_state, *tmp;
2330+ uint32_t *unused;
2331+
2332+#ifdef HAVE_DRM_ATOMIC
2333+ if (b->atomic_modeset)
2334+ return drm_pending_state_apply_atomic(pending_state,
2335+ DRM_STATE_APPLY_SYNC);
2336+#endif
2337+
2338+ if (b->state_invalid) {
2339+ /* If we need to reset all our state (e.g. because we've
2340+ * just started, or just been VT-switched in), explicitly
2341+ * disable all the CRTCs we aren't using. This also disables
2342+ * all connectors on these CRTCs, so we don't need to do that
2343+ * separately with the pre-atomic API. */
2344+ wl_array_for_each(unused, &b->unused_crtcs)
2345+ drmModeSetCrtc(b->drm.fd, *unused, 0, 0, 0, NULL, 0,
2346+ NULL);
2347+ }
2348+
2349+ wl_list_for_each_safe(output_state, tmp, &pending_state->output_list,
2350+ link) {
2351+ int ret;
2352+
2353+ assert(output_state->dpms == WESTON_DPMS_OFF);
2354+ ret = drm_output_apply_state_legacy(output_state);
2355+ if (ret != 0) {
2356+ weston_log("Couldn't apply state for output %s\n",
2357+ output_state->output->base.name);
2358+ }
2359+ }
2360+
2361+ b->state_invalid = false;
2362
2363- if (s->next && !backend->sprites_hidden)
2364- fb_id = s->next->fb_id;
2365+ assert(wl_list_empty(&pending_state->output_list));
2366
2367- ret = drmModeSetPlane(backend->drm.fd, s->plane_id,
2368- output->crtc_id, fb_id, flags,
2369- s->dest_x, s->dest_y,
2370- s->dest_w, s->dest_h,
2371- s->src_x, s->src_y,
2372- s->src_w, s->src_h);
2373- if (ret)
2374- weston_log("setplane failed: %d: %s\n",
2375- ret, strerror(errno));
2376+ drm_pending_state_free(pending_state);
2377
2378- vbl.request.type |= drm_waitvblank_pipe(output);
2379+ return 0;
2380+}
2381
2382- /*
2383- * Queue a vblank signal so we know when the surface
2384- * becomes active on the display or has been replaced.
2385- */
2386- vbl.request.signal = (unsigned long)s;
2387- ret = drmWaitVBlank(backend->drm.fd, &vbl);
2388- if (ret) {
2389- weston_log("vblank event request failed: %d: %s\n",
2390- ret, strerror(errno));
2391- }
2392+static int
2393+drm_output_repaint(struct weston_output *output_base,
2394+ pixman_region32_t *damage,
2395+ void *repaint_data)
2396+{
2397+ struct drm_pending_state *pending_state = repaint_data;
2398+ struct drm_output *output = to_drm_output(output_base);
2399+ struct drm_output_state *state = NULL;
2400+ struct drm_plane_state *scanout_state;
2401
2402- s->output = output;
2403- output->vblank_pending = 1;
2404- }
2405+ if (output->disable_pending || output->destroy_pending)
2406+ goto err;
2407
2408- return 0;
2409+ assert(!output->state_last);
2410+
2411+ /* If planes have been disabled in the core, we might not have
2412+ * hit assign_planes at all, so might not have valid output state
2413+ * here. */
2414+ state = drm_pending_state_get_output(pending_state, output);
2415+ if (!state)
2416+ state = drm_output_state_duplicate(output->state_cur,
2417+ pending_state,
2418+ DRM_OUTPUT_STATE_CLEAR_PLANES);
2419+ state->dpms = WESTON_DPMS_ON;
2420+
2421+ drm_output_render(state, damage);
2422+ scanout_state = drm_output_state_get_plane(state,
2423+ output->scanout_plane);
2424+ if (!scanout_state || !scanout_state->fb)
2425+ goto err;
2426
2427-err_pageflip:
2428- output->cursor_view = NULL;
2429- if (output->next) {
2430- drm_output_release_fb(output, output->next);
2431- output->next = NULL;
2432- }
2433+ return 0;
2434
2435+err:
2436+ drm_output_state_free(state);
2437 return -1;
2438 }
2439
2440@@ -800,9 +2402,10 @@ static void
2441 drm_output_start_repaint_loop(struct weston_output *output_base)
2442 {
2443 struct drm_output *output = to_drm_output(output_base);
2444+ struct drm_pending_state *pending_state;
2445+ struct drm_plane *scanout_plane = output->scanout_plane;
2446 struct drm_backend *backend =
2447 to_drm_backend(output_base->compositor);
2448- uint32_t fb_id;
2449 struct timespec ts, tnow;
2450 struct timespec vbl2now;
2451 int64_t refresh_nsec;
2452@@ -816,11 +2419,19 @@ drm_output_start_repaint_loop(struct weston_output *output_base)
2453 if (output->disable_pending || output->destroy_pending)
2454 return;
2455
2456- if (!output->current) {
2457+ if (!output->scanout_plane->state_cur->fb) {
2458 /* We can't page flip if there's no mode set */
2459 goto finish_frame;
2460 }
2461
2462+ /* Need to smash all state in from scratch; current timings might not
2463+ * be what we want, page flip might not work, etc.
2464+ */
2465+ if (backend->state_invalid)
2466+ goto finish_frame;
2467+
2468+ assert(scanout_plane->state_cur->output == output);
2469+
2470 /* Try to get current msc and timestamp via instant query */
2471 vbl.request.type |= drm_waitvblank_pipe(output);
2472 ret = drmWaitVBlank(backend->drm.fd, &vbl);
2473@@ -850,11 +2461,17 @@ drm_output_start_repaint_loop(struct weston_output *output_base)
2474 /* Immediate query didn't provide valid timestamp.
2475 * Use pageflip fallback.
2476 */
2477- fb_id = output->current->fb_id;
2478
2479- if (drmModePageFlip(backend->drm.fd, output->crtc_id, fb_id,
2480- DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
2481- weston_log("queueing pageflip failed: %m\n");
2482+ assert(!output->page_flip_pending);
2483+ assert(!output->state_last);
2484+
2485+ pending_state = drm_pending_state_alloc(backend);
2486+ drm_output_state_duplicate(output->state_cur, pending_state,
2487+ DRM_OUTPUT_STATE_PRESERVE_PLANES);
2488+
2489+ ret = drm_pending_state_apply(pending_state);
2490+ if (ret != 0) {
2491+ weston_log("applying repaint-start state failed: %m\n");
2492 goto finish_frame;
2493 }
2494
2495@@ -862,8 +2479,7 @@ drm_output_start_repaint_loop(struct weston_output *output_base)
2496
2497 finish_frame:
2498 /* if we cannot page-flip, immediately finish frame */
2499- weston_compositor_read_presentation_clock(output_base->compositor, &ts);
2500- weston_output_finish_frame(output_base, &ts,
2501+ weston_output_finish_frame(output_base, NULL,
2502 WP_PRESENTATION_FEEDBACK_INVALID);
2503 }
2504
2505@@ -882,70 +2498,132 @@ static void
2506 vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec,
2507 void *data)
2508 {
2509- struct drm_sprite *s = (struct drm_sprite *)data;
2510- struct drm_output *output = s->output;
2511- struct timespec ts;
2512+ struct drm_plane_state *ps = (struct drm_plane_state *) data;
2513+ struct drm_output_state *os = ps->output_state;
2514+ struct drm_output *output = os->output;
2515+ struct drm_backend *b = to_drm_backend(output->base.compositor);
2516 uint32_t flags = WP_PRESENTATION_FEEDBACK_KIND_HW_COMPLETION |
2517 WP_PRESENTATION_FEEDBACK_KIND_HW_CLOCK;
2518
2519+ assert(!b->atomic_modeset);
2520+
2521 drm_output_update_msc(output, frame);
2522- output->vblank_pending = 0;
2523+ output->vblank_pending--;
2524+ assert(output->vblank_pending >= 0);
2525
2526- drm_output_release_fb(output, s->current);
2527- s->current = s->next;
2528- s->next = NULL;
2529+ assert(ps->fb);
2530
2531- if (!output->page_flip_pending) {
2532- ts.tv_sec = sec;
2533- ts.tv_nsec = usec * 1000;
2534- weston_output_finish_frame(&output->base, &ts, flags);
2535- }
2536-}
2537+ if (output->page_flip_pending || output->vblank_pending)
2538+ return;
2539
2540-static void
2541-drm_output_destroy(struct weston_output *base);
2542+ drm_output_update_complete(output, flags, sec, usec);
2543+}
2544
2545 static void
2546 page_flip_handler(int fd, unsigned int frame,
2547 unsigned int sec, unsigned int usec, void *data)
2548 {
2549 struct drm_output *output = data;
2550- struct timespec ts;
2551+ struct drm_backend *b = to_drm_backend(output->base.compositor);
2552 uint32_t flags = WP_PRESENTATION_FEEDBACK_KIND_VSYNC |
2553 WP_PRESENTATION_FEEDBACK_KIND_HW_COMPLETION |
2554 WP_PRESENTATION_FEEDBACK_KIND_HW_CLOCK;
2555
2556 drm_output_update_msc(output, frame);
2557
2558- /* We don't set page_flip_pending on start_repaint_loop, in that case
2559- * we just want to page flip to the current buffer to get an accurate
2560- * timestamp */
2561- if (output->page_flip_pending) {
2562- drm_output_release_fb(output, output->current);
2563- output->current = output->next;
2564- output->next = NULL;
2565- }
2566-
2567+ assert(!b->atomic_modeset);
2568+ assert(output->page_flip_pending);
2569 output->page_flip_pending = 0;
2570
2571- if (output->destroy_pending)
2572- drm_output_destroy(&output->base);
2573- else if (output->disable_pending)
2574- weston_output_disable(&output->base);
2575- else if (!output->vblank_pending) {
2576- ts.tv_sec = sec;
2577- ts.tv_nsec = usec * 1000;
2578- weston_output_finish_frame(&output->base, &ts, flags);
2579+ if (output->vblank_pending)
2580+ return;
2581
2582- /* We can't call this from frame_notify, because the output's
2583- * repaint needed flag is cleared just after that */
2584- if (output->recorder)
2585- weston_output_schedule_repaint(&output->base);
2586- }
2587+ drm_output_update_complete(output, flags, sec, usec);
2588+}
2589+
2590+/**
2591+ * Begin a new repaint cycle
2592+ *
2593+ * Called by the core compositor at the beginning of a repaint cycle. Creates
2594+ * a new pending_state structure to own any output state created by individual
2595+ * output repaint functions until the repaint is flushed or cancelled.
2596+ */
2597+static void *
2598+drm_repaint_begin(struct weston_compositor *compositor)
2599+{
2600+ struct drm_backend *b = to_drm_backend(compositor);
2601+ struct drm_pending_state *ret;
2602+
2603+ ret = drm_pending_state_alloc(b);
2604+ b->repaint_data = ret;
2605+
2606+ return ret;
2607+}
2608+
2609+/**
2610+ * Flush a repaint set
2611+ *
2612+ * Called by the core compositor when a repaint cycle has been completed
2613+ * and should be flushed. Frees the pending state, transitioning ownership
2614+ * of the output state from the pending state, to the update itself. When
2615+ * the update completes (see drm_output_update_complete), the output
2616+ * state will be freed.
2617+ */
2618+static void
2619+drm_repaint_flush(struct weston_compositor *compositor, void *repaint_data)
2620+{
2621+ struct drm_backend *b = to_drm_backend(compositor);
2622+ struct drm_pending_state *pending_state = repaint_data;
2623+
2624+ drm_pending_state_apply(pending_state);
2625+ b->repaint_data = NULL;
2626+}
2627+
2628+/**
2629+ * Cancel a repaint set
2630+ *
2631+ * Called by the core compositor when a repaint has finished, so the data
2632+ * held across the repaint cycle should be discarded.
2633+ */
2634+static void
2635+drm_repaint_cancel(struct weston_compositor *compositor, void *repaint_data)
2636+{
2637+ struct drm_backend *b = to_drm_backend(compositor);
2638+ struct drm_pending_state *pending_state = repaint_data;
2639+
2640+ drm_pending_state_free(pending_state);
2641+ b->repaint_data = NULL;
2642+}
2643+
2644+#ifdef HAVE_DRM_ATOMIC
2645+static void
2646+atomic_flip_handler(int fd, unsigned int frame, unsigned int sec,
2647+ unsigned int usec, unsigned int crtc_id, void *data)
2648+{
2649+ struct drm_backend *b = data;
2650+ struct drm_output *output = drm_output_find_by_crtc(b, crtc_id);
2651+ uint32_t flags = WP_PRESENTATION_FEEDBACK_KIND_VSYNC |
2652+ WP_PRESENTATION_FEEDBACK_KIND_HW_COMPLETION |
2653+ WP_PRESENTATION_FEEDBACK_KIND_HW_CLOCK;
2654+
2655+ /* During the initial modeset, we can disable CRTCs which we don't
2656+ * actually handle during normal operation; this will give us events
2657+ * for unknown outputs. Ignore them. */
2658+ if (!output || !output->base.enabled)
2659+ return;
2660+
2661+ drm_output_update_msc(output, frame);
2662+
2663+ assert(b->atomic_modeset);
2664+ assert(output->atomic_complete_pending);
2665+ output->atomic_complete_pending = 0;
2666+
2667+ drm_output_update_complete(output, flags, sec, usec);
2668 }
2669+#endif
2670
2671 static uint32_t
2672-drm_output_check_sprite_format(struct drm_sprite *s,
2673+drm_output_check_plane_format(struct drm_plane *p,
2674 struct weston_view *ev, struct gbm_bo *bo)
2675 {
2676 uint32_t i, format;
2677@@ -966,31 +2644,25 @@ drm_output_check_sprite_format(struct drm_sprite *s,
2678 pixman_region32_fini(&r);
2679 }
2680
2681- for (i = 0; i < s->count_formats; i++)
2682- if (s->formats[i] == format)
2683+ for (i = 0; i < p->count_formats; i++)
2684+ if (p->formats[i] == format)
2685 return format;
2686
2687 return 0;
2688 }
2689
2690-static int
2691-drm_view_transform_supported(struct weston_view *ev)
2692-{
2693- return !ev->transform.enabled ||
2694- (ev->transform.matrix.type < WESTON_MATRIX_TRANSFORM_ROTATE);
2695-}
2696-
2697 static struct weston_plane *
2698-drm_output_prepare_overlay_view(struct drm_output *output,
2699+drm_output_prepare_overlay_view(struct drm_output_state *output_state,
2700 struct weston_view *ev)
2701 {
2702+ struct drm_output *output = output_state->output;
2703 struct weston_compositor *ec = output->base.compositor;
2704 struct drm_backend *b = to_drm_backend(ec);
2705 struct weston_buffer_viewport *viewport = &ev->surface->buffer_viewport;
2706 struct wl_resource *buffer_resource;
2707- struct drm_sprite *s;
2708+ struct drm_plane *p;
2709+ struct drm_plane_state *state = NULL;
2710 struct linux_dmabuf_buffer *dmabuf;
2711- int found = 0;
2712 struct gbm_bo *bo;
2713 pixman_region32_t dest_rect, src_rect;
2714 pixman_box32_t *box, tbox;
2715@@ -1024,18 +2696,24 @@ drm_output_prepare_overlay_view(struct drm_output *output,
2716 if (ev->alpha != 1.0f)
2717 return NULL;
2718
2719- wl_list_for_each(s, &b->sprite_list, link) {
2720- if (!drm_sprite_crtc_supported(output, s))
2721+ wl_list_for_each(p, &b->plane_list, link) {
2722+ if (p->type != WDRM_PLANE_TYPE_OVERLAY)
2723 continue;
2724
2725- if (!s->next) {
2726- found = 1;
2727- break;
2728+ if (!drm_plane_is_available(p, output))
2729+ continue;
2730+
2731+ state = drm_output_state_get_plane(output_state, p);
2732+ if (state->fb) {
2733+ state = NULL;
2734+ continue;
2735 }
2736+
2737+ break;
2738 }
2739
2740 /* No sprites available */
2741- if (!found)
2742+ if (!state)
2743 return NULL;
2744
2745 if ((dmabuf = linux_dmabuf_buffer_get(buffer_resource))) {
2746@@ -1072,32 +2750,30 @@ drm_output_prepare_overlay_view(struct drm_output *output,
2747 bo = gbm_bo_import(b->gbm, GBM_BO_IMPORT_FD, &gbm_dmabuf,
2748 GBM_BO_USE_SCANOUT);
2749 #else
2750- return NULL;
2751+ goto err;
2752 #endif
2753 } else {
2754 bo = gbm_bo_import(b->gbm, GBM_BO_IMPORT_WL_BUFFER,
2755 buffer_resource, GBM_BO_USE_SCANOUT);
2756 }
2757 if (!bo)
2758- return NULL;
2759+ goto err;
2760
2761- format = drm_output_check_sprite_format(s, ev, bo);
2762- if (format == 0) {
2763- gbm_bo_destroy(bo);
2764- return NULL;
2765- }
2766+ format = drm_output_check_plane_format(p, ev, bo);
2767+ if (format == 0)
2768+ goto err;
2769
2770- s->next = drm_fb_get_from_bo(bo, b, format);
2771- if (!s->next) {
2772- gbm_bo_destroy(bo);
2773- return NULL;
2774- }
2775+ state->fb = drm_fb_get_from_bo(bo, b, format, BUFFER_CLIENT);
2776+ if (!state->fb)
2777+ goto err;
2778+
2779+ drm_fb_set_buffer(state->fb, ev->surface->buffer_ref.buffer);
2780
2781- drm_fb_set_buffer(s->next, ev->surface->buffer_ref.buffer);
2782+ state->output = output;
2783
2784 box = pixman_region32_extents(&ev->transform.boundingbox);
2785- s->plane.x = box->x1;
2786- s->plane.y = box->y1;
2787+ p->base.x = box->x1;
2788+ p->base.y = box->y1;
2789
2790 /*
2791 * Calculate the source & dest rects properly based on actual
2792@@ -1114,10 +2790,10 @@ drm_output_prepare_overlay_view(struct drm_output *output,
2793 output->base.transform,
2794 output->base.current_scale,
2795 *box);
2796- s->dest_x = tbox.x1;
2797- s->dest_y = tbox.y1;
2798- s->dest_w = tbox.x2 - tbox.x1;
2799- s->dest_h = tbox.y2 - tbox.y1;
2800+ state->dest_x = tbox.x1;
2801+ state->dest_y = tbox.y1;
2802+ state->dest_w = tbox.x2 - tbox.x1;
2803+ state->dest_h = tbox.y2 - tbox.y1;
2804 pixman_region32_fini(&dest_rect);
2805
2806 pixman_region32_init(&src_rect);
2807@@ -1154,27 +2830,83 @@ drm_output_prepare_overlay_view(struct drm_output *output,
2808 viewport->buffer.scale,
2809 tbox);
2810
2811- s->src_x = tbox.x1 << 8;
2812- s->src_y = tbox.y1 << 8;
2813- s->src_w = (tbox.x2 - tbox.x1) << 8;
2814- s->src_h = (tbox.y2 - tbox.y1) << 8;
2815+ state->src_x = tbox.x1 << 8;
2816+ state->src_y = tbox.y1 << 8;
2817+ state->src_w = (tbox.x2 - tbox.x1) << 8;
2818+ state->src_h = (tbox.y2 - tbox.y1) << 8;
2819 pixman_region32_fini(&src_rect);
2820
2821- return &s->plane;
2822+ return &p->base;
2823+
2824+err:
2825+ drm_plane_state_put_back(state);
2826+ if (bo)
2827+ gbm_bo_destroy(bo);
2828+ return NULL;
2829+}
2830+
2831+/**
2832+ * Update the image for the current cursor surface
2833+ *
2834+ * @param b DRM backend structure
2835+ * @param bo GBM buffer object to write into
2836+ * @param ev View to use for cursor image
2837+ */
2838+static void
2839+cursor_bo_update(struct drm_backend *b, struct gbm_bo *bo,
2840+ struct weston_view *ev)
2841+{
2842+ struct weston_buffer *buffer = ev->surface->buffer_ref.buffer;
2843+ uint32_t buf[b->cursor_width * b->cursor_height];
2844+ int32_t stride;
2845+ uint8_t *s;
2846+ int i;
2847+
2848+ assert(buffer && buffer->shm_buffer);
2849+ assert(buffer->shm_buffer == wl_shm_buffer_get(buffer->resource));
2850+ assert(ev->surface->width <= b->cursor_width);
2851+ assert(ev->surface->height <= b->cursor_height);
2852+
2853+ memset(buf, 0, sizeof buf);
2854+ stride = wl_shm_buffer_get_stride(buffer->shm_buffer);
2855+ s = wl_shm_buffer_get_data(buffer->shm_buffer);
2856+
2857+ wl_shm_buffer_begin_access(buffer->shm_buffer);
2858+ for (i = 0; i < ev->surface->height; i++)
2859+ memcpy(buf + i * b->cursor_width,
2860+ s + i * stride,
2861+ ev->surface->width * 4);
2862+ wl_shm_buffer_end_access(buffer->shm_buffer);
2863+
2864+ if (gbm_bo_write(bo, buf, sizeof buf) < 0)
2865+ weston_log("failed update cursor: %m\n");
2866 }
2867
2868 static struct weston_plane *
2869-drm_output_prepare_cursor_view(struct drm_output *output,
2870+drm_output_prepare_cursor_view(struct drm_output_state *output_state,
2871 struct weston_view *ev)
2872 {
2873+ struct drm_output *output = output_state->output;
2874 struct drm_backend *b = to_drm_backend(output->base.compositor);
2875+ struct drm_plane *plane = output->cursor_plane;
2876+ struct drm_plane_state *plane_state;
2877 struct weston_buffer_viewport *viewport = &ev->surface->buffer_viewport;
2878 struct wl_shm_buffer *shmbuf;
2879+ bool needs_update = false;
2880+ float x, y;
2881
2882+ if (!plane)
2883+ return NULL;
2884+
2885+#if 0
2886 if (b->cursors_are_broken)
2887 return NULL;
2888+#endif
2889+
2890+ if (!plane->state_cur->complete)
2891+ return NULL;
2892
2893- if (output->cursor_view)
2894+ if (plane->state_cur->output && plane->state_cur->output != output)
2895 return NULL;
2896
2897 /* Don't import buffers which span multiple outputs. */
2898@@ -1207,111 +2939,120 @@ drm_output_prepare_cursor_view(struct drm_output *output,
2899 ev->surface->height > b->cursor_height)
2900 return NULL;
2901
2902- output->cursor_view = ev;
2903-
2904- return &output->cursor_plane;
2905-}
2906-
2907-/**
2908- * Update the image for the current cursor surface
2909- *
2910- * @param b DRM backend structure
2911- * @param bo GBM buffer object to write into
2912- * @param ev View to use for cursor image
2913- */
2914-static void
2915-cursor_bo_update(struct drm_backend *b, struct gbm_bo *bo,
2916- struct weston_view *ev)
2917-{
2918- struct weston_buffer *buffer = ev->surface->buffer_ref.buffer;
2919- uint32_t buf[b->cursor_width * b->cursor_height];
2920- int32_t stride;
2921- uint8_t *s;
2922- int i;
2923-
2924- assert(buffer && buffer->shm_buffer);
2925- assert(buffer->shm_buffer == wl_shm_buffer_get(buffer->resource));
2926- assert(ev->surface->width <= b->cursor_width);
2927- assert(ev->surface->height <= b->cursor_height);
2928+ plane_state =
2929+ drm_output_state_get_plane(output_state, output->cursor_plane);
2930
2931- memset(buf, 0, sizeof buf);
2932- stride = wl_shm_buffer_get_stride(buffer->shm_buffer);
2933- s = wl_shm_buffer_get_data(buffer->shm_buffer);
2934+ if (plane_state && plane_state->fb)
2935+ return NULL;
2936
2937- wl_shm_buffer_begin_access(buffer->shm_buffer);
2938- for (i = 0; i < ev->surface->height; i++)
2939- memcpy(buf + i * b->cursor_width,
2940- s + i * stride,
2941- ev->surface->width * 4);
2942- wl_shm_buffer_end_access(buffer->shm_buffer);
2943+ /* Since we're setting plane state up front, we need to work out
2944+ * whether or not we need to upload a new cursor. We can't use the
2945+ * plane damage, since the planes haven't actually been calculated
2946+ * yet: instead try to figure it out directly. KMS cursor planes are
2947+ * pretty unique here, in that they lie partway between a Weston plane
2948+ * (direct scanout) and a renderer. */
2949+ if (ev != output->cursor_view ||
2950+ pixman_region32_not_empty(&ev->surface->damage)) {
2951+ output->current_cursor++;
2952+ output->current_cursor =
2953+ output->current_cursor %
2954+ ARRAY_LENGTH(output->gbm_cursor_fb);
2955+ needs_update = true;
2956+ }
2957
2958- if (gbm_bo_write(bo, buf, sizeof buf) < 0)
2959- weston_log("failed update cursor: %m\n");
2960+ output->cursor_view = ev;
2961+ weston_view_to_global_float(ev, 0, 0, &x, &y);
2962+ plane->base.x = x;
2963+ plane->base.y = y;
2964+
2965+ plane_state->fb =
2966+ drm_fb_ref(output->gbm_cursor_fb[output->current_cursor]);
2967+ plane_state->output = output;
2968+ plane_state->src_x = 0;
2969+ plane_state->src_y = 0;
2970+ plane_state->src_w = b->cursor_width << 16;
2971+ plane_state->src_h = b->cursor_height << 16;
2972+ plane_state->dest_x = (x - output->base.x) * output->base.current_scale;
2973+ plane_state->dest_y = (y - output->base.y) * output->base.current_scale;
2974+ plane_state->dest_w = b->cursor_width;
2975+ plane_state->dest_h = b->cursor_height;
2976+
2977+ if (needs_update)
2978+ cursor_bo_update(b, plane_state->fb->bo, ev);
2979+
2980+ return &plane->base;
2981 }
2982
2983 static void
2984-drm_output_set_cursor(struct drm_output *output)
2985+drm_output_set_cursor(struct drm_output_state *output_state)
2986 {
2987- struct weston_view *ev = output->cursor_view;
2988- struct weston_buffer *buffer;
2989+ struct drm_output *output = output_state->output;
2990 struct drm_backend *b = to_drm_backend(output->base.compositor);
2991+ struct drm_plane *plane = output->cursor_plane;
2992+ struct drm_plane_state *state;
2993 EGLint handle;
2994 struct gbm_bo *bo;
2995- float x, y;
2996
2997- output->cursor_view = NULL;
2998- if (ev == NULL) {
2999+ if (!plane)
3000+ return;
3001+
3002+ state = drm_output_state_get_existing_plane(output_state, plane);
3003+ if (!state)
3004+ return;
3005+
3006+ if (!state->fb) {
3007+ pixman_region32_fini(&plane->base.damage);
3008+ pixman_region32_init(&plane->base.damage);
3009 drmModeSetCursor(b->drm.fd, output->crtc_id, 0, 0, 0);
3010- output->cursor_plane.x = INT32_MIN;
3011- output->cursor_plane.y = INT32_MIN;
3012 return;
3013 }
3014
3015- buffer = ev->surface->buffer_ref.buffer;
3016-
3017- if (buffer &&
3018- pixman_region32_not_empty(&output->cursor_plane.damage)) {
3019- pixman_region32_fini(&output->cursor_plane.damage);
3020- pixman_region32_init(&output->cursor_plane.damage);
3021- output->current_cursor ^= 1;
3022- bo = output->gbm_cursor_bo[output->current_cursor];
3023+ assert(state->fb == output->gbm_cursor_fb[output->current_cursor]);
3024+ assert(!plane->state_cur->output || plane->state_cur->output == output);
3025
3026- cursor_bo_update(b, bo, ev);
3027+ if (plane->state_cur->fb != state->fb) {
3028+ bo = state->fb->bo;
3029 handle = gbm_bo_get_handle(bo).s32;
3030 if (drmModeSetCursor(b->drm.fd, output->crtc_id, handle,
3031- b->cursor_width, b->cursor_height)) {
3032+ b->cursor_width, b->cursor_height)) {
3033 weston_log("failed to set cursor: %m\n");
3034- b->cursors_are_broken = 1;
3035+ goto err;
3036 }
3037 }
3038
3039- weston_view_to_global_float(ev, 0, 0, &x, &y);
3040+ pixman_region32_fini(&plane->base.damage);
3041+ pixman_region32_init(&plane->base.damage);
3042
3043- /* From global to output space, output transform is guaranteed to be
3044- * NORMAL by drm_output_prepare_cursor_view().
3045- */
3046- x = (x - output->base.x) * output->base.current_scale;
3047- y = (y - output->base.y) * output->base.current_scale;
3048+ if (drmModeMoveCursor(b->drm.fd, output->crtc_id,
3049+ state->dest_x, state->dest_y)) {
3050+ weston_log("failed to move cursor: %m\n");
3051+ goto err;
3052+ }
3053
3054- if (output->cursor_plane.x != x || output->cursor_plane.y != y) {
3055- if (drmModeMoveCursor(b->drm.fd, output->crtc_id, x, y)) {
3056- weston_log("failed to move cursor: %m\n");
3057- b->cursors_are_broken = 1;
3058- }
3059+ return;
3060
3061- output->cursor_plane.x = x;
3062- output->cursor_plane.y = y;
3063- }
3064+err:
3065+ b->cursors_are_broken = 1;
3066+ drmModeSetCursor(b->drm.fd, output->crtc_id, 0, 0, 0);
3067 }
3068
3069 static void
3070-drm_assign_planes(struct weston_output *output_base)
3071+drm_assign_planes(struct weston_output *output_base, void *repaint_data)
3072 {
3073 struct drm_backend *b = to_drm_backend(output_base->compositor);
3074+ struct drm_pending_state *pending_state = repaint_data;
3075 struct drm_output *output = to_drm_output(output_base);
3076- struct weston_view *ev, *next;
3077- pixman_region32_t overlap, surface_overlap;
3078+ struct drm_output_state *state;
3079+ struct drm_plane_state *plane_state;
3080+ struct weston_view *ev;
3081+ pixman_region32_t surface_overlap, renderer_region;
3082 struct weston_plane *primary, *next_plane;
3083+ bool picked_scanout = false;
3084+
3085+ assert(!output->state_last);
3086+ state = drm_output_state_duplicate(output->state_cur,
3087+ pending_state,
3088+ DRM_OUTPUT_STATE_CLEAR_PLANES);
3089
3090 /*
3091 * Find a surface for each sprite in the output using some heuristics:
3092@@ -1326,10 +3067,10 @@ drm_assign_planes(struct weston_output *output_base)
3093 * the client buffer can be used directly for the sprite surface
3094 * as we do for flipping full screen surfaces.
3095 */
3096- pixman_region32_init(&overlap);
3097+ pixman_region32_init(&renderer_region);
3098 primary = &output_base->compositor->primary_plane;
3099
3100- wl_list_for_each_safe(ev, next, &output_base->compositor->view_list, link) {
3101+ wl_list_for_each(ev, &output_base->compositor->view_list, link) {
3102 struct weston_surface *es = ev->surface;
3103
3104 /* Test whether this buffer can ever go into a plane:
3105@@ -1350,29 +3091,40 @@ drm_assign_planes(struct weston_output *output_base)
3106 es->keep_buffer = false;
3107
3108 pixman_region32_init(&surface_overlap);
3109- pixman_region32_intersect(&surface_overlap, &overlap,
3110+ pixman_region32_intersect(&surface_overlap, &renderer_region,
3111 &ev->transform.boundingbox);
3112
3113 next_plane = NULL;
3114- if (pixman_region32_not_empty(&surface_overlap))
3115+ if (pixman_region32_not_empty(&surface_overlap) || picked_scanout)
3116 next_plane = primary;
3117 if (next_plane == NULL)
3118- next_plane = drm_output_prepare_cursor_view(output, ev);
3119- if (next_plane == NULL)
3120- next_plane = drm_output_prepare_scanout_view(output, ev);
3121+ next_plane = drm_output_prepare_cursor_view(state, ev);
3122+
3123+ /* If a higher-stacked view already got assigned to scanout, it's incorrect to
3124+ * assign a subsequent (lower-stacked) view to scanout.
3125+ */
3126+ if (next_plane == NULL) {
3127+ next_plane = drm_output_prepare_scanout_view(state, ev);
3128+ if (next_plane)
3129+ picked_scanout = true;
3130+ }
3131+
3132 if (next_plane == NULL)
3133- next_plane = drm_output_prepare_overlay_view(output, ev);
3134+ next_plane = drm_output_prepare_overlay_view(state, ev);
3135+
3136 if (next_plane == NULL)
3137 next_plane = primary;
3138
3139 weston_view_move_to_plane(ev, next_plane);
3140
3141 if (next_plane == primary)
3142- pixman_region32_union(&overlap, &overlap,
3143+ pixman_region32_union(&renderer_region,
3144+ &renderer_region,
3145 &ev->transform.boundingbox);
3146
3147 if (next_plane == primary ||
3148- next_plane == &output->cursor_plane) {
3149+ (output->cursor_plane &&
3150+ next_plane == &output->cursor_plane->base)) {
3151 /* cursor plane involves a copy */
3152 ev->psf_flags = 0;
3153 } else {
3154@@ -1384,7 +3136,20 @@ drm_assign_planes(struct weston_output *output_base)
3155
3156 pixman_region32_fini(&surface_overlap);
3157 }
3158- pixman_region32_fini(&overlap);
3159+ pixman_region32_fini(&renderer_region);
3160+
3161+ /* We rely on output->cursor_view being both an accurate reflection of
3162+ * the cursor plane's state, but also being maintained across repaints
3163+ * to avoid unnecessary damage uploads, per the comment in
3164+ * drm_output_prepare_cursor_view. In the event that we go from having
3165+ * a cursor view to not having a cursor view, we need to clear it. */
3166+ if (output->cursor_view) {
3167+ plane_state =
3168+ drm_output_state_get_existing_plane(state,
3169+ output->cursor_plane);
3170+ if (!plane_state || !plane_state->fb)
3171+ output->cursor_view = NULL;
3172+ }
3173 }
3174
3175 /**
3176@@ -1407,7 +3172,7 @@ choose_mode (struct drm_output *output, struct weston_mode *target_mode)
3177 output->base.current_mode->height == target_mode->height &&
3178 (output->base.current_mode->refresh == target_mode->refresh ||
3179 target_mode->refresh == 0))
3180- return (struct drm_mode *)output->base.current_mode;
3181+ return to_drm_mode(output->base.current_mode);
3182
3183 wl_list_for_each(mode, &output->base.mode_list, base.link) {
3184 if (mode->mode_info.hdisplay == target_mode->width &&
3185@@ -1435,26 +3200,13 @@ drm_output_fini_pixman(struct drm_output *output);
3186 static int
3187 drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
3188 {
3189- struct drm_output *output;
3190- struct drm_mode *drm_mode;
3191- struct drm_backend *b;
3192-
3193- if (output_base == NULL) {
3194- weston_log("output is NULL.\n");
3195- return -1;
3196- }
3197-
3198- if (mode == NULL) {
3199- weston_log("mode is NULL.\n");
3200- return -1;
3201- }
3202-
3203- b = to_drm_backend(output_base->compositor);
3204- output = to_drm_output(output_base);
3205- drm_mode = choose_mode (output, mode);
3206+ struct drm_output *output = to_drm_output(output_base);
3207+ struct drm_backend *b = to_drm_backend(output_base->compositor);
3208+ struct drm_mode *drm_mode = choose_mode(output, mode);
3209
3210 if (!drm_mode) {
3211- weston_log("%s, invalid resolution:%dx%d\n", __func__, mode->width, mode->height);
3212+ weston_log("%s: invalid resolution %dx%d\n",
3213+ output_base->name, mode->width, mode->height);
3214 return -1;
3215 }
3216
3217@@ -1467,10 +3219,13 @@ drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mo
3218 output->base.current_mode->flags =
3219 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
3220
3221- /* reset rendering stuff. */
3222- drm_output_release_fb(output, output->current);
3223- drm_output_release_fb(output, output->next);
3224- output->current = output->next = NULL;
3225+ /* XXX: This drops our current buffer too early, before we've started
3226+ * displaying it. Ideally this should be much more atomic and
3227+ * integrated with a full repaint cycle, rather than doing a
3228+ * sledgehammer modeswitch first, and only later showing new
3229+ * content.
3230+ */
3231+ b->state_invalid = true;
3232
3233 if (b->use_pixman) {
3234 drm_output_fini_pixman(output);
3235@@ -1494,11 +3249,21 @@ drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mo
3236 static int
3237 on_drm_input(int fd, uint32_t mask, void *data)
3238 {
3239+#ifdef HAVE_DRM_ATOMIC
3240+ struct drm_backend *b = data;
3241+#endif
3242 drmEventContext evctx;
3243
3244 memset(&evctx, 0, sizeof evctx);
3245- evctx.version = DRM_EVENT_CONTEXT_VERSION;
3246- evctx.page_flip_handler = page_flip_handler;
3247+#ifndef HAVE_DRM_ATOMIC
3248+ evctx.version = 2;
3249+#else
3250+ evctx.version = 3;
3251+ if (b->atomic_modeset)
3252+ evctx.page_flip_handler2 = atomic_flip_handler;
3253+ else
3254+#endif
3255+ evctx.page_flip_handler = page_flip_handler;
3256 evctx.vblank_handler = vblank_handler;
3257 drmHandleEvent(fd, &evctx);
3258
3259@@ -1506,36 +3271,15 @@ on_drm_input(int fd, uint32_t mask, void *data)
3260 }
3261
3262 static int
3263-init_drm(struct drm_backend *b, struct udev_device *device)
3264+init_kms_caps(struct drm_backend *b)
3265 {
3266- const char *filename, *sysnum;
3267 uint64_t cap;
3268- int fd, ret;
3269+ int ret;
3270 clockid_t clk_id;
3271
3272- sysnum = udev_device_get_sysnum(device);
3273- if (sysnum)
3274- b->drm.id = atoi(sysnum);
3275- if (!sysnum || b->drm.id < 0) {
3276- weston_log("cannot get device sysnum\n");
3277- return -1;
3278- }
3279-
3280- filename = udev_device_get_devnode(device);
3281- fd = weston_launcher_open(b->compositor->launcher, filename, O_RDWR);
3282- if (fd < 0) {
3283- /* Probably permissions error */
3284- weston_log("couldn't open %s, skipping\n",
3285- udev_device_get_devnode(device));
3286- return -1;
3287- }
3288-
3289- weston_log("using %s\n", filename);
3290-
3291- b->drm.fd = fd;
3292- b->drm.filename = strdup(filename);
3293+ weston_log("using %s\n", b->drm.filename);
3294
3295- ret = drmGetCap(fd, DRM_CAP_TIMESTAMP_MONOTONIC, &cap);
3296+ ret = drmGetCap(b->drm.fd, DRM_CAP_TIMESTAMP_MONOTONIC, &cap);
3297 if (ret == 0 && cap == 1)
3298 clk_id = CLOCK_MONOTONIC;
3299 else
3300@@ -1547,18 +3291,40 @@ init_drm(struct drm_backend *b, struct udev_device *device)
3301 return -1;
3302 }
3303
3304- ret = drmGetCap(fd, DRM_CAP_CURSOR_WIDTH, &cap);
3305+ ret = drmGetCap(b->drm.fd, DRM_CAP_CURSOR_WIDTH, &cap);
3306 if (ret == 0)
3307 b->cursor_width = cap;
3308 else
3309 b->cursor_width = 64;
3310
3311- ret = drmGetCap(fd, DRM_CAP_CURSOR_HEIGHT, &cap);
3312+ ret = drmGetCap(b->drm.fd, DRM_CAP_CURSOR_HEIGHT, &cap);
3313 if (ret == 0)
3314 b->cursor_height = cap;
3315 else
3316 b->cursor_height = 64;
3317
3318+ if (!getenv("WESTON_DISABLE_UNIVERSAL_PLANES")) {
3319+ ret = drmSetClientCap(b->drm.fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
3320+ b->universal_planes = (ret == 0);
3321+ }
3322+ weston_log("DRM: %s universal planes\n",
3323+ b->universal_planes ? "supports" : "does not support");
3324+
3325+#ifdef HAVE_DRM_ATOMIC
3326+ if (b->universal_planes && !getenv("WESTON_DISABLE_ATOMIC")) {
3327+ #if 0
3328+ ret = drmGetCap(b->drm.fd, DRM_CAP_CRTC_IN_VBLANK_EVENT, &cap);
3329+ if (ret != 0)
3330+ cap = 0;
3331+ #endif
3332+ cap = 1 ;
3333+ ret = drmSetClientCap(b->drm.fd, DRM_CLIENT_CAP_ATOMIC, 1);
3334+ b->atomic_modeset = ((ret == 0) && (cap == 1));
3335+ }
3336+#endif
3337+ weston_log("DRM: %s atomic modesetting\n",
3338+ b->atomic_modeset ? "supports" : "does not support");
3339+
3340 return 0;
3341 }
3342
3343@@ -1642,7 +3408,6 @@ init_egl(struct drm_backend *b)
3344
3345 if (drm_backend_create_gl_renderer(b) < 0) {
3346 gbm_device_destroy(b->gbm);
3347- b->gbm = NULL;
3348 return -1;
3349 }
3350
3351@@ -1656,6 +3421,293 @@ init_pixman(struct drm_backend *b)
3352 }
3353
3354 /**
3355+ * Create a drm_plane for a hardware plane
3356+ *
3357+ * Creates one drm_plane structure for a hardware plane, and initialises its
3358+ * properties and formats.
3359+ *
3360+ * In the absence of universal plane support, where KMS does not explicitly
3361+ * expose the primary and cursor planes to userspace, this may also create
3362+ * an 'internal' plane for internal management.
3363+ *
3364+ * This function does not add the plane to the list of usable planes in Weston
3365+ * itself; the caller is responsible for this.
3366+ *
3367+ * Call drm_plane_destroy to clean up the plane.
3368+ *
3369+ * @sa drm_output_find_special_plane
3370+ * @param b DRM compositor backend
3371+ * @param kplane DRM plane to create, or NULL if creating internal plane
3372+ * @param output Output to create internal plane for, or NULL
3373+ * @param type Type to use when creating internal plane, or invalid
3374+ * @param format Format to use for internal planes, or 0
3375+ */
3376+static struct drm_plane *
3377+drm_plane_create(struct drm_backend *b, const drmModePlane *kplane,
3378+ struct drm_output *output, enum wdrm_plane_type type,
3379+ uint32_t format)
3380+{
3381+ struct drm_plane *plane;
3382+ drmModeObjectProperties *props;
3383+ int num_formats = (kplane) ? kplane->count_formats : 1;
3384+
3385+ plane = zalloc(sizeof(*plane) +
3386+ (sizeof(uint32_t) * num_formats));
3387+ if (!plane) {
3388+ weston_log("%s: out of memory\n", __func__);
3389+ return NULL;
3390+ }
3391+
3392+ plane->backend = b;
3393+ plane->state_cur = drm_plane_state_alloc(NULL, plane);
3394+ plane->state_cur->complete = true;
3395+
3396+ if (kplane) {
3397+ plane->possible_crtcs = kplane->possible_crtcs;
3398+ plane->plane_id = kplane->plane_id;
3399+ plane->count_formats = kplane->count_formats;
3400+ memcpy(plane->formats, kplane->formats,
3401+ kplane->count_formats * sizeof(kplane->formats[0]));
3402+
3403+ props = drmModeObjectGetProperties(b->drm.fd, kplane->plane_id,
3404+ DRM_MODE_OBJECT_PLANE);
3405+ if (!props) {
3406+ weston_log("couldn't get plane properties\n");
3407+ goto err;
3408+ }
3409+ drm_property_info_populate(b, plane_props, plane->props,
3410+ WDRM_PLANE__COUNT, props);
3411+ plane->type =
3412+ drm_property_get_value(&plane->props[WDRM_PLANE_TYPE],
3413+ props,
3414+ WDRM_PLANE_TYPE__COUNT);
3415+ drmModeFreeObjectProperties(props);
3416+ }
3417+ else {
3418+ plane->possible_crtcs = (1 << output->pipe);
3419+ plane->plane_id = 0;
3420+ plane->count_formats = 1;
3421+ plane->formats[0] = format;
3422+ plane->type = type;
3423+ }
3424+
3425+ if (plane->type == WDRM_PLANE_TYPE__COUNT)
3426+ goto err_props;
3427+
3428+ /* With universal planes, everything is a DRM plane; without
3429+ * universal planes, the only DRM planes are overlay planes.
3430+ * Everything else is a fake plane. */
3431+ if (b->universal_planes) {
3432+ assert(kplane);
3433+ } else {
3434+ if (kplane)
3435+ assert(plane->type == WDRM_PLANE_TYPE_OVERLAY);
3436+ else
3437+ assert(plane->type != WDRM_PLANE_TYPE_OVERLAY &&
3438+ output);
3439+ }
3440+
3441+ weston_plane_init(&plane->base, b->compositor, 0, 0);
3442+ wl_list_insert(&b->plane_list, &plane->link);
3443+
3444+ return plane;
3445+
3446+err_props:
3447+ drm_property_info_free(plane->props, WDRM_PLANE__COUNT);
3448+err:
3449+ drm_plane_state_free(plane->state_cur, true);
3450+ free(plane);
3451+ return NULL;
3452+}
3453+
3454+/**
3455+ * Find, or create, a special-purpose plane
3456+ *
3457+ * Primary and cursor planes are a special case, in that before universal
3458+ * planes, they are driven by non-plane API calls. Without universal plane
3459+ * support, the only way to configure a primary plane is via drmModeSetCrtc,
3460+ * and the only way to configure a cursor plane is drmModeSetCursor2.
3461+ *
3462+ * Although they may actually be regular planes in the hardware, without
3463+ * universal plane support, these planes are not actually exposed to
3464+ * userspace in the regular plane list.
3465+ *
3466+ * However, for ease of internal tracking, we want to manage all planes
3467+ * through the same drm_plane structures. Therefore, when we are running
3468+ * without universal plane support, we create fake drm_plane structures
3469+ * to track these planes.
3470+ *
3471+ * @param b DRM backend
3472+ * @param output Output to use for plane
3473+ * @param type Type of plane
3474+ */
3475+static struct drm_plane *
3476+drm_output_find_special_plane(struct drm_backend *b, struct drm_output *output,
3477+ enum wdrm_plane_type type)
3478+{
3479+ struct drm_plane *plane;
3480+
3481+ if (!b->universal_planes) {
3482+ uint32_t format;
3483+
3484+ switch (type) {
3485+ case WDRM_PLANE_TYPE_CURSOR:
3486+ format = GBM_FORMAT_ARGB8888;
3487+ break;
3488+ case WDRM_PLANE_TYPE_PRIMARY:
3489+ /* We don't know what formats the primary plane supports
3490+ * before universal planes, so we just assume that the
3491+ * GBM format works; however, this isn't set until after
3492+ * the output is created. */
3493+ format = 0;
3494+ break;
3495+ default:
3496+ assert(!"invalid type in drm_output_find_special_plane");
3497+ break;
3498+ }
3499+
3500+ return drm_plane_create(b, NULL, output, type, format);
3501+ }
3502+
3503+ wl_list_for_each(plane, &b->plane_list, link) {
3504+ struct drm_output *tmp;
3505+ bool found_elsewhere = false;
3506+
3507+ if (plane->type != type)
3508+ continue;
3509+ if (!drm_plane_is_available(plane, output))
3510+ continue;
3511+
3512+ /* On some platforms, primary/cursor planes can roam
3513+ * between different CRTCs, so make sure we don't claim the
3514+ * same plane for two outputs. */
3515+ wl_list_for_each(tmp, &b->compositor->pending_output_list,
3516+ base.link) {
3517+ if (tmp->cursor_plane == plane ||
3518+ tmp->scanout_plane == plane) {
3519+ found_elsewhere = true;
3520+ break;
3521+ }
3522+ }
3523+ wl_list_for_each(tmp, &b->compositor->output_list,
3524+ base.link) {
3525+ if (tmp->cursor_plane == plane ||
3526+ tmp->scanout_plane == plane) {
3527+ found_elsewhere = true;
3528+ break;
3529+ }
3530+ }
3531+
3532+ if (found_elsewhere)
3533+ continue;
3534+
3535+ plane->possible_crtcs = (1 << output->pipe);
3536+ return plane;
3537+ }
3538+
3539+ return NULL;
3540+}
3541+
3542+/**
3543+ * Destroy one DRM plane
3544+ *
3545+ * Destroy a DRM plane, removing it from screen and releasing its retained
3546+ * buffers in the process. The counterpart to drm_plane_create.
3547+ *
3548+ * @param plane Plane to deallocate (will be freed)
3549+ */
3550+static void
3551+drm_plane_destroy(struct drm_plane *plane)
3552+{
3553+ if (plane->type == WDRM_PLANE_TYPE_OVERLAY)
3554+ drmModeSetPlane(plane->backend->drm.fd, plane->plane_id,
3555+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
3556+ drm_plane_state_free(plane->state_cur, true);
3557+ drm_property_info_free(plane->props, WDRM_PLANE__COUNT);
3558+ weston_plane_release(&plane->base);
3559+ wl_list_remove(&plane->link);
3560+ free(plane);
3561+}
3562+
3563+/**
3564+ * Initialise sprites (overlay planes)
3565+ *
3566+ * Walk the list of provided DRM planes, and add overlay planes.
3567+ *
3568+ * Call destroy_sprites to free these planes.
3569+ *
3570+ * @param b DRM compositor backend
3571+ */
3572+static void
3573+create_sprites(struct drm_backend *b)
3574+{
3575+ drmModePlaneRes *kplane_res;
3576+ drmModePlane *kplane;
3577+ struct drm_plane *drm_plane;
3578+ uint32_t i;
3579+ kplane_res = drmModeGetPlaneResources(b->drm.fd);
3580+ if (!kplane_res) {
3581+ weston_log("failed to get plane resources: %s\n",
3582+ strerror(errno));
3583+ return;
3584+ }
3585+
3586+ for (i = 0; i < kplane_res->count_planes; i++) {
3587+ kplane = drmModeGetPlane(b->drm.fd, kplane_res->planes[i]);
3588+ if (!kplane)
3589+ continue;
3590+
3591+ drm_plane = drm_plane_create(b, kplane, NULL,
3592+ WDRM_PLANE_TYPE__COUNT, 0);
3593+ drmModeFreePlane(kplane);
3594+ if (!drm_plane)
3595+ continue;
3596+
3597+ if (drm_plane->type == WDRM_PLANE_TYPE_OVERLAY)
3598+ weston_compositor_stack_plane(b->compositor,
3599+ &drm_plane->base,
3600+ &b->compositor->primary_plane);
3601+ }
3602+
3603+ drmModeFreePlaneResources(kplane_res);
3604+}
3605+
3606+/**
3607+ * Clean up sprites (overlay planes)
3608+ *
3609+ * The counterpart to create_sprites.
3610+ *
3611+ * @param b DRM compositor backend
3612+ */
3613+static void
3614+destroy_sprites(struct drm_backend *b)
3615+{
3616+ struct drm_plane *plane, *next;
3617+
3618+ wl_list_for_each_safe(plane, next, &b->plane_list, link)
3619+ drm_plane_destroy(plane);
3620+}
3621+
3622+static uint32_t
3623+drm_refresh_rate_mHz(const drmModeModeInfo *info)
3624+{
3625+ uint64_t refresh;
3626+
3627+ /* Calculate higher precision (mHz) refresh rate */
3628+ refresh = (info->clock * 1000000LL / info->htotal +
3629+ info->vtotal / 2) / info->vtotal;
3630+
3631+ if (info->flags & DRM_MODE_FLAG_INTERLACE)
3632+ refresh *= 2;
3633+ if (info->flags & DRM_MODE_FLAG_DBLSCAN)
3634+ refresh /= 2;
3635+ if (info->vscan > 1)
3636+ refresh /= info->vscan;
3637+
3638+ return refresh;
3639+}
3640+
3641+/**
3642 * Add a mode to output's mode list
3643 *
3644 * Copy the supplied DRM mode into a Weston mode structure, and add it to the
3645@@ -1669,7 +3721,6 @@ static struct drm_mode *
3646 drm_output_add_mode(struct drm_output *output, const drmModeModeInfo *info)
3647 {
3648 struct drm_mode *mode;
3649- uint64_t refresh;
3650
3651 mode = malloc(sizeof *mode);
3652 if (mode == NULL)
3653@@ -1679,19 +3730,9 @@ drm_output_add_mode(struct drm_output *output, const drmModeModeInfo *info)
3654 mode->base.width = info->hdisplay;
3655 mode->base.height = info->vdisplay;
3656
3657- /* Calculate higher precision (mHz) refresh rate */
3658- refresh = (info->clock * 1000000LL / info->htotal +
3659- info->vtotal / 2) / info->vtotal;
3660-
3661- if (info->flags & DRM_MODE_FLAG_INTERLACE)
3662- refresh *= 2;
3663- if (info->flags & DRM_MODE_FLAG_DBLSCAN)
3664- refresh /= 2;
3665- if (info->vscan > 1)
3666- refresh /= info->vscan;
3667-
3668- mode->base.refresh = refresh;
3669+ mode->base.refresh = drm_refresh_rate_mHz(info);
3670 mode->mode_info = *info;
3671+ mode->blob_id = 0;
3672
3673 if (info->type & DRM_MODE_TYPE_PREFERRED)
3674 mode->base.flags |= WL_OUTPUT_MODE_PREFERRED;
3675@@ -1701,6 +3742,32 @@ drm_output_add_mode(struct drm_output *output, const drmModeModeInfo *info)
3676 return mode;
3677 }
3678
3679+/**
3680+ * Destroys a mode, and removes it from the list.
3681+ */
3682+static void
3683+drm_output_destroy_mode(struct drm_backend *backend, struct drm_mode *mode)
3684+{
3685+ if (mode->blob_id)
3686+ drmModeDestroyPropertyBlob(backend->drm.fd, mode->blob_id);
3687+ wl_list_remove(&mode->base.link);
3688+ free(mode);
3689+}
3690+
3691+/** Destroy a list of drm_modes
3692+ *
3693+ * @param backend The backend for releasing mode property blobs.
3694+ * @param mode_list The list linked by drm_mode::base.link.
3695+ */
3696+static void
3697+drm_mode_list_destroy(struct drm_backend *backend, struct wl_list *mode_list)
3698+{
3699+ struct drm_mode *mode, *next;
3700+
3701+ wl_list_for_each_safe(mode, next, mode_list, base.link)
3702+ drm_output_destroy_mode(backend, mode);
3703+}
3704+
3705 static int
3706 drm_subpixel_to_wayland(int drm_value)
3707 {
3708@@ -1757,46 +3824,72 @@ drm_set_backlight(struct weston_output *output_base, uint32_t value)
3709 backlight_set_brightness(output->backlight, new_brightness);
3710 }
3711
3712-static drmModePropertyPtr
3713-drm_get_prop(int fd, drmModeConnectorPtr connector, const char *name)
3714-{
3715- drmModePropertyPtr props;
3716- int i;
3717-
3718- for (i = 0; i < connector->count_props; i++) {
3719- props = drmModeGetProperty(fd, connector->props[i]);
3720- if (!props)
3721- continue;
3722-
3723- if (!strcmp(props->name, name))
3724- return props;
3725-
3726- drmModeFreeProperty(props);
3727- }
3728-
3729- return NULL;
3730-}
3731-
3732+/**
3733+ * Power output on or off
3734+ *
3735+ * The DPMS/power level of an output is used to switch it on or off. This
3736+ * is DRM's hook for doing so, which can called either as part of repaint,
3737+ * or independently of the repaint loop.
3738+ *
3739+ * If we are called as part of repaint, we simply set the relevant bit in
3740+ * state and return.
3741+ */
3742 static void
3743 drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
3744 {
3745 struct drm_output *output = to_drm_output(output_base);
3746- struct weston_compositor *ec = output_base->compositor;
3747- struct drm_backend *b = to_drm_backend(ec);
3748+ struct drm_backend *b = to_drm_backend(output_base->compositor);
3749+ struct drm_pending_state *pending_state = b->repaint_data;
3750+ struct drm_output_state *state;
3751 int ret;
3752
3753- if (!output->dpms_prop)
3754+ if (output->state_cur->dpms == level)
3755 return;
3756
3757- ret = drmModeConnectorSetProperty(b->drm.fd, output->connector_id,
3758- output->dpms_prop->prop_id, level);
3759- if (ret) {
3760- weston_log("DRM: DPMS: failed property set for %s\n",
3761- output->base.name);
3762+ /* If we're being called during the repaint loop, then this is
3763+ * simple: discard any previously-generated state, and create a new
3764+ * state where we disable everything. When we come to flush, this
3765+ * will be applied.
3766+ *
3767+ * However, we need to be careful: we can be called whilst another
3768+ * output is in its repaint cycle (pending_state exists), but our
3769+ * output still has an incomplete state application outstanding.
3770+ * In that case, we need to wait until that completes. */
3771+ if (pending_state && !output->state_last) {
3772+ /* The repaint loop already sets DPMS on; we don't need to
3773+ * explicitly set it on here, as it will already happen
3774+ * whilst applying the repaint state. */
3775+ if (level == WESTON_DPMS_ON)
3776+ return;
3777+
3778+ state = drm_pending_state_get_output(pending_state, output);
3779+ if (state)
3780+ drm_output_state_free(state);
3781+ state = drm_output_get_disable_state(pending_state, output);
3782 return;
3783 }
3784
3785- output->dpms = level;
3786+ /* As we throw everything away when disabling, just send us back through
3787+ * a repaint cycle. */
3788+ if (level == WESTON_DPMS_ON) {
3789+ if (output->dpms_off_pending)
3790+ output->dpms_off_pending = 0;
3791+ weston_output_schedule_repaint(output_base);
3792+ return;
3793+ }
3794+
3795+ /* If we've already got a request in the pipeline, then we need to
3796+ * park our DPMS request until that request has quiesced. */
3797+ if (output->state_last) {
3798+ output->dpms_off_pending = 1;
3799+ return;
3800+ }
3801+
3802+ pending_state = drm_pending_state_alloc(b);
3803+ drm_output_get_disable_state(pending_state, output);
3804+ ret = drm_pending_state_apply_sync(pending_state);
3805+ if (ret != 0)
3806+ weston_log("drm_set_dpms: couldn't disable output?\n");
3807 }
3808
3809 static const char * const connector_type_names[] = {
3810@@ -1821,11 +3914,20 @@ static const char * const connector_type_names[] = {
3811 #endif
3812 };
3813
3814+/** Create a name given a DRM connector
3815+ *
3816+ * \param con The DRM connector whose type and id form the name.
3817+ * \return A newly allocate string, or NULL on error. Must be free()'d
3818+ * after use.
3819+ *
3820+ * The name does not identify the DRM display device.
3821+ */
3822 static char *
3823 make_connector_name(const drmModeConnector *con)
3824 {
3825- char name[32];
3826+ char *name;
3827 const char *type_name = NULL;
3828+ int ret;
3829
3830 if (con->connector_type < ARRAY_LENGTH(connector_type_names))
3831 type_name = connector_type_names[con->connector_type];
3832@@ -1833,9 +3935,11 @@ make_connector_name(const drmModeConnector *con)
3833 if (!type_name)
3834 type_name = "UNNAMED";
3835
3836- snprintf(name, sizeof name, "%s-%d", type_name, con->connector_type_id);
3837+ ret = asprintf(&name, "%s-%d", type_name, con->connector_type_id);
3838+ if (ret < 0)
3839+ return NULL;
3840
3841- return strdup(name);
3842+ return name;
3843 }
3844
3845 static int
3846@@ -1843,16 +3947,20 @@ find_crtc_for_connector(struct drm_backend *b,
3847 drmModeRes *resources, drmModeConnector *connector)
3848 {
3849 drmModeEncoder *encoder;
3850- uint32_t possible_crtcs;
3851 int i, j;
3852+ int ret = -1;
3853
3854 for (j = 0; j < connector->count_encoders; j++) {
3855+ uint32_t possible_crtcs, encoder_id, crtc_id;
3856+
3857 encoder = drmModeGetEncoder(b->drm.fd, connector->encoders[j]);
3858 if (encoder == NULL) {
3859 weston_log("Failed to get encoder.\n");
3860- return -1;
3861+ continue;
3862 }
3863+ encoder_id = encoder->encoder_id;
3864 possible_crtcs = encoder->possible_crtcs;
3865+ crtc_id = encoder->crtc_id;
3866 drmModeFreeEncoder(encoder);
3867
3868 for (i = 0; i < resources->count_crtcs; i++) {
3869@@ -1862,10 +3970,66 @@ find_crtc_for_connector(struct drm_backend *b,
3870 if (drm_output_find_by_crtc(b, resources->crtcs[i]))
3871 continue;
3872
3873- return i;
3874+ /* Try to preserve the existing
3875+ * CRTC -> encoder -> connector routing; it makes
3876+ * initialisation faster, and also since we have a
3877+ * very dumb picking algorithm, may preserve a better
3878+ * choice. */
3879+ if (!connector->encoder_id ||
3880+ (encoder_id == connector->encoder_id &&
3881+ crtc_id == resources->crtcs[i]))
3882+ return i;
3883+
3884+ ret = i;
3885+ }
3886+ }
3887+
3888+ return ret;
3889+}
3890+
3891+static void drm_output_fini_cursor_egl(struct drm_output *output)
3892+{
3893+ unsigned int i;
3894+
3895+ for (i = 0; i < ARRAY_LENGTH(output->gbm_cursor_fb); i++) {
3896+ drm_fb_unref(output->gbm_cursor_fb[i]);
3897+ output->gbm_cursor_fb[i] = NULL;
3898+ }
3899+}
3900+
3901+static int
3902+drm_output_init_cursor_egl(struct drm_output *output, struct drm_backend *b)
3903+{
3904+ unsigned int i;
3905+
3906+ /* No point creating cursors if we don't have a plane for them. */
3907+ if (!output->cursor_plane)
3908+ return 0;
3909+
3910+ for (i = 0; i < ARRAY_LENGTH(output->gbm_cursor_fb); i++) {
3911+ struct gbm_bo *bo;
3912+
3913+ bo = gbm_bo_create(b->gbm, b->cursor_width, b->cursor_height,
3914+ GBM_FORMAT_ARGB8888,
3915+ GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE);
3916+ if (!bo)
3917+ goto err;
3918+
3919+ output->gbm_cursor_fb[i] =
3920+ drm_fb_get_from_bo(bo, b, GBM_FORMAT_ARGB8888,
3921+ BUFFER_CURSOR);
3922+ if (!output->gbm_cursor_fb[i]) {
3923+ gbm_bo_destroy(bo);
3924+ goto err;
3925 }
3926 }
3927
3928+ return 0;
3929+
3930+err:
3931+ weston_log("cursor buffers unavailable, using gl cursors\n");
3932+ b->cursors_are_broken = 1;
3933+ drm_output_fini_cursor_egl(output);
3934 return -1;
3935 }
3936
3937@@ -1877,7 +4041,7 @@ drm_output_init_egl(struct drm_output *output, struct drm_backend *b)
3938 output->gbm_format,
3939 fallback_format_for(output->gbm_format),
3940 };
3941- int i, flags, n_formats = 1;
3942+ int n_formats = 1;
3943
3944 output->gbm_surface = gbm_surface_create(b->gbm,
3945 output->base.current_mode->width,
3946@@ -1903,21 +4067,7 @@ drm_output_init_egl(struct drm_output *output, struct drm_backend *b)
3947 return -1;
3948 }
3949
3950- flags = GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE;
3951-
3952- for (i = 0; i < 2; i++) {
3953- if (output->gbm_cursor_bo[i])
3954- continue;
3955-
3956- output->gbm_cursor_bo[i] =
3957- gbm_bo_create(b->gbm, b->cursor_width, b->cursor_height,
3958- GBM_FORMAT_ARGB8888, flags);
3959- }
3960-
3961- if (output->gbm_cursor_bo[0] == NULL || output->gbm_cursor_bo[1] == NULL) {
3962- weston_log("cursor buffers unavailable, using gl cursors\n");
3963- b->cursors_are_broken = 1;
3964- }
3965+ drm_output_init_cursor_egl(output, b);
3966
3967 return 0;
3968 }
3969@@ -1925,8 +4075,22 @@ drm_output_init_egl(struct drm_output *output, struct drm_backend *b)
3970 static void
3971 drm_output_fini_egl(struct drm_output *output)
3972 {
3973+ struct drm_backend *b = to_drm_backend(output->base.compositor);
3974+
3975+ /* Destroying the GBM surface will destroy all our GBM buffers,
3976+ * regardless of refcount. Ensure we destroy them here. */
3977+ if (!b->shutting_down &&
3978+ output->scanout_plane->state_cur->fb &&
3979+ output->scanout_plane->state_cur->fb->type == BUFFER_GBM_SURFACE) {
3980+ drm_plane_state_free(output->scanout_plane->state_cur, true);
3981+ output->scanout_plane->state_cur =
3982+ drm_plane_state_alloc(NULL, output->scanout_plane);
3983+ output->scanout_plane->state_cur->complete = true;
3984+ }
3985+
3986 gl_renderer->output_destroy(&output->base);
3987 gbm_surface_destroy(output->gbm_surface);
3988+ drm_output_fini_cursor_egl(output);
3989 }
3990
3991 static int
3992@@ -1975,7 +4139,7 @@ drm_output_init_pixman(struct drm_output *output, struct drm_backend *b)
3993 err:
3994 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
3995 if (output->dumb[i])
3996- drm_fb_destroy_dumb(output->dumb[i]);
3997+ drm_fb_unref(output->dumb[i]);
3998 if (output->image[i])
3999 pixman_image_unref(output->image[i]);
4000
4001@@ -1989,14 +4153,26 @@ err:
4002 static void
4003 drm_output_fini_pixman(struct drm_output *output)
4004 {
4005+ struct drm_backend *b = to_drm_backend(output->base.compositor);
4006 unsigned int i;
4007
4008+ /* Destroying the Pixman surface will destroy all our buffers,
4009+ * regardless of refcount. Ensure we destroy them here. */
4010+ if (!b->shutting_down &&
4011+ output->scanout_plane->state_cur->fb &&
4012+ output->scanout_plane->state_cur->fb->type == BUFFER_PIXMAN_DUMB) {
4013+ drm_plane_state_free(output->scanout_plane->state_cur, true);
4014+ output->scanout_plane->state_cur =
4015+ drm_plane_state_alloc(NULL, output->scanout_plane);
4016+ output->scanout_plane->state_cur->complete = true;
4017+ }
4018+
4019 pixman_renderer_output_destroy(&output->base);
4020 pixman_region32_fini(&output->previous_damage);
4021
4022 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
4023- drm_fb_destroy_dumb(output->dumb[i]);
4024 pixman_image_unref(output->image[i]);
4025+ drm_fb_unref(output->dumb[i]);
4026 output->dumb[i] = NULL;
4027 output->image[i] = NULL;
4028 }
4029@@ -2100,27 +4276,38 @@ edid_parse(struct drm_edid *edid, const uint8_t *data, size_t length)
4030 return 0;
4031 }
4032
4033+/** Parse monitor make, model and serial from EDID
4034+ *
4035+ * \param b The backend instance.
4036+ * \param output The output whose \c drm_edid to fill in.
4037+ * \param props The DRM connector properties to get the EDID from.
4038+ * \param make[out] The monitor make (PNP ID).
4039+ * \param model[out] The monitor model (name).
4040+ * \param serial_number[out] The monitor serial number.
4041+ *
4042+ * Each of \c *make, \c *model and \c *serial_number are set only if the
4043+ * information is found in the EDID. The pointers they are set to must not
4044+ * be free()'d explicitly, instead they get implicitly freed when the
4045+ * \c drm_output is destroyed.
4046+ */
4047 static void
4048-find_and_parse_output_edid(struct drm_backend *b,
4049- struct drm_output *output,
4050- drmModeConnector *connector)
4051+find_and_parse_output_edid(struct drm_backend *b, struct drm_output *output,
4052+ drmModeObjectPropertiesPtr props,
4053+ const char **make,
4054+ const char **model,
4055+ const char **serial_number)
4056 {
4057 drmModePropertyBlobPtr edid_blob = NULL;
4058- drmModePropertyPtr property;
4059- int i;
4060+ uint32_t blob_id;
4061 int rc;
4062
4063- for (i = 0; i < connector->count_props && !edid_blob; i++) {
4064- property = drmModeGetProperty(b->drm.fd, connector->props[i]);
4065- if (!property)
4066- continue;
4067- if ((property->flags & DRM_MODE_PROP_BLOB) &&
4068- !strcmp(property->name, "EDID")) {
4069- edid_blob = drmModeGetPropertyBlob(b->drm.fd,
4070- connector->prop_values[i]);
4071- }
4072- drmModeFreeProperty(property);
4073- }
4074+ blob_id =
4075+ drm_property_get_value(&output->props_conn[WDRM_CONNECTOR_EDID],
4076+ props, 0);
4077+ if (!blob_id)
4078+ return;
4079+
4080+ edid_blob = drmModeGetPropertyBlob(b->drm.fd, blob_id);
4081 if (!edid_blob)
4082 return;
4083
4084@@ -2133,17 +4320,15 @@ find_and_parse_output_edid(struct drm_backend *b,
4085 output->edid.monitor_name,
4086 output->edid.serial_number);
4087 if (output->edid.pnp_id[0] != '\0')
4088- output->base.make = output->edid.pnp_id;
4089+ *make = output->edid.pnp_id;
4090 if (output->edid.monitor_name[0] != '\0')
4091- output->base.model = output->edid.monitor_name;
4092+ *model = output->edid.monitor_name;
4093 if (output->edid.serial_number[0] != '\0')
4094- output->base.serial_number = output->edid.serial_number;
4095+ *serial_number = output->edid.serial_number;
4096 }
4097 drmModeFreePropertyBlob(edid_blob);
4098 }
4099
4100-
4101-
4102 static int
4103 parse_modeline(const char *s, drmModeModeInfo *mode)
4104 {
4105@@ -2151,6 +4336,8 @@ parse_modeline(const char *s, drmModeModeInfo *mode)
4106 char vsync[16];
4107 float fclock;
4108
4109+ memset(mode, 0, sizeof *mode);
4110+
4111 mode->type = DRM_MODE_TYPE_USERDEF;
4112 mode->hskew = 0;
4113 mode->vscan = 0;
4114@@ -2355,29 +4542,15 @@ drm_output_set_mode(struct weston_output *base,
4115 struct drm_output *output = to_drm_output(base);
4116 struct drm_backend *b = to_drm_backend(base->compositor);
4117
4118- struct drm_mode *drm_mode, *next, *current;
4119- drmModeModeInfo crtc_mode;
4120- int i;
4121-
4122- output->base.make = "unknown";
4123- output->base.model = "unknown";
4124- output->base.serial_number = "unknown";
4125- wl_list_init(&output->base.mode_list);
4126-
4127- output->original_crtc = drmModeGetCrtc(b->drm.fd, output->crtc_id);
4128+ struct drm_mode *current;
4129+ drmModeModeInfo crtc_mode;
4130
4131 if (connector_get_current_mode(output->connector, b->drm.fd, &crtc_mode) < 0)
4132- goto err_free;
4133-
4134- for (i = 0; i < output->connector->count_modes; i++) {
4135- drm_mode = drm_output_add_mode(output, &output->connector->modes[i]);
4136- if (!drm_mode)
4137- goto err_free;
4138- }
4139+ return -1;
4140
4141 current = drm_output_choose_initial_mode(b, output, mode, modeline, &crtc_mode);
4142 if (!current)
4143- goto err_free;
4144+ return -1;
4145
4146 output->base.current_mode = &current->base;
4147 output->base.current_mode->flags |= WL_OUTPUT_MODE_CURRENT;
4148@@ -2386,22 +4559,7 @@ drm_output_set_mode(struct weston_output *base,
4149 output->base.native_mode = output->base.current_mode;
4150 output->base.native_scale = output->base.current_scale;
4151
4152- output->base.mm_width = output->connector->mmWidth;
4153- output->base.mm_height = output->connector->mmHeight;
4154-
4155 return 0;
4156-
4157-err_free:
4158- drmModeFreeCrtc(output->original_crtc);
4159- output->original_crtc = NULL;
4160-
4161- wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
4162- base.link) {
4163- wl_list_remove(&drm_mode->base.link);
4164- free(drm_mode);
4165- }
4166-
4167- return -1;
4168 }
4169
4170 static void
4171@@ -2413,6 +4571,12 @@ drm_output_set_gbm_format(struct weston_output *base,
4172
4173 if (parse_gbm_format(gbm_format, b->gbm_format, &output->gbm_format) == -1)
4174 output->gbm_format = b->gbm_format;
4175+
4176+ /* Without universal planes, we can't discover which formats are
4177+ * supported by the primary plane; we just hope that the GBM format
4178+ * works. */
4179+ if (!b->universal_planes)
4180+ output->scanout_plane->formats[0] = output->gbm_format;
4181 }
4182
4183 static void
4184@@ -2427,22 +4591,145 @@ drm_output_set_seat(struct weston_output *base,
4185 }
4186
4187 static int
4188+drm_output_init_gamma_size(struct drm_output *output)
4189+{
4190+ struct drm_backend *backend = to_drm_backend(output->base.compositor);
4191+ drmModeCrtc *crtc;
4192+
4193+ assert(output->base.compositor);
4194+ assert(output->crtc_id != 0);
4195+ crtc = drmModeGetCrtc(backend->drm.fd, output->crtc_id);
4196+ if (!crtc)
4197+ return -1;
4198+
4199+ output->base.gamma_size = crtc->gamma_size;
4200+
4201+ drmModeFreeCrtc(crtc);
4202+
4203+ return 0;
4204+}
4205+
4206+/** Allocate a CRTC for the output
4207+ *
4208+ * @param output The output with no allocated CRTC.
4209+ * @param resources DRM KMS resources.
4210+ * @param connector The DRM KMS connector data.
4211+ * @return 0 on success, -1 on failure.
4212+ *
4213+ * Finds a free CRTC that can drive the given connector, reserves the CRTC
4214+ * for the output, and loads the CRTC properties.
4215+ *
4216+ * Populates the cursor and scanout planes.
4217+ *
4218+ * On failure, the output remains without a CRTC.
4219+ */
4220+static int
4221+drm_output_init_crtc(struct drm_output *output,
4222+ drmModeRes *resources, drmModeConnector *connector)
4223+{
4224+ struct drm_backend *b = to_drm_backend(output->base.compositor);
4225+ drmModeObjectPropertiesPtr props;
4226+ int i;
4227+
4228+ assert(output->crtc_id == 0);
4229+
4230+ i = find_crtc_for_connector(b, resources, connector);
4231+ if (i < 0) {
4232+ weston_log("No usable crtc/encoder pair for connector.\n");
4233+ return -1;
4234+ }
4235+
4236+ output->crtc_id = resources->crtcs[i];
4237+ output->pipe = i;
4238+
4239+ props = drmModeObjectGetProperties(b->drm.fd, output->crtc_id,
4240+ DRM_MODE_OBJECT_CRTC);
4241+ if (!props) {
4242+ weston_log("failed to get CRTC properties\n");
4243+ goto err_crtc;
4244+ }
4245+ drm_property_info_populate(b, crtc_props, output->props_crtc,
4246+ WDRM_CRTC__COUNT, props);
4247+ drmModeFreeObjectProperties(props);
4248+
4249+ output->scanout_plane =
4250+ drm_output_find_special_plane(b, output,
4251+ WDRM_PLANE_TYPE_PRIMARY);
4252+ if (!output->scanout_plane) {
4253+ weston_log("Failed to find primary plane for output %s\n",
4254+ output->base.name);
4255+ goto err_crtc;
4256+ }
4257+
4258+ /* Failing to find a cursor plane is not fatal, as we'll fall back
4259+ * to software cursor. */
4260+ output->cursor_plane =
4261+ drm_output_find_special_plane(b, output,
4262+ WDRM_PLANE_TYPE_CURSOR);
4263+
4264+ return 0;
4265+
4266+err_crtc:
4267+ output->crtc_id = 0;
4268+ output->pipe = 0;
4269+
4270+ return -1;
4271+}
4272+
4273+/** Free the CRTC from the output
4274+ *
4275+ * @param output The output whose CRTC to deallocate.
4276+ *
4277+ * The CRTC reserved for the given output becomes free to use again.
4278+ */
4279+static void
4280+drm_output_fini_crtc(struct drm_output *output)
4281+{
4282+ struct drm_backend *b = to_drm_backend(output->base.compositor);
4283+
4284+ if (!b->universal_planes && !b->shutting_down) {
4285+ /* With universal planes, the 'special' planes are allocated at
4286+ * startup, freed at shutdown, and live on the plane list in
4287+ * between. We want the planes to continue to exist and be freed
4288+ * up for other outputs.
4289+ *
4290+ * Without universal planes, our special planes are
4291+ * pseudo-planes allocated at output creation, freed at output
4292+ * destruction, and not usable by other outputs.
4293+ *
4294+ * On the other hand, if the compositor is already shutting down,
4295+ * the plane has already been destroyed.
4296+ */
4297+ if (output->cursor_plane)
4298+ drm_plane_destroy(output->cursor_plane);
4299+ if (output->scanout_plane)
4300+ drm_plane_destroy(output->scanout_plane);
4301+ }
4302+
4303+ drm_property_info_free(output->props_crtc, WDRM_CRTC__COUNT);
4304+ output->crtc_id = 0;
4305+ output->cursor_plane = NULL;
4306+ output->scanout_plane = NULL;
4307+}
4308+
4309+static int
4310 drm_output_enable(struct weston_output *base)
4311 {
4312 struct drm_output *output = to_drm_output(base);
4313 struct drm_backend *b = to_drm_backend(base->compositor);
4314 struct weston_mode *m;
4315
4316- output->dpms_prop = drm_get_prop(b->drm.fd, output->connector, "DPMS");
4317+ if (b->pageflip_timeout)
4318+ drm_output_pageflip_timer_create(output);
4319
4320 if (b->use_pixman) {
4321 if (drm_output_init_pixman(output, b) < 0) {
4322 weston_log("Failed to init output pixman state\n");
4323- goto err_free;
4324+ goto err;
4325 }
4326 } else if (drm_output_init_egl(output, b) < 0) {
4327 weston_log("Failed to init output gl state\n");
4328- goto err_free;
4329+ goto err;
4330 }
4331
4332 if (output->backlight) {
4333@@ -2459,25 +4746,22 @@ drm_output_enable(struct weston_output *base)
4334 output->base.assign_planes = drm_assign_planes;
4335 output->base.set_dpms = drm_set_dpms;
4336 output->base.switch_mode = drm_output_switch_mode;
4337-
4338- output->base.gamma_size = output->original_crtc->gamma_size;
4339 output->base.set_gamma = drm_output_set_gamma;
4340
4341- output->base.subpixel = drm_subpixel_to_wayland(output->connector->subpixel);
4342-
4343- find_and_parse_output_edid(b, output, output->connector);
4344- if (output->connector->connector_type == DRM_MODE_CONNECTOR_LVDS ||
4345- output->connector->connector_type == DRM_MODE_CONNECTOR_eDP)
4346- output->base.connection_internal = 1;
4347-
4348- weston_plane_init(&output->cursor_plane, b->compositor,
4349- INT32_MIN, INT32_MIN);
4350- weston_plane_init(&output->fb_plane, b->compositor, 0, 0);
4351+ if (output->cursor_plane)
4352+ weston_compositor_stack_plane(b->compositor,
4353+ &output->cursor_plane->base,
4354+ NULL);
4355+ else
4356+ b->cursors_are_broken = 1;
4357
4358- weston_compositor_stack_plane(b->compositor, &output->cursor_plane, NULL);
4359- weston_compositor_stack_plane(b->compositor, &output->fb_plane,
4360+ weston_compositor_stack_plane(b->compositor,
4361+ &output->scanout_plane->base,
4362 &b->compositor->primary_plane);
4363
4364+ wl_array_remove_uint32(&b->unused_connectors, output->connector_id);
4365+ wl_array_remove_uint32(&b->unused_crtcs, output->crtc_id);
4366+
4367 weston_log("Output %s, (connector %d, crtc %d)\n",
4368 output->base.name, output->connector_id, output->crtc_id);
4369 wl_list_for_each(m, &output->base.mode_list, link)
4370@@ -2492,9 +4776,7 @@ drm_output_enable(struct weston_output *base)
4371
4372 return 0;
4373
4374-err_free:
4375- drmModeFreeProperty(output->dpms_prop);
4376-
4377+err:
4378 return -1;
4379 }
4380
4381@@ -2503,19 +4785,36 @@ drm_output_deinit(struct weston_output *base)
4382 {
4383 struct drm_output *output = to_drm_output(base);
4384 struct drm_backend *b = to_drm_backend(base->compositor);
4385+ uint32_t *unused;
4386
4387 if (b->use_pixman)
4388 drm_output_fini_pixman(output);
4389 else
4390 drm_output_fini_egl(output);
4391
4392- weston_plane_release(&output->fb_plane);
4393- weston_plane_release(&output->cursor_plane);
4394+ /* Since our planes are no longer in use anywhere, remove their base
4395+ * weston_plane's link from the plane stacking list, unless we're
4396+ * shutting down, in which case the plane has already been
4397+ * destroyed. */
4398+ if (!b->shutting_down) {
4399+ wl_list_remove(&output->scanout_plane->base.link);
4400+ wl_list_init(&output->scanout_plane->base.link);
4401+
4402+ if (output->cursor_plane) {
4403+ wl_list_remove(&output->cursor_plane->base.link);
4404+ wl_list_init(&output->cursor_plane->base.link);
4405+ /* Turn off hardware cursor */
4406+ drmModeSetCursor(b->drm.fd, output->crtc_id, 0, 0, 0);
4407+ }
4408+ }
4409
4410- drmModeFreeProperty(output->dpms_prop);
4411+ unused = wl_array_add(&b->unused_connectors, sizeof(*unused));
4412+ *unused = output->connector_id;
4413+ unused = wl_array_add(&b->unused_crtcs, sizeof(*unused));
4414+ *unused = output->crtc_id;
4415
4416- /* Turn off hardware cursor */
4417- drmModeSetCursor(b->drm.fd, output->crtc_id, 0, 0, 0);
4418+ /* Force programming unused connectors and crtcs. */
4419+ b->state_invalid = true;
4420 }
4421
4422 static void
4423@@ -2523,9 +4822,9 @@ drm_output_destroy(struct weston_output *base)
4424 {
4425 struct drm_output *output = to_drm_output(base);
4426 struct drm_backend *b = to_drm_backend(base->compositor);
4427- drmModeCrtcPtr origcrtc = output->original_crtc;
4428
4429- if (output->page_flip_pending) {
4430+ if (output->page_flip_pending || output->vblank_pending ||
4431+ output->atomic_complete_pending) {
4432 output->destroy_pending = 1;
4433 weston_log("destroy output while page flip pending\n");
4434 return;
4435@@ -2534,21 +4833,24 @@ drm_output_destroy(struct weston_output *base)
4436 if (output->base.enabled)
4437 drm_output_deinit(&output->base);
4438
4439- if (origcrtc) {
4440- /* Restore original CRTC state */
4441- drmModeSetCrtc(b->drm.fd, origcrtc->crtc_id, origcrtc->buffer_id,
4442- origcrtc->x, origcrtc->y,
4443- &output->connector_id, 1, &origcrtc->mode);
4444- drmModeFreeCrtc(origcrtc);
4445- }
4446+ drm_mode_list_destroy(b, &output->base.mode_list);
4447+
4448+ if (output->pageflip_timer)
4449+ wl_event_source_remove(output->pageflip_timer);
4450
4451 weston_output_destroy(&output->base);
4452
4453+ drm_output_fini_crtc(output);
4454+
4455+ drm_property_info_free(output->props_conn, WDRM_CONNECTOR__COUNT);
4456 drmModeFreeConnector(output->connector);
4457
4458 if (output->backlight)
4459 backlight_destroy(output->backlight);
4460
4461+ assert(!output->state_last);
4462+ drm_output_state_free(output->state_cur);
4463+
4464 free(output);
4465 }
4466
4467@@ -2556,26 +4858,69 @@ static int
4468 drm_output_disable(struct weston_output *base)
4469 {
4470 struct drm_output *output = to_drm_output(base);
4471- struct drm_backend *b = to_drm_backend(base->compositor);
4472
4473- if (output->page_flip_pending) {
4474+ if (output->page_flip_pending || output->vblank_pending ||
4475+ output->atomic_complete_pending) {
4476 output->disable_pending = 1;
4477 return -1;
4478 }
4479
4480+ weston_log("Disabling output %s\n", output->base.name);
4481+
4482 if (output->base.enabled)
4483 drm_output_deinit(&output->base);
4484
4485 output->disable_pending = 0;
4486
4487- weston_log("Disabling output %s\n", output->base.name);
4488- drmModeSetCrtc(b->drm.fd, output->crtc_id,
4489- 0, 0, 0, 0, 0, NULL);
4490-
4491 return 0;
4492 }
4493
4494 /**
4495+ * Update the list of unused connectors and CRTCs
4496+ *
4497+ * This keeps the unused_connectors and unused_crtcs arrays up to date.
4498+ *
4499+ * @param b Weston backend structure
4500+ * @param resources DRM resources for this device
4501+ */
4502+static void
4503+drm_backend_update_unused_outputs(struct drm_backend *b, drmModeRes *resources)
4504+{
4505+ int i;
4506+
4507+ wl_array_release(&b->unused_connectors);
4508+ wl_array_init(&b->unused_connectors);
4509+
4510+ for (i = 0; i < resources->count_connectors; i++) {
4511+ struct drm_output *output;
4512+ uint32_t *connector_id;
4513+
4514+ output = drm_output_find_by_connector(b, resources->connectors[i]);
4515+ if (output && output->base.enabled)
4516+ continue;
4517+
4518+ connector_id = wl_array_add(&b->unused_connectors,
4519+ sizeof(*connector_id));
4520+ *connector_id = resources->connectors[i];
4521+ }
4522+
4523+ wl_array_release(&b->unused_crtcs);
4524+ wl_array_init(&b->unused_crtcs);
4525+
4526+ for (i = 0; i < resources->count_crtcs; i++) {
4527+ struct drm_output *output;
4528+ uint32_t *crtc_id;
4529+
4530+ output = drm_output_find_by_crtc(b, resources->crtcs[i]);
4531+ if (output && output->base.enabled)
4532+ continue;
4533+
4534+ crtc_id = wl_array_add(&b->unused_crtcs, sizeof(*crtc_id));
4535+ *crtc_id = resources->crtcs[i];
4536+ }
4537+}
4538+
4539+/**
4540 * Create a Weston output structure
4541 *
4542 * Given a DRM connector, create a matching drm_output structure and add it
4543@@ -2595,108 +4940,87 @@ create_output_for_connector(struct drm_backend *b,
4544 struct udev_device *drm_device)
4545 {
4546 struct drm_output *output;
4547+ drmModeObjectPropertiesPtr props;
4548+ struct drm_mode *drm_mode;
4549+ char *name;
4550+ const char *make = "unknown";
4551+ const char *model = "unknown";
4552+ const char *serial_number = "unknown";
4553 int i;
4554
4555- i = find_crtc_for_connector(b, resources, connector);
4556- if (i < 0) {
4557- weston_log("No usable crtc/encoder pair for connector.\n");
4558- return -1;
4559- }
4560-
4561 output = zalloc(sizeof *output);
4562 if (output == NULL)
4563- return -1;
4564+ goto err_init;
4565
4566 output->connector = connector;
4567- output->crtc_id = resources->crtcs[i];
4568- output->pipe = i;
4569 output->connector_id = connector->connector_id;
4570
4571 output->backlight = backlight_init(drm_device,
4572 connector->connector_type);
4573
4574+ output->base.name = make_connector_name(connector);
4575+ weston_output_init(&output->base, b->compositor);
4576+ wl_list_init(&output->base.mode_list);
4577+
4578 output->base.enable = drm_output_enable;
4579 output->base.destroy = drm_output_destroy;
4580 output->base.disable = drm_output_disable;
4581- output->base.name = make_connector_name(connector);
4582
4583 output->destroy_pending = 0;
4584 output->disable_pending = 0;
4585- output->original_crtc = NULL;
4586
4587- weston_output_init(&output->base, b->compositor);
4588- weston_compositor_add_pending_output(&output->base, b->compositor);
4589+ if (drm_output_init_crtc(output, resources, connector) < 0)
4590+ goto err_output;
4591
4592- return 0;
4593-}
4594+ props = drmModeObjectGetProperties(b->drm.fd, connector->connector_id,
4595+ DRM_MODE_OBJECT_CONNECTOR);
4596+ if (!props) {
4597+ weston_log("failed to get connector properties\n");
4598+ goto err_output;
4599+ }
4600+ drm_property_info_populate(b, connector_props, output->props_conn,
4601+ WDRM_CONNECTOR__COUNT, props);
4602+ find_and_parse_output_edid(b, output, props,
4603+ &make, &model, &serial_number);
4604+ output->base.make = (char *)make;
4605+ output->base.model = (char *)model;
4606+ output->base.serial_number = (char *)serial_number;
4607+ output->base.subpixel = drm_subpixel_to_wayland(output->connector->subpixel);
4608
4609-static void
4610-create_sprites(struct drm_backend *b)
4611-{
4612- struct drm_sprite *sprite;
4613- drmModePlaneRes *plane_res;
4614- drmModePlane *plane;
4615- uint32_t i;
4616+ drmModeFreeObjectProperties(props);
4617
4618- plane_res = drmModeGetPlaneResources(b->drm.fd);
4619- if (!plane_res) {
4620- weston_log("failed to get plane resources: %s\n",
4621- strerror(errno));
4622- return;
4623- }
4624+ if (output->connector->connector_type == DRM_MODE_CONNECTOR_LVDS ||
4625+ output->connector->connector_type == DRM_MODE_CONNECTOR_eDP)
4626+ output->base.connection_internal = true;
4627
4628- for (i = 0; i < plane_res->count_planes; i++) {
4629- plane = drmModeGetPlane(b->drm.fd, plane_res->planes[i]);
4630- if (!plane)
4631- continue;
4632+ if (drm_output_init_gamma_size(output) < 0)
4633+ goto err_output;
4634
4635- sprite = zalloc(sizeof(*sprite) + ((sizeof(uint32_t)) *
4636- plane->count_formats));
4637- if (!sprite) {
4638- weston_log("%s: out of memory\n",
4639- __func__);
4640- drmModeFreePlane(plane);
4641- continue;
4642- }
4643+ output->state_cur = drm_output_state_alloc(output, NULL);
4644
4645- sprite->possible_crtcs = plane->possible_crtcs;
4646- sprite->plane_id = plane->plane_id;
4647- sprite->current = NULL;
4648- sprite->next = NULL;
4649- sprite->backend = b;
4650- sprite->count_formats = plane->count_formats;
4651- memcpy(sprite->formats, plane->formats,
4652- plane->count_formats * sizeof(plane->formats[0]));
4653- drmModeFreePlane(plane);
4654- weston_plane_init(&sprite->plane, b->compositor, 0, 0);
4655- weston_compositor_stack_plane(b->compositor, &sprite->plane,
4656- &b->compositor->primary_plane);
4657+ output->base.mm_width = output->connector->mmWidth;
4658+ output->base.mm_height = output->connector->mmHeight;
4659
4660- wl_list_insert(&b->sprite_list, &sprite->link);
4661+ for (i = 0; i < output->connector->count_modes; i++) {
4662+ drm_mode = drm_output_add_mode(output, &output->connector->modes[i]);
4663+ if (!drm_mode) {
4664+ weston_log("failed to add mode\n");
4665+ goto err_output;
4666+ }
4667 }
4668
4669- drmModeFreePlaneResources(plane_res);
4670-}
4671+ weston_compositor_add_pending_output(&output->base, b->compositor);
4672
4673-static void
4674-destroy_sprites(struct drm_backend *backend)
4675-{
4676- struct drm_sprite *sprite, *next;
4677- struct drm_output *output;
4678+ return 0;
4679
4680- output = container_of(backend->compositor->output_list.next,
4681- struct drm_output, base.link);
4682+err_output:
4683+ drm_output_destroy(&output->base);
4684+ return -1;
4685+ /* no fallthrough! */
4686
4687- wl_list_for_each_safe(sprite, next, &backend->sprite_list, link) {
4688- drmModeSetPlane(backend->drm.fd,
4689- sprite->plane_id,
4690- output->crtc_id, 0, 0,
4691- 0, 0, 0, 0, 0, 0, 0, 0);
4692- drm_output_release_fb(output, sprite->current);
4693- drm_output_release_fb(output, sprite->next);
4694- weston_plane_release(&sprite->plane);
4695- free(sprite);
4696- }
4697+err_init:
4698+ drmModeFreeConnector(connector);
4699+ return -1;
4700 }
4701
4702 static int
4703@@ -2718,24 +5042,25 @@ create_outputs(struct drm_backend *b, struct udev_device *drm_device)
4704 b->max_height = resources->max_height;
4705
4706 for (i = 0; i < resources->count_connectors; i++) {
4707+ int ret;
4708+
4709 connector = drmModeGetConnector(b->drm.fd,
4710 resources->connectors[i]);
4711 if (connector == NULL)
4712 continue;
4713
4714- if (connector->connection == DRM_MODE_CONNECTED &&
4715- (b->connector == 0 ||
4716- connector->connector_id == b->connector)) {
4717- if (create_output_for_connector(b, resources,
4718- connector, drm_device) < 0) {
4719- drmModeFreeConnector(connector);
4720- continue;
4721- }
4722+ if (connector->connection == DRM_MODE_CONNECTED) {
4723+ ret = create_output_for_connector(b, resources,
4724+ connector, drm_device);
4725+ if (ret < 0)
4726+ weston_log("failed to create new connector\n");
4727 } else {
4728 drmModeFreeConnector(connector);
4729 }
4730 }
4731
4732+ drm_backend_update_unused_outputs(b, resources);
4733+
4734 if (wl_list_empty(&b->compositor->output_list) &&
4735 wl_list_empty(&b->compositor->pending_output_list))
4736 weston_log("No currently active connector found.\n");
4737@@ -2779,11 +5104,6 @@ update_outputs(struct drm_backend *b, struct udev_device *drm_device)
4738 continue;
4739 }
4740
4741- if (b->connector && (b->connector != connector_id)) {
4742- drmModeFreeConnector(connector);
4743- continue;
4744- }
4745-
4746 connected[i] = connector_id;
4747
4748 if (drm_output_find_by_connector(b, connector_id)) {
4749@@ -2832,6 +5152,8 @@ update_outputs(struct drm_backend *b, struct udev_device *drm_device)
4750 drm_output_destroy(&output->base);
4751 }
4752
4753+ drm_backend_update_unused_outputs(b, resources);
4754+
4755 free(connected);
4756 drmModeFreeResources(resources);
4757 }
4758@@ -2885,6 +5207,8 @@ drm_destroy(struct weston_compositor *ec)
4759 wl_event_source_remove(b->udev_drm_source);
4760 wl_event_source_remove(b->drm_source);
4761
4762+ b->shutting_down = true;
4763+
4764 destroy_sprites(b);
4765
4766 weston_compositor_shutdown(ec);
4767@@ -2892,9 +5216,16 @@ drm_destroy(struct weston_compositor *ec)
4768 if (b->gbm)
4769 gbm_device_destroy(b->gbm);
4770
4771+ udev_monitor_unref(b->udev_monitor);
4772+ udev_unref(b->udev);
4773+
4774 weston_launcher_destroy(ec->launcher);
4775
4776+ wl_array_release(&b->unused_crtcs);
4777+ wl_array_release(&b->unused_connectors);
4778+
4779 close(b->drm.fd);
4780+ free(b->drm.filename);
4781 free(b);
4782 }
4783
4784@@ -2903,13 +5234,14 @@ session_notify(struct wl_listener *listener, void *data)
4785 {
4786 struct weston_compositor *compositor = data;
4787 struct drm_backend *b = to_drm_backend(compositor);
4788- struct drm_sprite *sprite;
4789+ struct drm_plane *plane;
4790 struct drm_output *output;
4791
4792 if (compositor->session_active) {
4793 weston_log("activating session\n");
4794 weston_compositor_wake(compositor);
4795 weston_compositor_damage_all(compositor);
4796+ b->state_invalid = true;
4797 udev_input_enable(&b->input);
4798 } else {
4799 weston_log("deactivating session\n");
4800@@ -2926,19 +5258,80 @@ session_notify(struct wl_listener *listener, void *data)
4801 * pending frame callbacks. */
4802
4803 wl_list_for_each(output, &compositor->output_list, base.link) {
4804- output->base.repaint_needed = 0;
4805- drmModeSetCursor(b->drm.fd, output->crtc_id, 0, 0, 0);
4806+ output->base.repaint_needed = false;
4807+ if (output->cursor_plane)
4808+ drmModeSetCursor(b->drm.fd, output->crtc_id,
4809+ 0, 0, 0);
4810 }
4811
4812 output = container_of(compositor->output_list.next,
4813 struct drm_output, base.link);
4814
4815- wl_list_for_each(sprite, &b->sprite_list, link)
4816+ wl_list_for_each(plane, &b->plane_list, link) {
4817+ if (plane->type != WDRM_PLANE_TYPE_OVERLAY)
4818+ continue;
4819+
4820 drmModeSetPlane(b->drm.fd,
4821- sprite->plane_id,
4822+ plane->plane_id,
4823 output->crtc_id, 0, 0,
4824 0, 0, 0, 0, 0, 0, 0, 0);
4825- };
4826+ }
4827+ }
4828+}
4829+
4830+/**
4831+ * Determines whether or not a device is capable of modesetting. If successful,
4832+ * sets b->drm.fd and b->drm.filename to the opened device.
4833+ */
4834+static bool
4835+drm_device_is_kms(struct drm_backend *b, struct udev_device *device)
4836+{
4837+ const char *filename = udev_device_get_devnode(device);
4838+ const char *sysnum = udev_device_get_sysnum(device);
4839+ drmModeRes *res;
4840+ int id, fd;
4841+
4842+ if (!filename)
4843+ return false;
4844+
4845+ fd = weston_launcher_open(b->compositor->launcher, filename, O_RDWR);
4846+ if (fd < 0)
4847+ return false;
4848+
4849+ res = drmModeGetResources(fd);
4850+ if (!res)
4851+ goto out_fd;
4852+
4853+ if (res->count_crtcs <= 0 || res->count_connectors <= 0 ||
4854+ res->count_encoders <= 0)
4855+ goto out_res;
4856+
4857+ if (sysnum)
4858+ id = atoi(sysnum);
4859+ if (!sysnum || id < 0) {
4860+ weston_log("couldn't get sysnum for device %s\n", filename);
4861+ goto out_res;
4862+ }
4863+
4864+ /* We can be called successfully on multiple devices; if we have,
4865+ * clean up old entries. */
4866+ if (b->drm.fd >= 0)
4867+ weston_launcher_close(b->compositor->launcher, b->drm.fd);
4868+ free(b->drm.filename);
4869+
4870+ b->drm.fd = fd;
4871+ b->drm.id = id;
4872+ b->drm.filename = strdup(filename);
4873+
4874+ drmModeFreeResources(res);
4875+
4876+ return true;
4877+
4878+out_res:
4879+ drmModeFreeResources(res);
4880+out_fd:
4881+ weston_launcher_close(b->compositor->launcher, fd);
4882+ return false;
4883 }
4884
4885 /*
4886@@ -2947,6 +5340,9 @@ session_notify(struct wl_listener *listener, void *data)
4887 * function loops over all devices and tries to find a PCI device with the
4888 * boot_vga sysfs attribute set to 1.
4889 * If no such device is found, the first DRM device reported by udev is used.
4890+ * Devices are also vetted to make sure they are are capable of modesetting,
4891+ * rather than pure render nodes (GPU with no display), or pure
4892+ * memory-allocation devices (VGEM).
4893 */
4894 static struct udev_device*
4895 find_primary_gpu(struct drm_backend *b, const char *seat)
4896@@ -2963,6 +5359,8 @@ find_primary_gpu(struct drm_backend *b, const char *seat)
4897 udev_enumerate_scan_devices(e);
4898 drm_device = NULL;
4899 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
4900+ bool is_boot_vga = false;
4901+
4902 path = udev_list_entry_get_name(entry);
4903 device = udev_device_new_from_syspath(b->udev, path);
4904 if (!device)
4905@@ -2979,27 +5377,77 @@ find_primary_gpu(struct drm_backend *b, const char *seat)
4906 "pci", NULL);
4907 if (pci) {
4908 id = udev_device_get_sysattr_value(pci, "boot_vga");
4909- if (id && !strcmp(id, "1")) {
4910- if (drm_device)
4911- udev_device_unref(drm_device);
4912- drm_device = device;
4913- break;
4914- }
4915+ if (id && !strcmp(id, "1"))
4916+ is_boot_vga = true;
4917 }
4918
4919- if (!drm_device)
4920- drm_device = device;
4921- else
4922+ /* If we already have a modesetting-capable device, and this
4923+ * device isn't our boot-VGA device, we aren't going to use
4924+ * it. */
4925+ if (!is_boot_vga && drm_device) {
4926+ udev_device_unref(device);
4927+ continue;
4928+ }
4929+
4930+ /* Make sure this device is actually capable of modesetting;
4931+ * if this call succeeds, b->drm.{fd,filename} will be set,
4932+ * and any old values freed. */
4933+ if (!drm_device_is_kms(b, device)) {
4934 udev_device_unref(device);
4935+ continue;
4936+ }
4937+
4938+ /* There can only be one boot_vga device, and we try to use it
4939+ * at all costs. */
4940+ if (is_boot_vga) {
4941+ if (drm_device)
4942+ udev_device_unref(drm_device);
4943+ drm_device = device;
4944+ break;
4945+ }
4946+
4947+ /* Per the (!is_boot_vga && drm_device) test above, we only
4948+ * trump existing saved devices with boot-VGA devices, so if
4949+ * we end up here, this must be the first device we've seen. */
4950+ assert(!drm_device);
4951+ drm_device = device;
4952 }
4953
4954+ /* If we're returning a device to use, we must have an open FD for
4955+ * it. */
4956+ assert(!!drm_device == (b->drm.fd >= 0));
4957+
4958 udev_enumerate_unref(e);
4959 return drm_device;
4960 }
4961
4962+static struct udev_device *
4963+open_specific_drm_device(struct drm_backend *b, const char *name)
4964+{
4965+ struct udev_device *device;
4966+
4967+ device = udev_device_new_from_subsystem_sysname(b->udev, "drm", name);
4968+ if (!device) {
4969+ weston_log("ERROR: could not open DRM device '%s'\n", name);
4970+ return NULL;
4971+ }
4972+
4973+ if (!drm_device_is_kms(b, device)) {
4974+ udev_device_unref(device);
4975+ weston_log("ERROR: DRM device '%s' is not a KMS device.\n", name);
4976+ return NULL;
4977+ }
4978+
4979+ /* If we're returning a device to use, we must have an open FD for
4980+ * it. */
4981+ assert(b->drm.fd >= 0);
4982+
4983+ return device;
4984+}
4985+
4986 static void
4987-planes_binding(struct weston_keyboard *keyboard, uint32_t time, uint32_t key,
4988- void *data)
4989+planes_binding(struct weston_keyboard *keyboard, uint32_t time,
4990+ uint32_t key, void *data)
4991 {
4992 struct drm_backend *b = data;
4993
4994@@ -3045,7 +5493,8 @@ recorder_frame_notify(struct wl_listener *listener, void *data)
4995 if (!output->recorder)
4996 return;
4997
4998- ret = drmPrimeHandleToFD(b->drm.fd, output->current->handle,
4999+ ret = drmPrimeHandleToFD(b->drm.fd,
5000+ output->scanout_plane->state_cur->fb->handle,
5001 DRM_CLOEXEC, &fd);
5002 if (ret) {
5003 weston_log("[libva recorder] "
5004@@ -3054,7 +5503,7 @@ recorder_frame_notify(struct wl_listener *listener, void *data)
5005 }
5006
5007 ret = vaapi_recorder_frame(output->recorder, fd,
5008- output->current->stride);
5009+ output->scanout_plane->state_cur->fb->stride);
5010 if (ret < 0) {
5011 weston_log("[libva recorder] aborted: %m\n");
5012 recorder_destroy(output);
5013@@ -3079,8 +5528,8 @@ create_recorder(struct drm_backend *b, int width, int height,
5014 }
5015
5016 static void
5017-recorder_binding(struct weston_keyboard *keyboard, uint32_t time, uint32_t key,
5018- void *data)
5019+recorder_binding(struct weston_keyboard *keyboard, uint32_t time,
5020+ uint32_t key, void *data)
5021 {
5022 struct drm_backend *b = data;
5023 struct drm_output *output;
5024@@ -3121,8 +5570,8 @@ recorder_binding(struct weston_keyboard *keyboard, uint32_t time, uint32_t key,
5025 }
5026 #else
5027 static void
5028-recorder_binding(struct weston_keyboard *keyboard, uint32_t time, uint32_t key,
5029- void *data)
5030+recorder_binding(struct weston_keyboard *keyboard, uint32_t time,
5031+ uint32_t key, void *data)
5032 {
5033 weston_log("Compiled without libva support\n");
5034 }
5035@@ -3173,8 +5622,8 @@ switch_to_gl_renderer(struct drm_backend *b)
5036 }
5037
5038 static void
5039-renderer_switch_binding(struct weston_keyboard *keyboard, uint32_t time,
5040- uint32_t key, void *data)
5041+renderer_switch_binding(struct weston_keyboard *keyboard,
5042+ uint32_t time, uint32_t key, void *data)
5043 {
5044 struct drm_backend *b =
5045 to_drm_backend(keyboard->seat->compositor);
5046@@ -3195,7 +5644,6 @@ drm_backend_create(struct weston_compositor *compositor,
5047 struct drm_backend *b;
5048 struct udev_device *drm_device;
5049 struct wl_event_loop *loop;
5050- const char *path;
5051 const char *seat_id = default_seat;
5052 int ret;
5053
5054@@ -3205,6 +5653,11 @@ drm_backend_create(struct weston_compositor *compositor,
5055 if (b == NULL)
5056 return NULL;
5057
5058+ b->state_invalid = true;
5059+ b->drm.fd = -1;
5060+ wl_array_init(&b->unused_crtcs);
5061+ wl_array_init(&b->unused_connectors);
5062+
5063 /*
5064 * KMS support for hardware planes cannot properly synchronize
5065 * without nuclear page flip. Without nuclear/atomic, hw plane
5066@@ -3218,6 +5671,9 @@ drm_backend_create(struct weston_compositor *compositor,
5067 b->sprites_are_broken = 1;
5068 b->compositor = compositor;
5069 b->use_pixman = config->use_pixman;
5070+ b->pageflip_timeout = config->pageflip_timeout;
5071+
5072+ compositor->backend = &b->base;
5073
5074 if (parse_gbm_format(config->gbm_format, GBM_FORMAT_XRGB8888, &b->gbm_format) < 0)
5075 goto err_compositor;
5076@@ -3229,8 +5685,9 @@ drm_backend_create(struct weston_compositor *compositor,
5077 compositor->launcher = weston_launcher_connect(compositor, config->tty,
5078 seat_id, true);
5079 if (compositor->launcher == NULL) {
5080- weston_log("fatal: drm backend should be run "
5081- "using weston-launch binary or as root\n");
5082+ weston_log("fatal: drm backend should be run using "
5083+ "weston-launch binary, or your system should "
5084+ "provide the logind D-Bus API.\n");
5085 goto err_compositor;
5086 }
5087
5088@@ -3243,14 +5700,16 @@ drm_backend_create(struct weston_compositor *compositor,
5089 b->session_listener.notify = session_notify;
5090 wl_signal_add(&compositor->session_signal, &b->session_listener);
5091
5092- drm_device = find_primary_gpu(b, seat_id);
5093+ if (config->specific_device)
5094+ drm_device = open_specific_drm_device(b, config->specific_device);
5095+ else
5096+ drm_device = find_primary_gpu(b, seat_id);
5097 if (drm_device == NULL) {
5098 weston_log("no drm device found\n");
5099 goto err_udev;
5100 }
5101- path = udev_device_get_syspath(drm_device);
5102
5103- if (init_drm(b, drm_device) < 0) {
5104+ if (init_kms_caps(b) < 0) {
5105 weston_log("failed to initialize kms\n");
5106 goto err_udev_dev;
5107 }
5108@@ -3262,21 +5721,20 @@ drm_backend_create(struct weston_compositor *compositor,
5109 }
5110 } else {
5111 if (init_egl(b) < 0) {
5112- weston_log("failed to initialize egl, use pixman\n");
5113- if (init_pixman(b) < 0) {
5114- weston_log("failed to initialize pixman renderer\n");
5115- goto err_udev_dev;
5116- }
5117- b->use_pixman = 1;
5118+ weston_log("failed to initialize egl\n");
5119+ goto err_udev_dev;
5120 }
5121 }
5122
5123 b->base.destroy = drm_destroy;
5124 b->base.restore = drm_restore;
5125+ b->base.repaint_begin = drm_repaint_begin;
5126+ b->base.repaint_flush = drm_repaint_flush;
5127+ b->base.repaint_cancel = drm_repaint_cancel;
5128
5129 weston_setup_vt_switch_bindings(compositor);
5130
5131- wl_list_init(&b->sprite_list);
5132+ wl_list_init(&b->plane_list);
5133 create_sprites(b);
5134
5135 if (udev_input_init(&b->input,
5136@@ -3286,10 +5744,8 @@ drm_backend_create(struct weston_compositor *compositor,
5137 goto err_sprite;
5138 }
5139
5140- b->connector = config->connector;
5141-
5142 if (create_outputs(b, drm_device) < 0) {
5143- weston_log("failed to create output for %s\n", path);
5144+ weston_log("failed to create output for %s\n", b->drm.filename);
5145 goto err_udev_input;
5146 }
5147
5148@@ -3298,8 +5754,6 @@ drm_backend_create(struct weston_compositor *compositor,
5149 if (!b->cursors_are_broken)
5150 compositor->capabilities |= WESTON_CAP_CURSOR_PLANE;
5151
5152- path = NULL;
5153-
5154 loop = wl_display_get_event_loop(compositor->wl_display);
5155 b->drm_source =
5156 wl_event_loop_add_fd(loop, b->drm.fd,
5157@@ -3341,8 +5795,6 @@ drm_backend_create(struct weston_compositor *compositor,
5158 "support failed.\n");
5159 }
5160
5161- compositor->backend = &b->base;
5162-
5163 ret = weston_plugin_api_register(compositor, WESTON_DRM_OUTPUT_API_NAME,
5164 &api, sizeof(api));
5165
5166diff --git a/libweston/compositor-drm.h b/libweston/compositor-drm.h
5167index 2e2995a..838e937 100644
5168--- a/libweston/compositor-drm.h
5169+++ b/libweston/compositor-drm.h
5170@@ -35,7 +35,7 @@
5171 extern "C" {
5172 #endif
5173
5174-#define WESTON_DRM_BACKEND_CONFIG_VERSION 2
5175+#define WESTON_DRM_BACKEND_CONFIG_VERSION 3
5176
5177 struct libinput_device;
5178
5179@@ -138,6 +138,20 @@ struct weston_drm_backend_config {
5180 */
5181 void (*configure_device)(struct weston_compositor *compositor,
5182 struct libinput_device *device);
5183+
5184+ /** Maximum duration for a pageflip event to arrive, after which the
5185+ * compositor will consider the DRM driver crashed and will try to exit
5186+ * cleanly.
5187+ *
5188+ * It is exprimed in milliseconds, 0 means disabled. */
5189+ uint32_t pageflip_timeout;
5190+
5191+ /** Specific DRM device to open
5192+ *
5193+ * A DRM device name, like "card0", to open. If NULL, use heuristics
5194+ * based on seat names and boot_vga to find the right device.
5195+ */
5196+ char *specific_device;
5197 };
5198
5199 #ifdef __cplusplus
5200diff --git a/libweston/compositor-fbdev.c b/libweston/compositor-fbdev.c
5201index 44f0cf5..32d71e0 100644
5202--- a/libweston/compositor-fbdev.c
5203+++ b/libweston/compositor-fbdev.c
5204@@ -118,7 +118,8 @@ fbdev_output_start_repaint_loop(struct weston_output *output)
5205 }
5206
5207 static int
5208-fbdev_output_repaint(struct weston_output *base, pixman_region32_t *damage)
5209+fbdev_output_repaint(struct weston_output *base, pixman_region32_t *damage,
5210+ void *repaint_data)
5211 {
5212 struct fbdev_output *output = to_fbdev_output(base);
5213 struct weston_compositor *ec = output->base.compositor;
5214@@ -693,7 +694,7 @@ session_notify(struct wl_listener *listener, void *data)
5215
5216 wl_list_for_each(output,
5217 &compositor->output_list, link) {
5218- output->repaint_needed = 0;
5219+ output->repaint_needed = false;
5220 }
5221 }
5222 }
5223diff --git a/libweston/compositor-headless.c b/libweston/compositor-headless.c
5224index a1aec6d..9e42e7f 100644
5225--- a/libweston/compositor-headless.c
5226+++ b/libweston/compositor-headless.c
5227@@ -92,7 +92,8 @@ finish_frame_handler(void *data)
5228
5229 static int
5230 headless_output_repaint(struct weston_output *output_base,
5231- pixman_region32_t *damage)
5232+ pixman_region32_t *damage,
5233+ void *repaint_data)
5234 {
5235 struct headless_output *output = to_headless_output(output_base);
5236 struct weston_compositor *ec = output->base.compositor;
5237diff --git a/libweston/compositor-rdp.c b/libweston/compositor-rdp.c
5238index d9668e8..091472b 100644
5239--- a/libweston/compositor-rdp.c
5240+++ b/libweston/compositor-rdp.c
5241@@ -355,7 +355,8 @@ rdp_output_start_repaint_loop(struct weston_output *output)
5242 }
5243
5244 static int
5245-rdp_output_repaint(struct weston_output *output_base, pixman_region32_t *damage)
5246+rdp_output_repaint(struct weston_output *output_base, pixman_region32_t *damage,
5247+ void *repaint_data)
5248 {
5249 struct rdp_output *output = container_of(output_base, struct rdp_output, base);
5250 struct weston_compositor *ec = output->base.compositor;
5251diff --git a/libweston/compositor-wayland.c b/libweston/compositor-wayland.c
5252index 9d35ef7..ebdbd13 100644
5253--- a/libweston/compositor-wayland.c
5254+++ b/libweston/compositor-wayland.c
5255@@ -488,7 +488,8 @@ wayland_output_start_repaint_loop(struct weston_output *output_base)
5256 #ifdef ENABLE_EGL
5257 static int
5258 wayland_output_repaint_gl(struct weston_output *output_base,
5259- pixman_region32_t *damage)
5260+ pixman_region32_t *damage,
5261+ void *repaint_data)
5262 {
5263 struct wayland_output *output = to_wayland_output(output_base);
5264 struct weston_compositor *ec = output->base.compositor;
5265@@ -595,7 +596,8 @@ wayland_shm_buffer_attach(struct wayland_shm_buffer *sb)
5266
5267 static int
5268 wayland_output_repaint_pixman(struct weston_output *output_base,
5269- pixman_region32_t *damage)
5270+ pixman_region32_t *damage,
5271+ void *repaint_data)
5272 {
5273 struct wayland_output *output = to_wayland_output(output_base);
5274 struct wayland_backend *b =
5275diff --git a/libweston/compositor-x11.c b/libweston/compositor-x11.c
5276index f9cb461..02cdf3e 100644
5277--- a/libweston/compositor-x11.c
5278+++ b/libweston/compositor-x11.c
5279@@ -389,7 +389,8 @@ x11_output_start_repaint_loop(struct weston_output *output)
5280
5281 static int
5282 x11_output_repaint_gl(struct weston_output *output_base,
5283- pixman_region32_t *damage)
5284+ pixman_region32_t *damage,
5285+ void *repaint_data)
5286 {
5287 struct x11_output *output = to_x11_output(output_base);
5288 struct weston_compositor *ec = output->base.compositor;
5289@@ -457,7 +458,8 @@ set_clip_for_output(struct weston_output *output_base, pixman_region32_t *region
5290
5291 static int
5292 x11_output_repaint_shm(struct weston_output *output_base,
5293- pixman_region32_t *damage)
5294+ pixman_region32_t *damage,
5295+ void *repaint_data)
5296 {
5297 struct x11_output *output = to_x11_output(output_base);
5298 struct weston_compositor *ec = output->base.compositor;
5299diff --git a/libweston/compositor.c b/libweston/compositor.c
5300index 9ded23f..fb647da 100644
5301--- a/libweston/compositor.c
5302+++ b/libweston/compositor.c
5303@@ -2254,7 +2254,7 @@ weston_output_take_feedback_list(struct weston_output *output,
5304 }
5305
5306 static int
5307-weston_output_repaint(struct weston_output *output)
5308+weston_output_repaint(struct weston_output *output, void *repaint_data)
5309 {
5310 struct weston_compositor *ec = output->compositor;
5311 struct weston_view *ev;
5312@@ -2273,7 +2273,7 @@ weston_output_repaint(struct weston_output *output)
5313 weston_compositor_build_view_list(ec);
5314
5315 if (output->assign_planes && !output->disable_planes) {
5316- output->assign_planes(output);
5317+ output->assign_planes(output, repaint_data);
5318 } else {
5319 wl_list_for_each(ev, &ec->view_list, link) {
5320 weston_view_move_to_plane(ev, &ec->primary_plane);
5321@@ -2306,11 +2306,13 @@ weston_output_repaint(struct weston_output *output)
5322 if (output->dirty)
5323 weston_output_update_matrix(output);
5324
5325- r = output->repaint(output, &output_damage);
5326+ r = output->repaint(output, &output_damage, repaint_data);
5327
5328 pixman_region32_fini(&output_damage);
5329
5330- output->repaint_needed = 0;
5331+ output->repaint_needed = false;
5332+ if (r == 0)
5333+ output->repaint_status = REPAINT_AWAITING_COMPLETION;
5334
5335 weston_compositor_repick(ec);
5336
5337@@ -2332,16 +2334,25 @@ weston_output_repaint(struct weston_output *output)
5338 static void
5339 weston_output_schedule_repaint_reset(struct weston_output *output)
5340 {
5341- output->repaint_scheduled = 0;
5342+ output->repaint_status = REPAINT_NOT_SCHEDULED;
5343 TL_POINT("core_repaint_exit_loop", TLP_OUTPUT(output), TLP_END);
5344 }
5345
5346 static int
5347-output_repaint_timer_handler(void *data)
5348+weston_output_maybe_repaint(struct weston_output *output, struct timespec *now,
5349+ void *repaint_data)
5350 {
5351- struct weston_output *output = data;
5352 struct weston_compositor *compositor = output->compositor;
5353- int ret;
5354+ int ret = 0;
5355+ int64_t msec_to_repaint;
5356+
5357+ /* We're not ready yet; come back to make a decision later. */
5358+ if (output->repaint_status != REPAINT_SCHEDULED)
5359+ return ret;
5360+
5361+ msec_to_repaint = timespec_sub_to_msec(&output->next_repaint, now);
5362+ if (msec_to_repaint > 1)
5363+ return ret;
5364
5365 /* If we're sleeping, drop the repaint machinery entirely; we will
5366 * explicitly repaint all outputs when we come back. */
5367@@ -2356,15 +2367,92 @@ output_repaint_timer_handler(void *data)
5368
5369 /* If repaint fails, we aren't going to get weston_output_finish_frame
5370 * to trigger a new repaint, so drop it from repaint and hope
5371- * something schedules a successful repaint later. */
5372- ret = weston_output_repaint(output);
5373+ * something schedules a successful repaint later. As repainting may
5374+ * take some time, re-read our clock as a courtesy to the next
5375+ * output. */
5376+ ret = weston_output_repaint(output, repaint_data);
5377+ weston_compositor_read_presentation_clock(compositor, now);
5378 if (ret != 0)
5379 goto err;
5380
5381- return 0;
5382+ return ret;
5383
5384 err:
5385 weston_output_schedule_repaint_reset(output);
5386+ return ret;
5387+}
5388+
5389+static void
5390+output_repaint_timer_arm(struct weston_compositor *compositor)
5391+{
5392+ struct weston_output *output;
5393+ bool any_should_repaint = false;
5394+ struct timespec now;
5395+ int64_t msec_to_next;
5396+
5397+ weston_compositor_read_presentation_clock(compositor, &now);
5398+
5399+ wl_list_for_each(output, &compositor->output_list, link) {
5400+ int64_t msec_to_this;
5401+
5402+ if (output->repaint_status != REPAINT_SCHEDULED)
5403+ continue;
5404+
5405+ msec_to_this = timespec_sub_to_msec(&output->next_repaint,
5406+ &now);
5407+ if (!any_should_repaint || msec_to_this < msec_to_next)
5408+ msec_to_next = msec_to_this;
5409+
5410+ any_should_repaint = true;
5411+ }
5412+
5413+ if (!any_should_repaint)
5414+ return;
5415+
5416+ /* Even if we should repaint immediately, add the minimum 1 ms delay.
5417+ * This is a workaround to allow coalescing multiple output repaints
5418+ * particularly from weston_output_finish_frame()
5419+ * into the same call, which would not happen if we called
5420+ * output_repaint_timer_handler() directly.
5421+ */
5422+ if (msec_to_next < 1)
5423+ msec_to_next = 1;
5424+
5425+ wl_event_source_timer_update(compositor->repaint_timer, msec_to_next);
5426+}
5427+
5428+static int
5429+output_repaint_timer_handler(void *data)
5430+{
5431+ struct weston_compositor *compositor = data;
5432+ struct weston_output *output;
5433+ struct timespec now;
5434+ void *repaint_data = NULL;
5435+ int ret;
5436+
5437+ weston_compositor_read_presentation_clock(compositor, &now);
5438+
5439+ if (compositor->backend->repaint_begin)
5440+ repaint_data = compositor->backend->repaint_begin(compositor);
5441+
5442+ wl_list_for_each(output, &compositor->output_list, link) {
5443+ ret = weston_output_maybe_repaint(output, &now, repaint_data);
5444+ if (ret)
5445+ break;
5446+ }
5447+
5448+ if (ret == 0) {
5449+ if (compositor->backend->repaint_flush)
5450+ compositor->backend->repaint_flush(compositor,
5451+ repaint_data);
5452+ } else {
5453+ if (compositor->backend->repaint_cancel)
5454+ compositor->backend->repaint_cancel(compositor,
5455+ repaint_data);
5456+ }
5457+
5458+ output_repaint_timer_arm(compositor);
5459+
5460 return 0;
5461 }
5462
5463@@ -2376,47 +2464,59 @@ weston_output_finish_frame(struct weston_output *output,
5464 struct weston_compositor *compositor = output->compositor;
5465 int32_t refresh_nsec;
5466 struct timespec now;
5467- struct timespec gone;
5468- int msec;
5469+ int64_t msec_rel;
5470
5471 TL_POINT("core_repaint_finished", TLP_OUTPUT(output),
5472 TLP_VBLANK(stamp), TLP_END);
5473
5474+ assert(output->repaint_status == REPAINT_AWAITING_COMPLETION);
5475+ assert(stamp || (presented_flags & WP_PRESENTATION_FEEDBACK_INVALID));
5476+
5477+ weston_compositor_read_presentation_clock(compositor, &now);
5478+
5479+ /* If we haven't been supplied any timestamp at all, we don't have a
5480+ * timebase to work against, so any delay just wastes time. Push a
5481+ * repaint as soon as possible so we can get on with it. */
5482+ if (!stamp) {
5483+ output->next_repaint = now;
5484+ goto out;
5485+ }
5486+
5487 refresh_nsec = millihz_to_nsec(output->current_mode->refresh);
5488 weston_presentation_feedback_present_list(&output->feedback_list,
5489 output, refresh_nsec, stamp,
5490 output->msc,
5491 presented_flags);
5492
5493- output->frame_time = stamp->tv_sec * 1000 + stamp->tv_nsec / 1000000;
5494+ output->frame_time = timespec_to_msec(stamp);
5495
5496- weston_compositor_read_presentation_clock(compositor, &now);
5497- timespec_sub(&gone, &now, stamp);
5498- msec = (refresh_nsec - timespec_to_nsec(&gone)) / 1000000; /* floor */
5499- msec -= compositor->repaint_msec;
5500+ timespec_add_nsec(&output->next_repaint, stamp, refresh_nsec);
5501+ timespec_add_msec(&output->next_repaint, &output->next_repaint,
5502+ -compositor->repaint_msec);
5503+ msec_rel = timespec_sub_to_msec(&output->next_repaint, &now);
5504
5505- if (msec < -1000 || msec > 1000) {
5506+ if (msec_rel < -1000 || msec_rel > 1000) {
5507 static bool warned;
5508
5509 if (!warned)
5510 weston_log("Warning: computed repaint delay is "
5511- "insane: %d msec\n", msec);
5512+ "insane: %lld msec\n", (long long) msec_rel);
5513 warned = true;
5514
5515- msec = 0;
5516+ output->next_repaint = now;
5517 }
5518
5519 /* Called from restart_repaint_loop and restart happens already after
5520 * the deadline given by repaint_msec? In that case we delay until
5521 * the deadline of the next frame, to give clients a more predictable
5522 * timing of the repaint cycle to lock on. */
5523- if (presented_flags == WP_PRESENTATION_FEEDBACK_INVALID && msec < 0)
5524- msec += refresh_nsec / 1000000;
5525+ if (presented_flags == WP_PRESENTATION_FEEDBACK_INVALID && msec_rel < 0)
5526+ timespec_add_nsec(&output->next_repaint, &output->next_repaint,
5527+ refresh_nsec);
5528
5529- if (msec < 1)
5530- output_repaint_timer_handler(output);
5531- else
5532- wl_event_source_timer_update(output->repaint_timer, msec);
5533+out:
5534+ output->repaint_status = REPAINT_SCHEDULED;
5535+ output_repaint_timer_arm(compositor);
5536 }
5537
5538 static void
5539@@ -2424,6 +2524,8 @@ idle_repaint(void *data)
5540 {
5541 struct weston_output *output = data;
5542
5543+ assert(output->repaint_status == REPAINT_BEGIN_FROM_IDLE);
5544+ output->repaint_status = REPAINT_AWAITING_COMPLETION;
5545 output->start_repaint_loop(output);
5546 }
5547
5548@@ -2538,12 +2640,17 @@ weston_output_schedule_repaint(struct weston_output *output)
5549 TL_POINT("core_repaint_req", TLP_OUTPUT(output), TLP_END);
5550
5551 loop = wl_display_get_event_loop(compositor->wl_display);
5552- output->repaint_needed = 1;
5553- if (output->repaint_scheduled)
5554+ output->repaint_needed = true;
5555+
5556+ /* If we already have a repaint scheduled for our idle handler,
5557+ * no need to set it again. If the repaint has been called but
5558+ * not finished, then weston_output_finish_frame() will notice
5559+ * that a repaint is needed and schedule one. */
5560+ if (output->repaint_status != REPAINT_NOT_SCHEDULED)
5561 return;
5562
5563+ output->repaint_status = REPAINT_BEGIN_FROM_IDLE;
5564 wl_event_loop_add_idle(loop, idle_repaint, output);
5565- output->repaint_scheduled = 1;
5566 TL_POINT("core_repaint_enter_loop", TLP_OUTPUT(output), TLP_END);
5567 }
5568
5569@@ -4400,8 +4507,6 @@ weston_output_transform_coordinate(struct weston_output *output,
5570 static void
5571 weston_output_enable_undo(struct weston_output *output)
5572 {
5573- wl_event_source_remove(output->repaint_timer);
5574-
5575 wl_global_destroy(output->global);
5576
5577 pixman_region32_fini(&output->region);
5578@@ -4583,7 +4688,6 @@ weston_output_enable(struct weston_output *output)
5579 {
5580 struct weston_compositor *c = output->compositor;
5581 struct weston_output *iterator;
5582- struct wl_event_loop *loop;
5583 int x = 0, y = 0;
5584
5585 assert(output->enable);
5586@@ -4624,10 +4728,6 @@ weston_output_enable(struct weston_output *output)
5587 wl_list_init(&output->feedback_list);
5588 wl_list_init(&output->link);
5589
5590- loop = wl_display_get_event_loop(c->wl_display);
5591- output->repaint_timer = wl_event_loop_add_timer(loop,
5592- output_repaint_timer_handler, output);
5593-
5594 /* Invert the output id pool and look for the lowest numbered
5595 * switch (the least significant bit). Take that bit's position
5596 * as our ID, and mark it used in the compositor's output_id_pool.
5597@@ -5129,6 +5229,9 @@ weston_compositor_create(struct wl_display *display, void *user_data)
5598
5599 loop = wl_display_get_event_loop(ec->wl_display);
5600 ec->idle_source = wl_event_loop_add_timer(loop, idle_handler, ec);
5601+ ec->repaint_timer =
5602+ wl_event_loop_add_timer(loop, output_repaint_timer_handler,
5603+ ec);
5604
5605 weston_layer_init(&ec->fade_layer, ec);
5606 weston_layer_init(&ec->cursor_layer, ec);
5607diff --git a/libweston/compositor.h b/libweston/compositor.h
5608index 08e728a..6070c77 100644
5609--- a/libweston/compositor.h
5610+++ b/libweston/compositor.h
5611@@ -170,9 +170,23 @@ struct weston_output {
5612 pixman_region32_t region;
5613
5614 pixman_region32_t previous_damage;
5615- int repaint_needed;
5616- int repaint_scheduled;
5617- struct wl_event_source *repaint_timer;
5618+
5619+ /** True if damage has occurred since the last repaint for this output;
5620+ * if set, a repaint will eventually occur. */
5621+ bool repaint_needed;
5622+
5623+ /** State of the repaint loop */
5624+ enum {
5625+ REPAINT_NOT_SCHEDULED = 0, /**< idle; no repaint will occur */
5626+ REPAINT_BEGIN_FROM_IDLE, /**< start_repaint_loop scheduled */
5627+ REPAINT_SCHEDULED, /**< repaint is scheduled to occur */
5628+ REPAINT_AWAITING_COMPLETION, /**< last repaint not yet finished */
5629+ } repaint_status;
5630+
5631+ /** If repaint_status is REPAINT_SCHEDULED, contains the time the
5632+ * next repaint should be run */
5633+ struct timespec next_repaint;
5634+
5635 struct weston_output_zoom zoom;
5636 int dirty;
5637 struct wl_signal frame_signal;
5638@@ -198,9 +212,10 @@ struct weston_output {
5639
5640 void (*start_repaint_loop)(struct weston_output *output);
5641 int (*repaint)(struct weston_output *output,
5642- pixman_region32_t *damage);
5643+ pixman_region32_t *damage,
5644+ void *repaint_data);
5645 void (*destroy)(struct weston_output *output);
5646- void (*assign_planes)(struct weston_output *output);
5647+ void (*assign_planes)(struct weston_output *output, void *repaint_data);
5648 int (*switch_mode)(struct weston_output *output, struct weston_mode *mode);
5649
5650 /* backlight values are on 0-255 range, where higher is brighter */
5651@@ -790,6 +805,39 @@ struct weston_backend_config {
5652 struct weston_backend {
5653 void (*destroy)(struct weston_compositor *compositor);
5654 void (*restore)(struct weston_compositor *compositor);
5655+
5656+ /** Begin a repaint sequence
5657+ *
5658+ * Provides the backend with explicit markers around repaint
5659+ * sequences, which may allow the backend to aggregate state
5660+ * application. This call will be bracketed by the repaint_flush (on
5661+ * success), or repaint_cancel (when any output in the grouping fails
5662+ * repaint).
5663+ *
5664+ * Returns an opaque pointer, which the backend may use as private
5665+ * data referring to the repaint cycle.
5666+ */
5667+ void * (*repaint_begin)(struct weston_compositor *compositor);
5668+
5669+ /** Cancel a repaint sequence
5670+ *
5671+ * Cancels a repaint sequence, when an error has occurred during
5672+ * one output's repaint; see repaint_begin.
5673+ *
5674+ * @param repaint_data Data returned by repaint_begin
5675+ */
5676+ void (*repaint_cancel)(struct weston_compositor *compositor,
5677+ void *repaint_data);
5678+
5679+ /** Conclude a repaint sequence
5680+ *
5681+ * Called on successful completion of a repaint sequence; see
5682+ * repaint_begin.
5683+ *
5684+ * @param repaint_data Data returned by repaint_begin
5685+ */
5686+ void (*repaint_flush)(struct weston_compositor *compositor,
5687+ void *repaint_data);
5688 };
5689
5690 struct weston_desktop_xwayland;
5691@@ -845,6 +893,7 @@ struct weston_compositor {
5692 struct wl_event_source *idle_source;
5693 uint32_t idle_inhibit;
5694 int idle_time; /* timeout, s */
5695+ struct wl_event_source *repaint_timer;
5696
5697 const struct weston_pointer_grab_interface *default_pointer_grab;
5698
5699diff --git a/libweston/pixel-formats.c b/libweston/pixel-formats.c
5700new file mode 100644
5701index 0000000..df84a9f
5702--- /dev/null
5703+++ b/libweston/pixel-formats.c
5704@@ -0,0 +1,430 @@
5705+/*
5706+ * Copyright © 2016 Collabora, Ltd.
5707+ *
5708+ * Permission is hereby granted, free of charge, to any person obtaining a
5709+ * copy of this software and associated documentation files (the "Software"),
5710+ * to deal in the Software without restriction, including without limitation
5711+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
5712+ * and/or sell copies of the Software, and to permit persons to whom the
5713+ * Software is furnished to do so, subject to the following conditions:
5714+ *
5715+ * The above copyright notice and this permission notice (including the next
5716+ * paragraph) shall be included in all copies or substantial portions of the
5717+ * Software.
5718+ *
5719+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
5720+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
5721+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
5722+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
5723+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
5724+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
5725+ * DEALINGS IN THE SOFTWARE.
5726+ *
5727+ * Author: Daniel Stone <daniels@collabora.com>
5728+ */
5729+
5730+#include "config.h"
5731+
5732+#include <endian.h>
5733+#include <inttypes.h>
5734+#include <stdbool.h>
5735+#include <unistd.h>
5736+#include <drm_fourcc.h>
5737+
5738+#include "helpers.h"
5739+#include "wayland-util.h"
5740+#include "pixel-formats.h"
5741+
5742+#if ENABLE_EGL
5743+#include <EGL/egl.h>
5744+#include <EGL/eglext.h>
5745+#include <GLES2/gl2.h>
5746+#include <GLES2/gl2ext.h>
5747+#define GL_FORMAT(fmt) .gl_format = (fmt)
5748+#define GL_TYPE(type) .gl_type = (type)
5749+#define SAMPLER_TYPE(type) .sampler_type = (type)
5750+#else
5751+#define GL_FORMAT(fmt) .gl_format = 0
5752+#define GL_TYPE(type) .gl_type = 0
5753+#define SAMPLER_TYPE(type) .sampler_type = 0
5754+#endif
5755+
5756+#include "weston-egl-ext.h"
5757+
5758+/**
5759+ * Table of DRM formats supported by Weston; RGB, ARGB and YUV formats are
5760+ * supported. Indexed/greyscale formats, and formats not containing complete
5761+ * colour channels, are not supported.
5762+ */
5763+static const struct pixel_format_info pixel_format_table[] = {
5764+ {
5765+ .format = DRM_FORMAT_XRGB4444,
5766+ },
5767+ {
5768+ .format = DRM_FORMAT_ARGB4444,
5769+ .opaque_substitute = DRM_FORMAT_XRGB4444,
5770+ },
5771+ {
5772+ .format = DRM_FORMAT_XBGR4444,
5773+ },
5774+ {
5775+ .format = DRM_FORMAT_ABGR4444,
5776+ .opaque_substitute = DRM_FORMAT_XBGR4444,
5777+ },
5778+ {
5779+ .format = DRM_FORMAT_RGBX4444,
5780+# if __BYTE_ORDER == __LITTLE_ENDIAN
5781+ GL_FORMAT(GL_RGBA),
5782+ GL_TYPE(GL_UNSIGNED_SHORT_4_4_4_4),
5783+#endif
5784+ },
5785+ {
5786+ .format = DRM_FORMAT_RGBA4444,
5787+ .opaque_substitute = DRM_FORMAT_RGBX4444,
5788+# if __BYTE_ORDER == __LITTLE_ENDIAN
5789+ GL_FORMAT(GL_RGBA),
5790+ GL_TYPE(GL_UNSIGNED_SHORT_4_4_4_4),
5791+#endif
5792+ },
5793+ {
5794+ .format = DRM_FORMAT_BGRX4444,
5795+ },
5796+ {
5797+ .format = DRM_FORMAT_BGRA4444,
5798+ .opaque_substitute = DRM_FORMAT_BGRX4444,
5799+ },
5800+ {
5801+ .format = DRM_FORMAT_XRGB1555,
5802+ .depth = 15,
5803+ .bpp = 16,
5804+ },
5805+ {
5806+ .format = DRM_FORMAT_ARGB1555,
5807+ .opaque_substitute = DRM_FORMAT_XRGB1555,
5808+ },
5809+ {
5810+ .format = DRM_FORMAT_XBGR1555,
5811+ },
5812+ {
5813+ .format = DRM_FORMAT_ABGR1555,
5814+ .opaque_substitute = DRM_FORMAT_XBGR1555,
5815+ },
5816+ {
5817+ .format = DRM_FORMAT_RGBX5551,
5818+# if __BYTE_ORDER == __LITTLE_ENDIAN
5819+ GL_FORMAT(GL_RGBA),
5820+ GL_TYPE(GL_UNSIGNED_SHORT_5_5_5_1),
5821+#endif
5822+ },
5823+ {
5824+ .format = DRM_FORMAT_RGBA5551,
5825+ .opaque_substitute = DRM_FORMAT_RGBX5551,
5826+# if __BYTE_ORDER == __LITTLE_ENDIAN
5827+ GL_FORMAT(GL_RGBA),
5828+ GL_TYPE(GL_UNSIGNED_SHORT_5_5_5_1),
5829+#endif
5830+ },
5831+ {
5832+ .format = DRM_FORMAT_BGRX5551,
5833+ },
5834+ {
5835+ .format = DRM_FORMAT_BGRA5551,
5836+ .opaque_substitute = DRM_FORMAT_BGRX5551,
5837+ },
5838+ {
5839+ .format = DRM_FORMAT_RGB565,
5840+ .depth = 16,
5841+ .bpp = 16,
5842+# if __BYTE_ORDER == __LITTLE_ENDIAN
5843+ GL_FORMAT(GL_RGB),
5844+ GL_TYPE(GL_UNSIGNED_SHORT_5_6_5),
5845+#endif
5846+ },
5847+ {
5848+ .format = DRM_FORMAT_BGR565,
5849+ },
5850+ {
5851+ .format = DRM_FORMAT_RGB888,
5852+ },
5853+ {
5854+ .format = DRM_FORMAT_BGR888,
5855+ GL_FORMAT(GL_RGB),
5856+ GL_TYPE(GL_UNSIGNED_BYTE),
5857+ },
5858+ {
5859+ .format = DRM_FORMAT_XRGB8888,
5860+ .depth = 24,
5861+ .bpp = 32,
5862+ GL_FORMAT(GL_BGRA_EXT),
5863+ GL_TYPE(GL_UNSIGNED_BYTE),
5864+ },
5865+ {
5866+ .format = DRM_FORMAT_ARGB8888,
5867+ .opaque_substitute = DRM_FORMAT_XRGB8888,
5868+ .depth = 32,
5869+ .bpp = 32,
5870+ GL_FORMAT(GL_BGRA_EXT),
5871+ GL_TYPE(GL_UNSIGNED_BYTE),
5872+ },
5873+ {
5874+ .format = DRM_FORMAT_XBGR8888,
5875+ GL_FORMAT(GL_RGBA),
5876+ GL_TYPE(GL_UNSIGNED_BYTE),
5877+ },
5878+ {
5879+ .format = DRM_FORMAT_ABGR8888,
5880+ .opaque_substitute = DRM_FORMAT_XBGR8888,
5881+ GL_FORMAT(GL_RGBA),
5882+ GL_TYPE(GL_UNSIGNED_BYTE),
5883+ },
5884+ {
5885+ .format = DRM_FORMAT_RGBX8888,
5886+ },
5887+ {
5888+ .format = DRM_FORMAT_RGBA8888,
5889+ .opaque_substitute = DRM_FORMAT_RGBX8888,
5890+ },
5891+ {
5892+ .format = DRM_FORMAT_BGRX8888,
5893+ },
5894+ {
5895+ .format = DRM_FORMAT_BGRA8888,
5896+ .opaque_substitute = DRM_FORMAT_BGRX8888,
5897+ },
5898+ {
5899+ .format = DRM_FORMAT_XRGB2101010,
5900+ .depth = 30,
5901+ .bpp = 32,
5902+ },
5903+ {
5904+ .format = DRM_FORMAT_ARGB2101010,
5905+ .opaque_substitute = DRM_FORMAT_XRGB2101010,
5906+ },
5907+ {
5908+ .format = DRM_FORMAT_XBGR2101010,
5909+# if __BYTE_ORDER == __LITTLE_ENDIAN
5910+ GL_FORMAT(GL_RGBA),
5911+ GL_TYPE(GL_UNSIGNED_INT_2_10_10_10_REV_EXT),
5912+#endif
5913+ },
5914+ {
5915+ .format = DRM_FORMAT_ABGR2101010,
5916+ .opaque_substitute = DRM_FORMAT_XBGR2101010,
5917+# if __BYTE_ORDER == __LITTLE_ENDIAN
5918+ GL_FORMAT(GL_RGBA),
5919+ GL_TYPE(GL_UNSIGNED_INT_2_10_10_10_REV_EXT),
5920+#endif
5921+ },
5922+ {
5923+ .format = DRM_FORMAT_RGBX1010102,
5924+ },
5925+ {
5926+ .format = DRM_FORMAT_RGBA1010102,
5927+ .opaque_substitute = DRM_FORMAT_RGBX1010102,
5928+ },
5929+ {
5930+ .format = DRM_FORMAT_BGRX1010102,
5931+ },
5932+ {
5933+ .format = DRM_FORMAT_BGRA1010102,
5934+ .opaque_substitute = DRM_FORMAT_BGRX1010102,
5935+ },
5936+ {
5937+ .format = DRM_FORMAT_YUYV,
5938+ SAMPLER_TYPE(EGL_TEXTURE_Y_XUXV_WL),
5939+ .num_planes = 1,
5940+ .hsub = 2,
5941+ },
5942+ {
5943+ .format = DRM_FORMAT_YVYU,
5944+ SAMPLER_TYPE(EGL_TEXTURE_Y_XUXV_WL),
5945+ .num_planes = 1,
5946+ .chroma_order = ORDER_VU,
5947+ .hsub = 2,
5948+ },
5949+ {
5950+ .format = DRM_FORMAT_UYVY,
5951+ SAMPLER_TYPE(EGL_TEXTURE_Y_XUXV_WL),
5952+ .num_planes = 1,
5953+ .luma_chroma_order = ORDER_CHROMA_LUMA,
5954+ .hsub = 2,
5955+ },
5956+ {
5957+ .format = DRM_FORMAT_VYUY,
5958+ SAMPLER_TYPE(EGL_TEXTURE_Y_XUXV_WL),
5959+ .num_planes = 1,
5960+ .luma_chroma_order = ORDER_CHROMA_LUMA,
5961+ .chroma_order = ORDER_VU,
5962+ .hsub = 2,
5963+ },
5964+ {
5965+ .format = DRM_FORMAT_NV12,
5966+ SAMPLER_TYPE(EGL_TEXTURE_Y_UV_WL),
5967+ .num_planes = 2,
5968+ .hsub = 2,
5969+ .vsub = 2,
5970+ },
5971+ {
5972+ .format = DRM_FORMAT_NV21,
5973+ SAMPLER_TYPE(EGL_TEXTURE_Y_UV_WL),
5974+ .num_planes = 2,
5975+ .chroma_order = ORDER_VU,
5976+ .hsub = 2,
5977+ .vsub = 2,
5978+ },
5979+ {
5980+ .format = DRM_FORMAT_NV16,
5981+ SAMPLER_TYPE(EGL_TEXTURE_Y_UV_WL),
5982+ .num_planes = 2,
5983+ .hsub = 2,
5984+ .vsub = 1,
5985+ },
5986+ {
5987+ .format = DRM_FORMAT_NV61,
5988+ SAMPLER_TYPE(EGL_TEXTURE_Y_UV_WL),
5989+ .num_planes = 2,
5990+ .chroma_order = ORDER_VU,
5991+ .hsub = 2,
5992+ .vsub = 1,
5993+ },
5994+ {
5995+ .format = DRM_FORMAT_NV24,
5996+ SAMPLER_TYPE(EGL_TEXTURE_Y_UV_WL),
5997+ .num_planes = 2,
5998+ },
5999+ {
6000+ .format = DRM_FORMAT_NV42,
6001+ SAMPLER_TYPE(EGL_TEXTURE_Y_UV_WL),
6002+ .num_planes = 2,
6003+ .chroma_order = ORDER_VU,
6004+ },
6005+ {
6006+ .format = DRM_FORMAT_YUV410,
6007+ SAMPLER_TYPE(EGL_TEXTURE_Y_U_V_WL),
6008+ .num_planes = 3,
6009+ .hsub = 4,
6010+ .vsub = 4,
6011+ },
6012+ {
6013+ .format = DRM_FORMAT_YVU410,
6014+ SAMPLER_TYPE(EGL_TEXTURE_Y_U_V_WL),
6015+ .num_planes = 3,
6016+ .chroma_order = ORDER_VU,
6017+ .hsub = 4,
6018+ .vsub = 4,
6019+ },
6020+ {
6021+ .format = DRM_FORMAT_YUV411,
6022+ SAMPLER_TYPE(EGL_TEXTURE_Y_U_V_WL),
6023+ .num_planes = 3,
6024+ .hsub = 4,
6025+ .vsub = 1,
6026+ },
6027+ {
6028+ .format = DRM_FORMAT_YVU411,
6029+ SAMPLER_TYPE(EGL_TEXTURE_Y_U_V_WL),
6030+ .num_planes = 3,
6031+ .chroma_order = ORDER_VU,
6032+ .hsub = 4,
6033+ .vsub = 1,
6034+ },
6035+ {
6036+ .format = DRM_FORMAT_YUV420,
6037+ SAMPLER_TYPE(EGL_TEXTURE_Y_U_V_WL),
6038+ .num_planes = 3,
6039+ .hsub = 2,
6040+ .vsub = 2,
6041+ },
6042+ {
6043+ .format = DRM_FORMAT_YVU420,
6044+ SAMPLER_TYPE(EGL_TEXTURE_Y_U_V_WL),
6045+ .num_planes = 3,
6046+ .chroma_order = ORDER_VU,
6047+ .hsub = 2,
6048+ .vsub = 2,
6049+ },
6050+ {
6051+ .format = DRM_FORMAT_YUV422,
6052+ SAMPLER_TYPE(EGL_TEXTURE_Y_U_V_WL),
6053+ .num_planes = 3,
6054+ .hsub = 2,
6055+ .vsub = 1,
6056+ },
6057+ {
6058+ .format = DRM_FORMAT_YVU422,
6059+ SAMPLER_TYPE(EGL_TEXTURE_Y_U_V_WL),
6060+ .num_planes = 3,
6061+ .chroma_order = ORDER_VU,
6062+ .hsub = 2,
6063+ .vsub = 1,
6064+ },
6065+ {
6066+ .format = DRM_FORMAT_YUV444,
6067+ SAMPLER_TYPE(EGL_TEXTURE_Y_U_V_WL),
6068+ .num_planes = 3,
6069+ },
6070+ {
6071+ .format = DRM_FORMAT_YVU444,
6072+ SAMPLER_TYPE(EGL_TEXTURE_Y_U_V_WL),
6073+ .num_planes = 3,
6074+ .chroma_order = ORDER_VU,
6075+ },
6076+};
6077+
6078+WL_EXPORT const struct pixel_format_info *
6079+pixel_format_get_info(uint32_t format)
6080+{
6081+ unsigned int i;
6082+
6083+ for (i = 0; i < ARRAY_LENGTH(pixel_format_table); i++) {
6084+ if (pixel_format_table[i].format == format)
6085+ return &pixel_format_table[i];
6086+ }
6087+
6088+ return NULL;
6089+}
6090+
6091+WL_EXPORT unsigned int
6092+pixel_format_get_plane_count(const struct pixel_format_info *info)
6093+{
6094+ return info->num_planes ? info->num_planes : 1;
6095+}
6096+
6097+WL_EXPORT bool
6098+pixel_format_is_opaque(const struct pixel_format_info *info)
6099+{
6100+ return !info->opaque_substitute;
6101+}
6102+
6103+WL_EXPORT const struct pixel_format_info *
6104+pixel_format_get_opaque_substitute(const struct pixel_format_info *info)
6105+{
6106+ if (!info->opaque_substitute)
6107+ return info;
6108+ else
6109+ return pixel_format_get_info(info->opaque_substitute);
6110+}
6111+
6112+WL_EXPORT unsigned int
6113+pixel_format_width_for_plane(const struct pixel_format_info *info,
6114+ unsigned int plane,
6115+ unsigned int width)
6116+{
6117+ /* We don't support any formats where the first plane is subsampled. */
6118+ if (plane == 0 || !info->hsub)
6119+ return width;
6120+
6121+ return width / info->hsub;
6122+}
6123+
6124+WL_EXPORT unsigned int
6125+pixel_format_height_for_plane(const struct pixel_format_info *info,
6126+ unsigned int plane,
6127+ unsigned int height)
6128+{
6129+ /* We don't support any formats where the first plane is subsampled. */
6130+ if (plane == 0 || !info->vsub)
6131+ return height;
6132+
6133+ return height / info->vsub;
6134+}
6135diff --git a/libweston/pixel-formats.h b/libweston/pixel-formats.h
6136new file mode 100644
6137index 0000000..b16aae3
6138--- /dev/null
6139+++ b/libweston/pixel-formats.h
6140@@ -0,0 +1,194 @@
6141+/*
6142+ * Copyright © 2016 Collabora, Ltd.
6143+ *
6144+ * Permission is hereby granted, free of charge, to any person obtaining a
6145+ * copy of this software and associated documentation files (the "Software"),
6146+ * to deal in the Software without restriction, including without limitation
6147+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
6148+ * and/or sell copies of the Software, and to permit persons to whom the
6149+ * Software is furnished to do so, subject to the following conditions:
6150+ *
6151+ * The above copyright notice and this permission notice (including the next
6152+ * paragraph) shall be included in all copies or substantial portions of the
6153+ * Software.
6154+ *
6155+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
6156+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
6157+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
6158+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
6159+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
6160+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
6161+ * DEALINGS IN THE SOFTWARE.
6162+ *
6163+ * Author: Daniel Stone <daniels@collabora.com>
6164+ */
6165+
6166+#include <inttypes.h>
6167+#include <stdbool.h>
6168+
6169+/**
6170+ * Contains information about pixel formats, mapping format codes from
6171+ * wl_shm and drm_fourcc.h (which are deliberately identical, but for the
6172+ * special cases of WL_SHM_ARGB8888 and WL_SHM_XRGB8888) into various
6173+ * sets of information. Helper functions are provided for dealing with these
6174+ * raw structures.
6175+ */
6176+struct pixel_format_info {
6177+ /** DRM/wl_shm format code */
6178+ uint32_t format;
6179+
6180+ /** If non-zero, number of planes in base (non-modified) format. */
6181+ int num_planes;
6182+
6183+ /** If format contains alpha channel, opaque equivalent of format,
6184+ * i.e. alpha channel replaced with X. */
6185+ uint32_t opaque_substitute;
6186+
6187+ /** How the format should be sampled, expressed in terms of tokens
6188+ * from the EGL_WL_bind_wayland_display extension. If not set,
6189+ * assumed to be either RGB or RGBA, depending on whether or not
6190+ * the format contains an alpha channel. The samplers may still
6191+ * return alpha even for opaque formats; users must manually set
6192+ * the alpha channel to 1.0 (or ignore it) if the format is
6193+ * opaque. */
6194+ uint32_t sampler_type;
6195+
6196+ /** GL format, if data can be natively/directly uploaded. Note that
6197+ * whilst DRM formats are little-endian unless explicitly specified,
6198+ * (i.e. DRM_FORMAT_ARGB8888 is stored BGRA as sequential bytes in
6199+ * memory), GL uses the sequential byte order, so that format maps to
6200+ * GL_BGRA_EXT plus GL_UNSIGNED_BYTE. To add to the confusion, the
6201+ * explicitly-sized types (e.g. GL_UNSIGNED_SHORT_5_5_5_1) read in
6202+ * machine-endian order, so for these types, the correspondence
6203+ * depends on endianness. */
6204+ int gl_format;
6205+
6206+ /** GL data type, if data can be natively/directly uploaded. */
6207+ int gl_type;
6208+
6209+ /** If set, this format can be used with the legacy drmModeAddFB()
6210+ * function (not AddFB2), using this and the bpp member. */
6211+ int depth;
6212+
6213+ /** See 'depth' member above. */
6214+ int bpp;
6215+
6216+ /** Horizontal subsampling; if non-zero, divide the width by this
6217+ * member to obtain the number of columns in the source buffer for
6218+ * secondary planes only. Stride is not affected by horizontal
6219+ * subsampling. */
6220+ int hsub;
6221+
6222+ /** Vertical subsampling; if non-zero, divide the height by this
6223+ * member to obtain the number of rows in the source buffer for
6224+ * secondary planes only. */
6225+ int vsub;
6226+
6227+ /* Ordering of chroma components. */
6228+ enum {
6229+ ORDER_UV = 0,
6230+ ORDER_VU,
6231+ } chroma_order;
6232+
6233+ /* If packed YUV (num_planes == 1), ordering of luma/chroma
6234+ * components. */
6235+ enum {
6236+ ORDER_LUMA_CHROMA = 0,
6237+ ORDER_CHROMA_LUMA,
6238+ } luma_chroma_order;
6239+};
6240+
6241+/**
6242+ * Get pixel format information for a DRM format code
6243+ *
6244+ * Given a DRM format code, return a pixel format info structure describing
6245+ * the properties of that format.
6246+ *
6247+ * @param format DRM format code to get info for
6248+ * @returns A pixel format structure (must not be freed), or NULL if the
6249+ * format could not be found
6250+ */
6251+const struct pixel_format_info *pixel_format_get_info(uint32_t format);
6252+
6253+/**
6254+ * Get number of planes used by a pixel format
6255+ *
6256+ * Given a pixel format info structure, return the number of planes
6257+ * required for a buffer. Note that this is not necessarily identical to
6258+ * the number of samplers required to be bound, as two views into a single
6259+ * plane are sometimes required.
6260+ *
6261+ * @param format Pixel format info structure
6262+ * @returns Number of planes required for the format
6263+ */
6264+unsigned int
6265+pixel_format_get_plane_count(const struct pixel_format_info *format);
6266+
6267+/**
6268+ * Determine if a pixel format is opaque or contains alpha
6269+ *
6270+ * Returns whether or not the pixel format is opaque, or contains a
6271+ * significant alpha channel. Note that the suggested EGL sampler type may
6272+ * still sample undefined data into the alpha channel; users must consider
6273+ * alpha as 1.0 if the format is opaque, and not rely on the sampler to
6274+ * return this when sampling from the alpha channel.
6275+ *
6276+ * @param format Pixel format info structure
6277+ * @returns True if the format is opaque, or false if it has significant alpha
6278+ */
6279+bool pixel_format_is_opaque(const struct pixel_format_info *format);
6280+
6281+/**
6282+ * Get compatible opaque equivalent for a format
6283+ *
6284+ * Given a pixel format info structure, return a format which is wholly
6285+ * compatible with the input format, but opaque, ignoring the alpha channel.
6286+ * If an alpha format is provided, but the content is known to all be opaque,
6287+ * then this can be used as a substitute to avoid blending.
6288+ *
6289+ * If the input format is opaque, this function will return the input format.
6290+ *
6291+ * @param format Pixel format info structure
6292+ * @returns A pixel format info structure for the compatible opaque substitute
6293+ */
6294+const struct pixel_format_info *
6295+pixel_format_get_opaque_substitute(const struct pixel_format_info *format);
6296+
6297+/**
6298+ * Return the effective sampling width for a given plane
6299+ *
6300+ * When horizontal subsampling is effective, a sampler bound to a secondary
6301+ * plane must bind the sampler with a smaller effective width. This function
6302+ * returns the effective width to use for the sampler, i.e. dividing by hsub.
6303+ *
6304+ * If horizontal subsampling is not in effect, this will be equal to the
6305+ * width.
6306+ *
6307+ * @param format Pixel format info structure
6308+ * @param plane Zero-indexed plane number
6309+ * @param width Width of the buffer
6310+ * @returns Effective width for sampling
6311+ */
6312+unsigned int
6313+pixel_format_width_for_plane(const struct pixel_format_info *format,
6314+ unsigned int plane,
6315+ unsigned int width);
6316+
6317+/**
6318+ * Return the effective sampling height for a given plane
6319+ *
6320+ * When vertical subsampling is in effect, a sampler bound to a secondary
6321+ * plane must bind the sampler with a smaller effective height. This function
6322+ * returns the effective height to use for the sampler, i.e. dividing by vsub.
6323+ *
6324+ * If vertical subsampling is not in effect, this will be equal to the height.
6325+ *
6326+ * @param format Pixel format info structure
6327+ * @param plane Zero-indexed plane number
6328+ * @param height Height of the buffer
6329+ * @returns Effective width for sampling
6330+ */
6331+unsigned int
6332+pixel_format_height_for_plane(const struct pixel_format_info *format,
6333+ unsigned int plane,
6334+ unsigned int height);
6335diff --git a/shared/timespec-util.h b/shared/timespec-util.h
6336index edd4ec1..ca0156a 100644
6337--- a/shared/timespec-util.h
6338+++ b/shared/timespec-util.h
6339@@ -28,6 +28,8 @@
6340
6341 #include <stdint.h>
6342 #include <assert.h>
6343+#include <time.h>
6344+#include <stdbool.h>
6345
6346 #define NSEC_PER_SEC 1000000000
6347
6348@@ -49,6 +51,39 @@ timespec_sub(struct timespec *r,
6349 }
6350 }
6351
6352+/* Add a nanosecond value to a timespec
6353+ *
6354+ * \param r[out] result: a + b
6355+ * \param a[in] base operand as timespec
6356+ * \param b[in] operand in nanoseconds
6357+ */
6358+static inline void
6359+timespec_add_nsec(struct timespec *r, const struct timespec *a, int64_t b)
6360+{
6361+ r->tv_sec = a->tv_sec + (b / NSEC_PER_SEC);
6362+ r->tv_nsec = a->tv_nsec + (b % NSEC_PER_SEC);
6363+
6364+ if (r->tv_nsec >= NSEC_PER_SEC) {
6365+ r->tv_sec++;
6366+ r->tv_nsec -= NSEC_PER_SEC;
6367+ } else if (r->tv_nsec < 0) {
6368+ r->tv_sec--;
6369+ r->tv_nsec += NSEC_PER_SEC;
6370+ }
6371+}
6372+
6373+/* Add a millisecond value to a timespec
6374+ *
6375+ * \param r[out] result: a + b
6376+ * \param a[in] base operand as timespec
6377+ * \param b[in] operand in milliseconds
6378+ */
6379+static inline void
6380+timespec_add_msec(struct timespec *r, const struct timespec *a, int64_t b)
6381+{
6382+ return timespec_add_nsec(r, a, b * 1000000);
6383+}
6384+
6385 /* Convert timespec to nanoseconds
6386 *
6387 * \param a timespec
6388@@ -60,6 +95,155 @@ timespec_to_nsec(const struct timespec *a)
6389 return (int64_t)a->tv_sec * NSEC_PER_SEC + a->tv_nsec;
6390 }
6391
6392+/* Subtract timespecs and return result in nanoseconds
6393+ *
6394+ * \param a[in] operand
6395+ * \param b[in] operand
6396+ * \return to_nanoseconds(a - b)
6397+ */
6398+static inline int64_t
6399+timespec_sub_to_nsec(const struct timespec *a, const struct timespec *b)
6400+{
6401+ struct timespec r;
6402+ timespec_sub(&r, a, b);
6403+ return timespec_to_nsec(&r);
6404+}
6405+
6406+/* Convert timespec to milliseconds
6407+ *
6408+ * \param a timespec
6409+ * \return milliseconds
6410+ *
6411+ * Rounding to integer milliseconds happens always down (floor()).
6412+ */
6413+static inline int64_t
6414+timespec_to_msec(const struct timespec *a)
6415+{
6416+ return (int64_t)a->tv_sec * 1000 + a->tv_nsec / 1000000;
6417+}
6418+
6419+/* Subtract timespecs and return result in milliseconds
6420+ *
6421+ * \param a[in] operand
6422+ * \param b[in] operand
6423+ * \return to_milliseconds(a - b)
6424+ */
6425+static inline int64_t
6426+timespec_sub_to_msec(const struct timespec *a, const struct timespec *b)
6427+{
6428+ return timespec_sub_to_nsec(a, b) / 1000000;
6429+}
6430+
6431+/* Convert timespec to microseconds
6432+ *
6433+ * \param a timespec
6434+ * \return microseconds
6435+ *
6436+ * Rounding to integer microseconds happens always down (floor()).
6437+ */
6438+static inline int64_t
6439+timespec_to_usec(const struct timespec *a)
6440+{
6441+ return (int64_t)a->tv_sec * 1000000 + a->tv_nsec / 1000;
6442+}
6443+
6444+/* Convert timespec to protocol data
6445+ *
6446+ * \param a timespec
6447+ * \param tv_sec_hi[out] the high bytes of the seconds part
6448+ * \param tv_sec_lo[out] the low bytes of the seconds part
6449+ * \param tv_nsec[out] the nanoseconds part
6450+ *
6451+ * The input timespec must be normalized (the nanoseconds part should
6452+ * be less than 1 second) and non-negative.
6453+ */
6454+static inline void
6455+timespec_to_proto(const struct timespec *a, uint32_t *tv_sec_hi,
6456+ uint32_t *tv_sec_lo, uint32_t *tv_nsec)
6457+{
6458+ assert(a->tv_sec >= 0);
6459+ assert(a->tv_nsec >= 0 && a->tv_nsec < NSEC_PER_SEC);
6460+
6461+ uint64_t sec64 = a->tv_sec;
6462+
6463+ *tv_sec_hi = sec64 >> 32;
6464+ *tv_sec_lo = sec64 & 0xffffffff;
6465+ *tv_nsec = a->tv_nsec;
6466+}
6467+
6468+/* Convert nanoseconds to timespec
6469+ *
6470+ * \param a timespec
6471+ * \param b nanoseconds
6472+ */
6473+static inline void
6474+timespec_from_nsec(struct timespec *a, int64_t b)
6475+{
6476+ a->tv_sec = b / NSEC_PER_SEC;
6477+ a->tv_nsec = b % NSEC_PER_SEC;
6478+}
6479+
6480+/* Convert microseconds to timespec
6481+ *
6482+ * \param a timespec
6483+ * \param b microseconds
6484+ */
6485+static inline void
6486+timespec_from_usec(struct timespec *a, int64_t b)
6487+{
6488+ timespec_from_nsec(a, b * 1000);
6489+}
6490+
6491+/* Convert milliseconds to timespec
6492+ *
6493+ * \param a timespec
6494+ * \param b milliseconds
6495+ */
6496+static inline void
6497+timespec_from_msec(struct timespec *a, int64_t b)
6498+{
6499+ timespec_from_nsec(a, b * 1000000);
6500+}
6501+
6502+/* Convert protocol data to timespec
6503+ *
6504+ * \param a[out] timespec
6505+ * \param tv_sec_hi the high bytes of seconds part
6506+ * \param tv_sec_lo the low bytes of seconds part
6507+ * \param tv_nsec the nanoseconds part
6508+ */
6509+static inline void
6510+timespec_from_proto(struct timespec *a, uint32_t tv_sec_hi,
6511+ uint32_t tv_sec_lo, uint32_t tv_nsec)
6512+{
6513+ a->tv_sec = ((uint64_t)tv_sec_hi << 32) + tv_sec_lo;
6514+ a->tv_nsec = tv_nsec;
6515+}
6516+
6517+/* Check if a timespec is zero
6518+ *
6519+ * \param a timespec
6520+ * \return whether the timespec is zero
6521+ */
6522+static inline bool
6523+timespec_is_zero(const struct timespec *a)
6524+{
6525+ return a->tv_sec == 0 && a->tv_nsec == 0;
6526+}
6527+
6528+/* Check if two timespecs are equal
6529+ *
6530+ * \param a[in] timespec to check
6531+ * \param b[in] timespec to check
6532+ * \return whether timespecs a and b are equal
6533+ */
6534+static inline bool
6535+timespec_eq(const struct timespec *a, const struct timespec *b)
6536+{
6537+ return a->tv_sec == b->tv_sec &&
6538+ a->tv_nsec == b->tv_nsec;
6539+}
6540+
6541 /* Convert milli-Hertz to nanoseconds
6542 *
6543 * \param mhz frequency in mHz, not zero
6544--
65451.9.1
6546