xref: /OK3568_Linux_fs/buildroot/package/weston/0017-backend-drm-Support-mirror-mode.patch (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1From 4d890ce02a5fe7657140a2767cdd27b5a646cfa9 Mon Sep 17 00:00:00 2001
2From: Jeffy Chen <jeffy.chen@rock-chips.com>
3Date: Thu, 19 Nov 2020 09:41:47 +0800
4Subject: [PATCH 17/93] backend-drm: Support mirror mode
5
6Set env "WESTON_DRM_MIRROR" to enable mirror mode, and set env
7"WESTON_DRM_KEEP_RATIO" to keep the aspect ratio.
8
9Signed-off-by: Jeffy Chen <jeffy.chen@rock-chips.com>
10---
11 clients/desktop-shell.c               |   9 +-
12 desktop-shell/shell.c                 |   3 +
13 include/libweston/libweston.h         |   4 +
14 libweston/backend-drm/drm-gbm.c       |   4 +-
15 libweston/backend-drm/drm-internal.h  |  10 +
16 libweston/backend-drm/drm.c           | 332 +++++++++++++++++++++++++-
17 libweston/backend-drm/meson.build     |   3 +-
18 libweston/backend-drm/state-propose.c |  23 +-
19 libweston/compositor.c                |  24 +-
20 libweston/input.c                     |   7 +
21 meson.build                           |   5 +
22 11 files changed, 403 insertions(+), 21 deletions(-)
23
24diff --git a/clients/desktop-shell.c b/clients/desktop-shell.c
25index 6eb9775..2d2fd83 100644
26--- a/clients/desktop-shell.c
27+++ b/clients/desktop-shell.c
28@@ -1023,9 +1023,14 @@ desktop_shell_configure(void *data,
29 			struct wl_surface *surface,
30 			int32_t width, int32_t height)
31 {
32-	struct window *window = wl_surface_get_user_data(surface);
33-	struct surface *s = window_get_user_data(window);
34+	struct window *window;
35+	struct surface *s;
36+
37+	if (!surface)
38+		return;
39
40+	window = wl_surface_get_user_data(surface);
41+	s = window_get_user_data(window);
42 	s->configure(data, desktop_shell, edges, window, width, height);
43 }
44
45diff --git a/desktop-shell/shell.c b/desktop-shell/shell.c
46index 89ea491..7aa787c 100644
47--- a/desktop-shell/shell.c
48+++ b/desktop-shell/shell.c
49@@ -3857,6 +3857,9 @@ weston_view_set_initial_position(struct weston_view *view,
50 	}
51
52 	wl_list_for_each(output, &compositor->output_list, link) {
53+		if (output->unavailable)
54+			continue;
55+
56 		if (pixman_region32_contains_point(&output->region, ix, iy, NULL)) {
57 			target_output = output;
58 			break;
59diff --git a/include/libweston/libweston.h b/include/libweston/libweston.h
60index d35963f..a8ec105 100644
61--- a/include/libweston/libweston.h
62+++ b/include/libweston/libweston.h
63@@ -573,7 +573,11 @@ struct weston_output {
64 	 */
65 	void (*detach_head)(struct weston_output *output,
66 			    struct weston_head *head);
67+
68+	bool unavailable;
69 };
70+#define weston_output_valid(o) \
71+	((o) && !(o)->destroying && !(o)->unavailable)
72
73 enum weston_pointer_motion_mask {
74 	WESTON_POINTER_MOTION_ABS = 1 << 0,
75diff --git a/libweston/backend-drm/drm-gbm.c b/libweston/backend-drm/drm-gbm.c
76index 76fa79f..d10cc40 100644
77--- a/libweston/backend-drm/drm-gbm.c
78+++ b/libweston/backend-drm/drm-gbm.c
79@@ -275,8 +275,8 @@ drm_output_fini_egl(struct drm_output *output)
80 	/* Destroying the GBM surface will destroy all our GBM buffers,
81 	 * regardless of refcount. Ensure we destroy them here. */
82 	if (!b->shutting_down &&
83-	    output->scanout_plane->state_cur->fb &&
84-	    output->scanout_plane->state_cur->fb->type == BUFFER_GBM_SURFACE) {
85+	    output->scanout_plane->state_cur->fb && (output->is_mirror ||
86+	    output->scanout_plane->state_cur->fb->type == BUFFER_GBM_SURFACE)) {
87 		drm_plane_reset_state(output->scanout_plane);
88 	}
89
90diff --git a/libweston/backend-drm/drm-internal.h b/libweston/backend-drm/drm-internal.h
91index af82922..037c937 100644
92--- a/libweston/backend-drm/drm-internal.h
93+++ b/libweston/backend-drm/drm-internal.h
94@@ -362,6 +362,8 @@ struct drm_backend {
95
96 	int virtual_width;
97 	int virtual_height;
98+
99+	bool mirror_mode;
100 };
101
102 struct drm_mode {
103@@ -617,6 +619,10 @@ struct drm_output {
104 	int current_image;
105 	pixman_region32_t previous_damage;
106
107+	/* Wrap fb for scale/rotate usage */
108+	struct drm_fb *wrap[2];
109+	int next_wrap;
110+
111 	struct vaapi_recorder *recorder;
112 	struct wl_listener recorder_frame_listener;
113
114@@ -631,6 +637,10 @@ struct drm_output {
115
116 	/* The dummy framebuffer for SET_CRTC. */
117 	struct drm_fb *fb_dummy;
118+
119+	bool is_mirror;
120+
121+	pixman_box32_t plane_bounds;
122 };
123
124 void
125diff --git a/libweston/backend-drm/drm.c b/libweston/backend-drm/drm.c
126index a2f215f..ec7e9be 100644
127--- a/libweston/backend-drm/drm.c
128+++ b/libweston/backend-drm/drm.c
129@@ -68,6 +68,11 @@
130 #include "linux-dmabuf-unstable-v1-server-protocol.h"
131 #include "linux-explicit-synchronization.h"
132
133+#ifdef HAVE_RGA
134+#include <rga/rga.h>
135+#include <rga/RgaApi.h>
136+#endif
137+
138 static const char default_seat[] = "seat0";
139
140 static inline bool
141@@ -86,6 +91,120 @@ drm_head_is_external(struct drm_head *head)
142 	}
143 };
144
145+static int
146+drm_output_get_rotation(struct drm_output *output)
147+{
148+	switch (output->base.transform) {
149+	case WL_OUTPUT_TRANSFORM_90:
150+	case WL_OUTPUT_TRANSFORM_FLIPPED_90:
151+		return 90;
152+	case WL_OUTPUT_TRANSFORM_180:
153+	case WL_OUTPUT_TRANSFORM_FLIPPED_180:
154+		return 180;
155+	case WL_OUTPUT_TRANSFORM_270:
156+	case WL_OUTPUT_TRANSFORM_FLIPPED_270:
157+		return 270;
158+	default:
159+		return 0;
160+	}
161+}
162+
163+#ifdef HAVE_RGA
164+static inline RgaSURF_FORMAT
165+rga_get_format(const struct pixel_format_info *format)
166+{
167+	switch (format->format) {
168+	case DRM_FORMAT_XRGB8888:
169+		return RK_FORMAT_BGRX_8888;
170+	case DRM_FORMAT_ARGB8888:
171+		return RK_FORMAT_BGRA_8888;
172+	case DRM_FORMAT_RGB565:
173+		return RK_FORMAT_RGB_565;
174+	default:
175+		return RK_FORMAT_UNKNOWN;
176+	}
177+}
178+#endif
179+
180+static int
181+drm_copy_fb(struct drm_fb *src, struct drm_fb *dst, int rotation,
182+	    int src_width, int src_height)
183+{
184+#ifndef HAVE_RGA
185+	/* TODO: Use pixman to do the copy */
186+	weston_log("rga not supported\n");
187+	return -1;
188+#else
189+	RgaSURF_FORMAT src_format, dst_format;
190+	rga_info_t src_info = {0};
191+	rga_info_t dst_info = {0};
192+	int src_fd, dst_fd;
193+	int ret;
194+
195+	static bool rga_supported = true;
196+	static bool rga_inited = false;
197+
198+	if (!rga_supported)
199+		return -1;
200+
201+	if (!rga_inited) {
202+		ret = c_RkRgaInit();
203+		if (ret < 0) {
204+			weston_log("rga not supported\n");
205+			rga_supported = false;
206+			return ret;
207+		}
208+		rga_inited = true;
209+	}
210+
211+	src_format = rga_get_format(src->format);
212+	dst_format = rga_get_format(dst->format);
213+
214+	if (src_format == RK_FORMAT_UNKNOWN ||
215+	    dst_format == RK_FORMAT_UNKNOWN) {
216+		weston_log("unsupported fb format\n");
217+		return -1;
218+	}
219+
220+	ret = drmPrimeHandleToFD(src->fd, src->handles[0],
221+				 DRM_CLOEXEC, &src_fd);
222+	if (ret < 0)
223+		return ret;
224+
225+	ret = drmPrimeHandleToFD(dst->fd, dst->handles[0],
226+				 DRM_CLOEXEC, &dst_fd);
227+	if (ret < 0)
228+		goto close_src;
229+
230+	src_info.fd = src_fd;
231+	src_info.mmuFlag = 1;
232+
233+	rga_set_rect(&src_info.rect, 0, 0, src_width, src_height,
234+		     src->strides[0] * 8 / src->format->bpp, src->height,
235+		     src_format);
236+
237+	if (rotation == 90)
238+		src_info.rotation = HAL_TRANSFORM_ROT_90;
239+	else if (rotation == 180)
240+		src_info.rotation = HAL_TRANSFORM_ROT_180;
241+	else if (rotation == 270)
242+		src_info.rotation = HAL_TRANSFORM_ROT_270;
243+
244+	dst_info.fd = dst_fd;
245+	dst_info.mmuFlag = 1;
246+
247+	rga_set_rect(&dst_info.rect, 0, 0, dst->width, dst->height,
248+		     dst->strides[0] * 8 / dst->format->bpp, dst->height,
249+		     dst_format);
250+
251+	ret = c_RkRgaBlit(&src_info, &dst_info, NULL);
252+	close(dst_fd);
253+close_src:
254+	close(src_fd);
255+	return ret;
256+#endif
257+}
258+
259 static void
260 drm_backend_update_outputs(struct drm_backend *b)
261 {
262@@ -95,6 +214,28 @@ drm_backend_update_outputs(struct drm_backend *b)
263 		return;
264
265 	primary = b->primary_head->base.output;
266+
267+	if (b->mirror_mode) {
268+		struct weston_output *base;
269+
270+		wl_list_for_each(base, &b->compositor->output_list, link) {
271+			struct drm_output *output = to_drm_output(base);
272+			bool is_mirror = base != primary;
273+
274+			if (output->is_mirror == is_mirror)
275+				continue;
276+
277+			/* Make mirrors unavailable for normal views */
278+			output->base.unavailable = is_mirror;
279+
280+			output->is_mirror = is_mirror;
281+			output->state_invalid = true;
282+
283+			weston_log("Output %s changed to %s output\n",
284+				   base->name, is_mirror ? "mirror" : "main");
285+		}
286+	}
287+
288 	if (!primary)
289 		return;
290
291@@ -405,6 +546,69 @@ drm_output_render_pixman(struct drm_output_state *state,
292 	return drm_fb_ref(output->dumb[output->current_image]);
293 }
294
295+static struct drm_fb *
296+drm_output_get_fb(struct drm_pending_state *pending_state,
297+		  struct weston_output *output_base)
298+{
299+	struct drm_output *output = to_drm_output(output_base);
300+	struct drm_plane_state *scanout_state;
301+	struct drm_output_state *state;
302+	struct drm_fb *fb = output->scanout_plane->state_cur->fb;
303+
304+	state = drm_pending_state_get_output(pending_state, output);
305+	if (!state)
306+		return fb;
307+
308+	scanout_state =
309+		drm_output_state_get_existing_plane(state,
310+						    output->scanout_plane);
311+	if (!scanout_state || !scanout_state->fb)
312+		return fb;
313+
314+	return scanout_state->fb;
315+}
316+
317+static void
318+drm_output_try_destroy_wrap_fb(struct drm_output *output)
319+{
320+	if (output->wrap[0]) {
321+		drm_fb_unref(output->wrap[0]);
322+		output->wrap[0] = NULL;
323+	}
324+
325+	if (output->wrap[1]) {
326+		drm_fb_unref(output->wrap[1]);
327+		output->wrap[1] = NULL;
328+	}
329+
330+	output->next_wrap = 0;
331+}
332+
333+static struct drm_fb *
334+drm_output_get_wrap_fb(struct drm_backend *b, struct drm_output *output,
335+		       int width, int height)
336+{
337+	struct drm_fb *fb = output->wrap[output->next_wrap];
338+
339+	if (fb) {
340+		if (fb->width == width && fb->height == height)
341+			goto out;
342+
343+		drm_fb_unref(fb);
344+	}
345+
346+	fb = drm_fb_create_dumb(b->drm, width, height, output->gbm_format);
347+	if (!fb) {
348+		weston_log("failed to create wrap fb\n");
349+		return NULL;
350+	}
351+
352+	output->wrap[output->next_wrap] = fb;
353+out:
354+	output->next_wrap ^= 1;
355+	return drm_fb_ref(fb);
356+}
357+
358 void
359 drm_output_render(struct drm_output_state *state, pixman_region32_t *damage)
360 {
361@@ -417,10 +621,13 @@ drm_output_render(struct drm_output_state *state, pixman_region32_t *damage)
362 		&scanout_plane->props[WDRM_PLANE_FB_DAMAGE_CLIPS];
363 	struct drm_backend *b = device->backend;
364 	struct drm_mode *mode;
365-	struct drm_fb *fb;
366+	struct drm_fb *fb = NULL;
367 	pixman_region32_t scanout_damage;
368 	pixman_box32_t *rects;
369 	int n_rects;
370+	int sw, sh, dx, dy, dw, dh;
371+	int rotation = 0;
372+	bool scaling;
373
374 	/* If we already have a client buffer promoted to scanout, then we don't
375 	 * want to render. */
376@@ -428,6 +635,35 @@ drm_output_render(struct drm_output_state *state, pixman_region32_t *damage)
377 	if (scanout_state->fb)
378 		return;
379
380+	if (!output->is_mirror) {
381+		struct drm_output *tmp;
382+
383+		/* Repaint all mirrors when updating main output */
384+		wl_list_for_each(tmp, &b->compositor->output_list, base.link)
385+			if (tmp->is_mirror)
386+				weston_output_schedule_repaint(&tmp->base);
387+	} else {
388+		if (!b->primary_head)
389+			goto out;
390+
391+		rotation = drm_output_get_rotation(output);
392+
393+		fb = drm_output_get_fb(state->pending_state,
394+				       b->primary_head->base.output);
395+		if (fb) {
396+			drm_fb_ref(fb);
397+
398+			pixman_region32_init(&scanout_damage);
399+			wl_signal_emit(&output->base.frame_signal,
400+				       &scanout_damage);
401+			pixman_region32_fini(&scanout_damage);
402+		} else {
403+			weston_compositor_damage_all(b->compositor);
404+		}
405+
406+		goto out;
407+	}
408+
409 	/*
410 	 * If we don't have any damage on the primary plane, and we already
411 	 * have a renderer buffer active, we can reuse it; else we pass
412@@ -447,24 +683,86 @@ drm_output_render(struct drm_output_state *state, pixman_region32_t *damage)
413 		fb = drm_output_render_gl(state, damage);
414 	}
415
416+out:
417 	if (!fb) {
418 		drm_plane_state_put_back(scanout_state);
419 		return;
420 	}
421
422+	sw = fb->width;
423+	sh = fb->height;
424+
425+	dx = output->plane_bounds.x1;
426+	dy = output->plane_bounds.y1;
427+	dw = output->plane_bounds.x2 - output->plane_bounds.x1;
428+	dh = output->plane_bounds.y2 - output->plane_bounds.y1;
429+
430+	if (!dw || !dh) {
431+		mode = to_drm_mode(output->base.current_mode);
432+		dw = mode->mode_info.hdisplay;
433+		dh = mode->mode_info.vdisplay;
434+	}
435+
436+	if (output->is_mirror && getenv("WESTON_DRM_KEEP_RATIO")) {
437+		float src_ratio = (float) sw / sh;
438+		float dst_ratio = (float) dw / dh;
439+		int offset;
440+
441+		if (rotation % 180)
442+			src_ratio = 1 / src_ratio;
443+
444+		if (src_ratio > dst_ratio) {
445+			offset = dh - dw / src_ratio;
446+			dy = offset / 2;
447+			dh -= offset;
448+		} else {
449+			offset = dw - dh * src_ratio;
450+			dx = offset / 2;
451+			dw -= offset;
452+		}
453+	}
454+
455+	scaling = sw != dw || sh != dh;
456+
457+	if (rotation || (scaling && !output->scanout_plane->can_scale)) {
458+		struct drm_fb *wrap_fb =
459+			drm_output_get_wrap_fb(b, output, dw, dh);
460+		if (!wrap_fb) {
461+			weston_log("failed to get wrap fb\n");
462+			goto err;
463+		}
464+
465+		if (drm_copy_fb(fb, wrap_fb, rotation, sw, sh) < 0) {
466+			weston_log("failed to copy fb\n");
467+			goto err;
468+		}
469+
470+		sw = dw;
471+		sh = dh;
472+
473+		drm_fb_unref(fb);
474+		fb = wrap_fb;
475+	} else {
476+		drm_output_try_destroy_wrap_fb(output);
477+	}
478+
479 	scanout_state->fb = fb;
480+	fb = NULL;
481+
482 	scanout_state->output = output;
483
484 	scanout_state->src_x = 0;
485 	scanout_state->src_y = 0;
486-	scanout_state->src_w = fb->width << 16;
487-	scanout_state->src_h = fb->height << 16;
488+	scanout_state->src_w = sw << 16;
489+	scanout_state->src_h = sh << 16;
490
491-	mode = to_drm_mode(output->base.current_mode);
492-	scanout_state->dest_x = 0;
493-	scanout_state->dest_y = 0;
494-	scanout_state->dest_w = mode->mode_info.hdisplay;
495-	scanout_state->dest_h = mode->mode_info.vdisplay;
496+	scanout_state->dest_x = dx;
497+	scanout_state->dest_y = dy;
498+	scanout_state->dest_w = dw;
499+	scanout_state->dest_h = dh;
500+
501+	if (output->is_mirror)
502+		return;
503
504 	pixman_region32_subtract(&c->primary_plane.damage,
505 				 &c->primary_plane.damage, damage);
506@@ -500,6 +798,12 @@ drm_output_render(struct drm_output_state *state, pixman_region32_t *damage)
507 				  &scanout_state->damage_blob_id);
508
509 	pixman_region32_fini(&scanout_damage);
510+	return;
511+err:
512+	if (fb)
513+		drm_fb_unref(fb);
514+
515+	drm_plane_state_put_back(scanout_state);
516 }
517
518 static int
519@@ -1347,8 +1651,8 @@ drm_output_fini_pixman(struct drm_output *output)
520 	/* Destroying the Pixman surface will destroy all our buffers,
521 	 * regardless of refcount. Ensure we destroy them here. */
522 	if (!b->shutting_down &&
523-	    output->scanout_plane->state_cur->fb &&
524-	    output->scanout_plane->state_cur->fb->type == BUFFER_PIXMAN_DUMB) {
525+	    output->scanout_plane->state_cur->fb && (output->is_mirror ||
526+	    output->scanout_plane->state_cur->fb->type == BUFFER_PIXMAN_DUMB)) {
527 		drm_plane_reset_state(output->scanout_plane);
528 	}
529
530@@ -2067,6 +2371,8 @@ drm_output_destroy(struct weston_output *base)
531
532 	assert(output->hdr_output_metadata_blob_id == 0);
533
534+	drm_output_try_destroy_wrap_fb(output);
535+
536 	free(output);
537 }
538
539@@ -3442,6 +3748,12 @@ drm_backend_create(struct weston_compositor *compositor,
540 	else
541 		b->resize_freeze_ms = DRM_RESIZE_FREEZE_MS;
542
543+	buf = getenv("WESTON_DRM_MIRROR");
544+	if (buf && buf[0] == '1') {
545+		b->mirror_mode = true;
546+		weston_log("Entering mirror mode.\n");
547+	}
548+
549 	device = zalloc(sizeof *device);
550 	if (device == NULL)
551 		return NULL;
552diff --git a/libweston/backend-drm/meson.build b/libweston/backend-drm/meson.build
553index bf7ce33..92ca921 100644
554--- a/libweston/backend-drm/meson.build
555+++ b/libweston/backend-drm/meson.build
556@@ -40,7 +40,8 @@ deps_drm = [
557 	dep_libdrm,
558 	dep_libinput_backend,
559 	dependency('libudev', version: '>= 136'),
560-	dep_backlight
561+	dep_backlight,
562+	dep_rga
563 ]
564
565 if get_option('renderer-gl')
566diff --git a/libweston/backend-drm/state-propose.c b/libweston/backend-drm/state-propose.c
567index 967b6bd..69d49bc 100644
568--- a/libweston/backend-drm/state-propose.c
569+++ b/libweston/backend-drm/state-propose.c
570@@ -55,6 +55,21 @@ static const char *const drm_output_propose_state_mode_as_string[] = {
571 	[DRM_OUTPUT_PROPOSE_STATE_PLANES_ONLY]	= "plane-only state"
572 };
573
574+static bool
575+drm_is_mirroring(struct drm_backend *b)
576+{
577+	struct drm_output *tmp;
578+
579+	if (!b->mirror_mode)
580+		return false;
581+
582+	wl_list_for_each(tmp, &b->compositor->output_list, base.link)
583+		if (tmp->is_mirror)
584+			return true;
585+
586+	return false;
587+}
588+
589 static const char *
590 drm_propose_state_mode_to_string(enum drm_output_propose_state_mode mode)
591 {
592@@ -459,7 +474,8 @@ drm_output_find_plane_for_view(struct drm_output_state *state,
593 			FAILURE_REASONS_FB_FORMAT_INCOMPATIBLE;
594 		return NULL;
595 	} else if (buffer->type == WESTON_BUFFER_SHM) {
596-		if (!output->cursor_plane || device->cursors_are_broken) {
597+		if (!output->cursor_plane || device->cursors_are_broken ||
598+		    drm_is_mirroring(b)) {
599 			pnode->try_view_on_plane_failure_reasons |=
600 				FAILURE_REASONS_FB_FORMAT_INCOMPATIBLE;
601 			return NULL;
602@@ -932,7 +948,10 @@ drm_assign_planes(struct weston_output *output_base)
603 	drm_debug(b, "\t[repaint] preparing state for output %s (%lu)\n",
604 		  output_base->name, (unsigned long) output_base->id);
605
606-	if (!device->sprites_are_broken && !output->virtual && b->gbm) {
607+	/* Force single plane in mirror mode */
608+	if (drm_is_mirroring(b)) {
609+		drm_debug(b, "\t[state] no overlay plane in mirror mode\n");
610+	} else if (!device->sprites_are_broken && !output->virtual && b->gbm) {
611 		drm_debug(b, "\t[repaint] trying planes-only build state\n");
612 		state = drm_output_propose_state(output_base, pending_state, mode);
613 		if (!state) {
614diff --git a/libweston/compositor.c b/libweston/compositor.c
615index 2125f1a..eea8da2 100644
616--- a/libweston/compositor.c
617+++ b/libweston/compositor.c
618@@ -1426,7 +1426,7 @@ weston_view_assign_output(struct weston_view *ev)
619 	mask = 0;
620 	pixman_region32_init(&region);
621 	wl_list_for_each(output, &ec->output_list, link) {
622-		if (output->destroying)
623+		if (!weston_output_valid(output))
624 			continue;
625
626 		pixman_region32_intersect(&region, &ev->transform.boundingbox,
627@@ -5660,6 +5660,9 @@ bind_output(struct wl_client *client,
628 static void
629 weston_head_add_global(struct weston_head *head)
630 {
631+	if (head->global || !weston_output_valid(head->output))
632+		return;
633+
634 	head->global = wl_global_create(head->compositor->wl_display,
635 					&wl_output_interface, 3,
636 					head, bind_output);
637@@ -5695,6 +5698,15 @@ weston_head_remove_global(struct weston_head *head)
638 	wl_list_init(&head->xdg_output_resource_list);
639 }
640
641+static void
642+weston_head_update_global(struct weston_head *head)
643+{
644+	if (weston_output_valid(head->output))
645+		weston_head_add_global(head);
646+	else
647+		weston_head_remove_global(head);
648+}
649+
650 /** Get the backing object of wl_output
651  *
652  * \param resource A wl_output protocol object.
653@@ -6521,6 +6533,7 @@ WL_EXPORT void
654 weston_compositor_reflow_outputs(struct weston_compositor *compositor)
655 {
656 	struct weston_output *output;
657+	struct weston_head *head;
658 	int x, y, next_x, next_y;
659
660 	if (compositor->output_flow_dirty)
661@@ -6528,7 +6541,10 @@ weston_compositor_reflow_outputs(struct weston_compositor *compositor)
662
663 	next_x = next_y = 0;
664 	wl_list_for_each(output, &compositor->output_list, link) {
665-		if (output->destroying)
666+		wl_list_for_each(head, &output->head_list, output_link)
667+			weston_head_update_global(head);
668+
669+		if (!weston_output_valid(output))
670 			continue;
671
672 		x = next_x;
673@@ -6743,11 +6759,11 @@ weston_compositor_add_output(struct weston_compositor *compositor,
674 	wl_list_insert(compositor->output_list.prev, &output->link);
675 	output->enabled = true;
676
677+	wl_signal_emit(&compositor->output_created_signal, output);
678+
679 	wl_list_for_each(head, &output->head_list, output_link)
680 		weston_head_add_global(head);
681
682-	wl_signal_emit(&compositor->output_created_signal, output);
683-
684 	/*
685 	 * Use view_list, as paint nodes have not been created for this
686 	 * output yet. Any existing view might touch this new output.
687diff --git a/libweston/input.c b/libweston/input.c
688index 235cf02..8c9cabc 100644
689--- a/libweston/input.c
690+++ b/libweston/input.c
691@@ -1733,6 +1733,10 @@ weston_pointer_clamp(struct weston_pointer *pointer, wl_fixed_t *fx, wl_fixed_t
692 	wl_list_for_each(output, &ec->output_list, link) {
693 		if (pointer->seat->output && pointer->seat->output != output)
694 			continue;
695+
696+		if (output->unavailable)
697+			continue;
698+
699 		if (pixman_region32_contains_point(&output->region,
700 						   x, y, NULL))
701 			valid = 1;
702@@ -1802,6 +1806,9 @@ weston_pointer_handle_output_destroy(struct wl_listener *listener, void *data)
703 	y = wl_fixed_to_int(pointer->y);
704
705 	wl_list_for_each(output, &ec->output_list, link) {
706+		if (output->unavailable)
707+			continue;
708+
709 		if (pixman_region32_contains_point(&output->region,
710 						   x, y, NULL))
711 			return;
712diff --git a/meson.build b/meson.build
713index 82119ac..46e57e2 100644
714--- a/meson.build
715+++ b/meson.build
716@@ -141,6 +141,11 @@ if dep_xkbcommon.version().version_compare('>= 0.5.0')
717 	config_h.set('HAVE_XKBCOMMON_COMPOSE', '1')
718 endif
719
720+dep_rga = dependency('librga', required: false)
721+if dep_rga.found()
722+	config_h.set('HAVE_RGA', '1')
723+endif
724+
725 dep_wayland_server = dependency('wayland-server', version: '>= 1.20.0')
726 dep_wayland_client = dependency('wayland-client', version: '>= 1.20.0')
727 dep_pixman = dependency('pixman-1', version: '>= 0.25.2')
728--
7292.20.1
730
731