1From cbb008443c4aebfedcb608144fb8decbecc0685b 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 | 330 +++++++++++++++++++++++++- 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, 401 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..159abee 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,118 @@ 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->bpp) { 168+ case 32: 169+ return RK_FORMAT_BGRX_8888; 170+ case 16: 171+ return RK_FORMAT_RGB_565; 172+ default: 173+ return RK_FORMAT_UNKNOWN; 174+ } 175+} 176+#endif 177+ 178+static int 179+drm_copy_fb(struct drm_fb *src, struct drm_fb *dst, int rotation, 180+ int src_width, int src_height) 181+{ 182+#ifndef HAVE_RGA 183+ /* TODO: Use pixman to do the copy */ 184+ weston_log("rga not supported\n"); 185+ return -1; 186+#else 187+ RgaSURF_FORMAT src_format, dst_format; 188+ rga_info_t src_info = {0}; 189+ rga_info_t dst_info = {0}; 190+ int src_fd, dst_fd; 191+ int ret; 192+ 193+ static bool rga_supported = true; 194+ static bool rga_inited = false; 195+ 196+ if (!rga_supported) 197+ return -1; 198+ 199+ if (!rga_inited) { 200+ ret = c_RkRgaInit(); 201+ if (ret < 0) { 202+ weston_log("rga not supported\n"); 203+ rga_supported = false; 204+ return ret; 205+ } 206+ rga_inited = true; 207+ } 208+ 209+ src_format = rga_get_format(src->format); 210+ dst_format = rga_get_format(dst->format); 211+ 212+ if (src_format == RK_FORMAT_UNKNOWN || 213+ dst_format == RK_FORMAT_UNKNOWN) { 214+ weston_log("unsupported fb format\n"); 215+ return -1; 216+ } 217+ 218+ ret = drmPrimeHandleToFD(src->fd, src->handles[0], 219+ DRM_CLOEXEC, &src_fd); 220+ if (ret < 0) 221+ return ret; 222+ 223+ ret = drmPrimeHandleToFD(dst->fd, dst->handles[0], 224+ DRM_CLOEXEC, &dst_fd); 225+ if (ret < 0) 226+ goto close_src; 227+ 228+ src_info.fd = src_fd; 229+ src_info.mmuFlag = 1; 230+ 231+ rga_set_rect(&src_info.rect, 0, 0, src_width, src_height, 232+ src->strides[0] * 8 / src->format->bpp, src->height, 233+ src_format); 234+ 235+ if (rotation == 90) 236+ src_info.rotation = HAL_TRANSFORM_ROT_90; 237+ else if (rotation == 180) 238+ src_info.rotation = HAL_TRANSFORM_ROT_180; 239+ else if (rotation == 270) 240+ src_info.rotation = HAL_TRANSFORM_ROT_270; 241+ 242+ dst_info.fd = dst_fd; 243+ dst_info.mmuFlag = 1; 244+ 245+ rga_set_rect(&dst_info.rect, 0, 0, dst->width, dst->height, 246+ dst->strides[0] * 8 / dst->format->bpp, dst->height, 247+ dst_format); 248+ 249+ ret = c_RkRgaBlit(&src_info, &dst_info, NULL); 250+ close(dst_fd); 251+close_src: 252+ close(src_fd); 253+ return ret; 254+#endif 255+} 256+ 257 static void 258 drm_backend_update_outputs(struct drm_backend *b) 259 { 260@@ -95,6 +212,28 @@ drm_backend_update_outputs(struct drm_backend *b) 261 return; 262 263 primary = b->primary_head->base.output; 264+ 265+ if (b->mirror_mode) { 266+ struct weston_output *base; 267+ 268+ wl_list_for_each(base, &b->compositor->output_list, link) { 269+ struct drm_output *output = to_drm_output(base); 270+ bool is_mirror = base != primary; 271+ 272+ if (output->is_mirror == is_mirror) 273+ continue; 274+ 275+ /* Make mirrors unavailable for normal views */ 276+ output->base.unavailable = is_mirror; 277+ 278+ output->is_mirror = is_mirror; 279+ output->state_invalid = true; 280+ 281+ weston_log("Output %s changed to %s output\n", 282+ base->name, is_mirror ? "mirror" : "main"); 283+ } 284+ } 285+ 286 if (!primary) 287 return; 288 289@@ -405,6 +544,69 @@ drm_output_render_pixman(struct drm_output_state *state, 290 return drm_fb_ref(output->dumb[output->current_image]); 291 } 292 293+static struct drm_fb * 294+drm_output_get_fb(struct drm_pending_state *pending_state, 295+ struct weston_output *output_base) 296+{ 297+ struct drm_output *output = to_drm_output(output_base); 298+ struct drm_plane_state *scanout_state; 299+ struct drm_output_state *state; 300+ struct drm_fb *fb = output->scanout_plane->state_cur->fb; 301+ 302+ state = drm_pending_state_get_output(pending_state, output); 303+ if (!state) 304+ return fb; 305+ 306+ scanout_state = 307+ drm_output_state_get_existing_plane(state, 308+ output->scanout_plane); 309+ if (!scanout_state || !scanout_state->fb) 310+ return fb; 311+ 312+ return scanout_state->fb; 313+} 314+ 315+static void 316+drm_output_try_destroy_wrap_fb(struct drm_output *output) 317+{ 318+ if (output->wrap[0]) { 319+ drm_fb_unref(output->wrap[0]); 320+ output->wrap[0] = NULL; 321+ } 322+ 323+ if (output->wrap[1]) { 324+ drm_fb_unref(output->wrap[1]); 325+ output->wrap[1] = NULL; 326+ } 327+ 328+ output->next_wrap = 0; 329+} 330+ 331+static struct drm_fb * 332+drm_output_get_wrap_fb(struct drm_backend *b, struct drm_output *output, 333+ int width, int height) 334+{ 335+ struct drm_fb *fb = output->wrap[output->next_wrap]; 336+ 337+ if (fb) { 338+ if (fb->width == width && fb->height == height) 339+ goto out; 340+ 341+ drm_fb_unref(fb); 342+ } 343+ 344+ fb = drm_fb_create_dumb(b->drm, width, height, output->gbm_format); 345+ if (!fb) { 346+ weston_log("failed to create wrap fb\n"); 347+ return NULL; 348+ } 349+ 350+ output->wrap[output->next_wrap] = fb; 351+out: 352+ output->next_wrap ^= 1; 353+ return drm_fb_ref(fb); 354+} 355+ 356 void 357 drm_output_render(struct drm_output_state *state, pixman_region32_t *damage) 358 { 359@@ -417,10 +619,13 @@ drm_output_render(struct drm_output_state *state, pixman_region32_t *damage) 360 &scanout_plane->props[WDRM_PLANE_FB_DAMAGE_CLIPS]; 361 struct drm_backend *b = device->backend; 362 struct drm_mode *mode; 363- struct drm_fb *fb; 364+ struct drm_fb *fb = NULL; 365 pixman_region32_t scanout_damage; 366 pixman_box32_t *rects; 367 int n_rects; 368+ int sw, sh, dx, dy, dw, dh; 369+ int rotation = 0; 370+ bool scaling; 371 372 /* If we already have a client buffer promoted to scanout, then we don't 373 * want to render. */ 374@@ -428,6 +633,35 @@ drm_output_render(struct drm_output_state *state, pixman_region32_t *damage) 375 if (scanout_state->fb) 376 return; 377 378+ if (!output->is_mirror) { 379+ struct drm_output *tmp; 380+ 381+ /* Repaint all mirrors when updating main output */ 382+ wl_list_for_each(tmp, &b->compositor->output_list, base.link) 383+ if (tmp->is_mirror) 384+ weston_output_schedule_repaint(&tmp->base); 385+ } else { 386+ if (!b->primary_head) 387+ goto out; 388+ 389+ rotation = drm_output_get_rotation(output); 390+ 391+ fb = drm_output_get_fb(state->pending_state, 392+ b->primary_head->base.output); 393+ if (fb) { 394+ drm_fb_ref(fb); 395+ 396+ pixman_region32_init(&scanout_damage); 397+ wl_signal_emit(&output->base.frame_signal, 398+ &scanout_damage); 399+ pixman_region32_fini(&scanout_damage); 400+ } else { 401+ weston_compositor_damage_all(b->compositor); 402+ } 403+ 404+ goto out; 405+ } 406+ 407 /* 408 * If we don't have any damage on the primary plane, and we already 409 * have a renderer buffer active, we can reuse it; else we pass 410@@ -447,24 +681,86 @@ drm_output_render(struct drm_output_state *state, pixman_region32_t *damage) 411 fb = drm_output_render_gl(state, damage); 412 } 413 414+out: 415 if (!fb) { 416 drm_plane_state_put_back(scanout_state); 417 return; 418 } 419 420+ sw = fb->width; 421+ sh = fb->height; 422+ 423+ dx = output->plane_bounds.x1; 424+ dy = output->plane_bounds.y1; 425+ dw = output->plane_bounds.x2 - output->plane_bounds.x1; 426+ dh = output->plane_bounds.y2 - output->plane_bounds.y1; 427+ 428+ if (!dw || !dh) { 429+ mode = to_drm_mode(output->base.current_mode); 430+ dw = mode->mode_info.hdisplay; 431+ dh = mode->mode_info.vdisplay; 432+ } 433+ 434+ if (output->is_mirror && getenv("WESTON_DRM_KEEP_RATIO")) { 435+ float src_ratio = (float) sw / sh; 436+ float dst_ratio = (float) dw / dh; 437+ int offset; 438+ 439+ if (rotation % 180) 440+ src_ratio = 1 / src_ratio; 441+ 442+ if (src_ratio > dst_ratio) { 443+ offset = dh - dw / src_ratio; 444+ dy = offset / 2; 445+ dh -= offset; 446+ } else { 447+ offset = dw - dh * src_ratio; 448+ dx = offset / 2; 449+ dw -= offset; 450+ } 451+ } 452+ 453+ scaling = sw != dw || sh != dh; 454+ 455+ if (rotation || (scaling && !output->scanout_plane->can_scale)) { 456+ struct drm_fb *wrap_fb = 457+ drm_output_get_wrap_fb(b, output, dw, dh); 458+ if (!wrap_fb) { 459+ weston_log("failed to get wrap fb\n"); 460+ goto err; 461+ } 462+ 463+ if (drm_copy_fb(fb, wrap_fb, rotation, sw, sh) < 0) { 464+ weston_log("failed to copy fb\n"); 465+ goto err; 466+ } 467+ 468+ sw = dw; 469+ sh = dh; 470+ 471+ drm_fb_unref(fb); 472+ fb = wrap_fb; 473+ } else { 474+ drm_output_try_destroy_wrap_fb(output); 475+ } 476+ 477 scanout_state->fb = fb; 478+ fb = NULL; 479+ 480 scanout_state->output = output; 481 482 scanout_state->src_x = 0; 483 scanout_state->src_y = 0; 484- scanout_state->src_w = fb->width << 16; 485- scanout_state->src_h = fb->height << 16; 486+ scanout_state->src_w = sw << 16; 487+ scanout_state->src_h = sh << 16; 488 489- mode = to_drm_mode(output->base.current_mode); 490- scanout_state->dest_x = 0; 491- scanout_state->dest_y = 0; 492- scanout_state->dest_w = mode->mode_info.hdisplay; 493- scanout_state->dest_h = mode->mode_info.vdisplay; 494+ scanout_state->dest_x = dx; 495+ scanout_state->dest_y = dy; 496+ scanout_state->dest_w = dw; 497+ scanout_state->dest_h = dh; 498+ 499+ if (output->is_mirror) 500+ return; 501 502 pixman_region32_subtract(&c->primary_plane.damage, 503 &c->primary_plane.damage, damage); 504@@ -500,6 +796,12 @@ drm_output_render(struct drm_output_state *state, pixman_region32_t *damage) 505 &scanout_state->damage_blob_id); 506 507 pixman_region32_fini(&scanout_damage); 508+ return; 509+err: 510+ if (fb) 511+ drm_fb_unref(fb); 512+ 513+ drm_plane_state_put_back(scanout_state); 514 } 515 516 static int 517@@ -1347,8 +1649,8 @@ drm_output_fini_pixman(struct drm_output *output) 518 /* Destroying the Pixman surface will destroy all our buffers, 519 * regardless of refcount. Ensure we destroy them here. */ 520 if (!b->shutting_down && 521- output->scanout_plane->state_cur->fb && 522- output->scanout_plane->state_cur->fb->type == BUFFER_PIXMAN_DUMB) { 523+ output->scanout_plane->state_cur->fb && (output->is_mirror || 524+ output->scanout_plane->state_cur->fb->type == BUFFER_PIXMAN_DUMB)) { 525 drm_plane_reset_state(output->scanout_plane); 526 } 527 528@@ -2067,6 +2369,8 @@ drm_output_destroy(struct weston_output *base) 529 530 assert(output->hdr_output_metadata_blob_id == 0); 531 532+ drm_output_try_destroy_wrap_fb(output); 533+ 534 free(output); 535 } 536 537@@ -3442,6 +3746,12 @@ drm_backend_create(struct weston_compositor *compositor, 538 else 539 b->resize_freeze_ms = DRM_RESIZE_FREEZE_MS; 540 541+ buf = getenv("WESTON_DRM_MIRROR"); 542+ if (buf && buf[0] == '1') { 543+ b->mirror_mode = true; 544+ weston_log("Entering mirror mode.\n"); 545+ } 546+ 547 device = zalloc(sizeof *device); 548 if (device == NULL) 549 return NULL; 550diff --git a/libweston/backend-drm/meson.build b/libweston/backend-drm/meson.build 551index bf7ce33..92ca921 100644 552--- a/libweston/backend-drm/meson.build 553+++ b/libweston/backend-drm/meson.build 554@@ -40,7 +40,8 @@ deps_drm = [ 555 dep_libdrm, 556 dep_libinput_backend, 557 dependency('libudev', version: '>= 136'), 558- dep_backlight 559+ dep_backlight, 560+ dep_rga 561 ] 562 563 if get_option('renderer-gl') 564diff --git a/libweston/backend-drm/state-propose.c b/libweston/backend-drm/state-propose.c 565index 967b6bd..69d49bc 100644 566--- a/libweston/backend-drm/state-propose.c 567+++ b/libweston/backend-drm/state-propose.c 568@@ -55,6 +55,21 @@ static const char *const drm_output_propose_state_mode_as_string[] = { 569 [DRM_OUTPUT_PROPOSE_STATE_PLANES_ONLY] = "plane-only state" 570 }; 571 572+static bool 573+drm_is_mirroring(struct drm_backend *b) 574+{ 575+ struct drm_output *tmp; 576+ 577+ if (!b->mirror_mode) 578+ return false; 579+ 580+ wl_list_for_each(tmp, &b->compositor->output_list, base.link) 581+ if (tmp->is_mirror) 582+ return true; 583+ 584+ return false; 585+} 586+ 587 static const char * 588 drm_propose_state_mode_to_string(enum drm_output_propose_state_mode mode) 589 { 590@@ -459,7 +474,8 @@ drm_output_find_plane_for_view(struct drm_output_state *state, 591 FAILURE_REASONS_FB_FORMAT_INCOMPATIBLE; 592 return NULL; 593 } else if (buffer->type == WESTON_BUFFER_SHM) { 594- if (!output->cursor_plane || device->cursors_are_broken) { 595+ if (!output->cursor_plane || device->cursors_are_broken || 596+ drm_is_mirroring(b)) { 597 pnode->try_view_on_plane_failure_reasons |= 598 FAILURE_REASONS_FB_FORMAT_INCOMPATIBLE; 599 return NULL; 600@@ -932,7 +948,10 @@ drm_assign_planes(struct weston_output *output_base) 601 drm_debug(b, "\t[repaint] preparing state for output %s (%lu)\n", 602 output_base->name, (unsigned long) output_base->id); 603 604- if (!device->sprites_are_broken && !output->virtual && b->gbm) { 605+ /* Force single plane in mirror mode */ 606+ if (drm_is_mirroring(b)) { 607+ drm_debug(b, "\t[state] no overlay plane in mirror mode\n"); 608+ } else if (!device->sprites_are_broken && !output->virtual && b->gbm) { 609 drm_debug(b, "\t[repaint] trying planes-only build state\n"); 610 state = drm_output_propose_state(output_base, pending_state, mode); 611 if (!state) { 612diff --git a/libweston/compositor.c b/libweston/compositor.c 613index 707d1a0..07743ff 100644 614--- a/libweston/compositor.c 615+++ b/libweston/compositor.c 616@@ -1426,7 +1426,7 @@ weston_view_assign_output(struct weston_view *ev) 617 mask = 0; 618 pixman_region32_init(®ion); 619 wl_list_for_each(output, &ec->output_list, link) { 620- if (output->destroying) 621+ if (!weston_output_valid(output)) 622 continue; 623 624 pixman_region32_intersect(®ion, &ev->transform.boundingbox, 625@@ -5660,6 +5660,9 @@ bind_output(struct wl_client *client, 626 static void 627 weston_head_add_global(struct weston_head *head) 628 { 629+ if (head->global || !weston_output_valid(head->output)) 630+ return; 631+ 632 head->global = wl_global_create(head->compositor->wl_display, 633 &wl_output_interface, 3, 634 head, bind_output); 635@@ -5695,6 +5698,15 @@ weston_head_remove_global(struct weston_head *head) 636 wl_list_init(&head->xdg_output_resource_list); 637 } 638 639+static void 640+weston_head_update_global(struct weston_head *head) 641+{ 642+ if (weston_output_valid(head->output)) 643+ weston_head_add_global(head); 644+ else 645+ weston_head_remove_global(head); 646+} 647+ 648 /** Get the backing object of wl_output 649 * 650 * \param resource A wl_output protocol object. 651@@ -6521,6 +6533,7 @@ WL_EXPORT void 652 weston_compositor_reflow_outputs(struct weston_compositor *compositor) 653 { 654 struct weston_output *output; 655+ struct weston_head *head; 656 int x, y, next_x, next_y; 657 658 if (compositor->output_flow_dirty) 659@@ -6528,7 +6541,10 @@ weston_compositor_reflow_outputs(struct weston_compositor *compositor) 660 661 next_x = next_y = 0; 662 wl_list_for_each(output, &compositor->output_list, link) { 663- if (output->destroying) 664+ wl_list_for_each(head, &output->head_list, output_link) 665+ weston_head_update_global(head); 666+ 667+ if (!weston_output_valid(output)) 668 continue; 669 670 x = next_x; 671@@ -6743,11 +6759,11 @@ weston_compositor_add_output(struct weston_compositor *compositor, 672 wl_list_insert(compositor->output_list.prev, &output->link); 673 output->enabled = true; 674 675+ wl_signal_emit(&compositor->output_created_signal, output); 676+ 677 wl_list_for_each(head, &output->head_list, output_link) 678 weston_head_add_global(head); 679 680- wl_signal_emit(&compositor->output_created_signal, output); 681- 682 /* 683 * Use view_list, as paint nodes have not been created for this 684 * output yet. Any existing view might touch this new output. 685diff --git a/libweston/input.c b/libweston/input.c 686index 235cf02..8c9cabc 100644 687--- a/libweston/input.c 688+++ b/libweston/input.c 689@@ -1733,6 +1733,10 @@ weston_pointer_clamp(struct weston_pointer *pointer, wl_fixed_t *fx, wl_fixed_t 690 wl_list_for_each(output, &ec->output_list, link) { 691 if (pointer->seat->output && pointer->seat->output != output) 692 continue; 693+ 694+ if (output->unavailable) 695+ continue; 696+ 697 if (pixman_region32_contains_point(&output->region, 698 x, y, NULL)) 699 valid = 1; 700@@ -1802,6 +1806,9 @@ weston_pointer_handle_output_destroy(struct wl_listener *listener, void *data) 701 y = wl_fixed_to_int(pointer->y); 702 703 wl_list_for_each(output, &ec->output_list, link) { 704+ if (output->unavailable) 705+ continue; 706+ 707 if (pixman_region32_contains_point(&output->region, 708 x, y, NULL)) 709 return; 710diff --git a/meson.build b/meson.build 711index 82119ac..46e57e2 100644 712--- a/meson.build 713+++ b/meson.build 714@@ -141,6 +141,11 @@ if dep_xkbcommon.version().version_compare('>= 0.5.0') 715 config_h.set('HAVE_XKBCOMMON_COMPOSE', '1') 716 endif 717 718+dep_rga = dependency('librga', required: false) 719+if dep_rga.found() 720+ config_h.set('HAVE_RGA', '1') 721+endif 722+ 723 dep_wayland_server = dependency('wayland-server', version: '>= 1.20.0') 724 dep_wayland_client = dependency('wayland-client', version: '>= 1.20.0') 725 dep_pixman = dependency('pixman-1', version: '>= 0.25.2') 726-- 7272.20.1 728 729