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