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