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(®ion); 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(®ion, &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