1From 7d216da6668ce78ab02bdf586126562e3be691e5 Mon Sep 17 00:00:00 2001 2From: Jeffy Chen <jeffy.chen@rock-chips.com> 3Date: Fri, 3 Jul 2020 12:37:37 +0800 4Subject: [PATCH 19/95] backend-drm: Support controlling output dynamically 5 6Use config file to set output's rotate/down-scale/size/pos/mode/off/ 7freeze/input/display-rectangle and prefer/primary output. 8 9Default config file is "/tmp/.weston_drm.conf", can override with 10"WESTON_DRM_CONFIG" environment. 11 12Supported configs format is "output:<output name>:<config>", for 13example: 14echo "output:DSI-1:off" >> /tmp/.weston_drm.conf 15echo "output:eDP-1:freeze" >> /tmp/.weston_drm.conf 16echo "output:all:rotate90" >> /tmp/.weston_drm.conf 17echo "output:all:rect=<100,20,1636,2068>" >> /tmp/.weston_drm.conf 18echo "output:HDMI-A-1:mode=800x600" >> /tmp/.weston_drm.conf 19echo "output:HDMI-A-1:pos=100,200" >> /tmp/.weston_drm.conf 20echo "output:HDMI-A-1:size=1920x1080" >> /tmp/.weston_drm.conf 21echo "output:HDMI-A-1:prefer" >> /tmp/.weston_drm.conf 22echo "output:HDMI-A-1:primary" >> /tmp/.weston_drm.conf 23echo "output:HDMI-A-1:down-scale=0.5" >> /tmp/.weston_drm.conf 24echo "output:HDMI-A-1:input=*" >> /tmp/.weston_drm.conf 25echo "output:HDMI-A-1:input=" >> /tmp/.weston_drm.conf 26echo "output:HDMI-A-1:input=event6" >> /tmp/.weston_drm.conf 27echo "output:HDMI-A-1:input=goodix*" >> /tmp/.weston_drm.conf 28echo "output:HDMI-A-1:input=goodix-ts" >> /tmp/.weston_drm.conf 29 30Signed-off-by: Jeffy Chen <jeffy.chen@rock-chips.com> 31--- 32 compositor/main.c | 14 ++ 33 desktop-shell/shell.c | 58 +++++- 34 include/libweston/libweston.h | 7 + 35 libweston/backend-drm/drm-internal.h | 16 ++ 36 libweston/backend-drm/drm.c | 266 ++++++++++++++++++++++++++- 37 libweston/backend-drm/modes.c | 20 +- 38 libweston/compositor.c | 30 ++- 39 libweston/libinput-seat.c | 43 +++++ 40 libweston/libweston-internal.h | 3 + 41 libweston/renderer-gl/gl-renderer.c | 4 + 42 10 files changed, 435 insertions(+), 26 deletions(-) 43 44diff --git a/compositor/main.c b/compositor/main.c 45index dcfe85b..d65f8aa 100644 46--- a/compositor/main.c 47+++ b/compositor/main.c 48@@ -2080,6 +2080,20 @@ drm_backend_output_configure(struct weston_output *output, 49 } 50 free(s); 51 52+ weston_config_section_get_string(section, "pos", &s, NULL); 53+ if (s) { 54+ if (sscanf(s, "%d,%d", &output->x, &output->y) == 2) 55+ output->fixed_position = true; 56+ free(s); 57+ } 58+ 59+ weston_config_section_get_string(section, "size", &s, NULL); 60+ if (s) { 61+ if (sscanf(s, "%dx%d", &output->width, &output->height) == 2) 62+ output->fixed_size = true; 63+ free(s); 64+ } 65+ 66 if (api->set_mode(output, mode, modeline) < 0) { 67 weston_log("Cannot configure an output using weston_drm_output_api.\n"); 68 free(modeline); 69diff --git a/desktop-shell/shell.c b/desktop-shell/shell.c 70index 7aa787c..be36b70 100644 71--- a/desktop-shell/shell.c 72+++ b/desktop-shell/shell.c 73@@ -3831,7 +3831,7 @@ weston_view_set_initial_position(struct weston_view *view, 74 int ix = 0, iy = 0; 75 int32_t range_x, range_y; 76 int32_t x, y; 77- struct weston_output *output, *target_output = NULL; 78+ struct weston_output *output, *target_output = NULL, *prefer_output = NULL; 79 struct weston_seat *seat; 80 pixman_rectangle32_t area; 81 82@@ -3856,16 +3856,20 @@ weston_view_set_initial_position(struct weston_view *view, 83 } 84 } 85 86- wl_list_for_each(output, &compositor->output_list, link) { 87+ wl_list_for_each_reverse(output, &compositor->output_list, link) { 88 if (output->unavailable) 89 continue; 90 91- if (pixman_region32_contains_point(&output->region, ix, iy, NULL)) { 92+ if (output == compositor->prefer_output) 93+ prefer_output = output; 94+ 95+ if (pixman_region32_contains_point(&output->region, ix, iy, NULL)) 96 target_output = output; 97- break; 98- } 99 } 100 101+ if (prefer_output) 102+ target_output = prefer_output; 103+ 104 if (!target_output) { 105 weston_view_set_position(view, 10 + random() % 400, 106 10 + random() % 400); 107@@ -4382,6 +4386,41 @@ shell_resize_surface_to_output(struct desktop_shell *shell, 108 output->height); 109 } 110 111+static void 112+handle_output_resize_layer(struct desktop_shell *shell, 113+ struct weston_layer *layer, void *data) 114+{ 115+ struct weston_output *output = data; 116+ struct weston_view *view; 117+ 118+ wl_list_for_each(view, &layer->view_list.link, layer_link.link) { 119+ struct weston_desktop_surface *desktop_surface; 120+ struct shell_surface *shsurf; 121+ bool dirty = false; 122+ 123+ if (view->output != output) 124+ continue; 125+ 126+ shsurf = get_shell_surface(view->surface); 127+ if (!shsurf) 128+ continue; 129+ 130+ desktop_surface = shsurf->desktop_surface; 131+ if (weston_desktop_surface_get_fullscreen(desktop_surface)) { 132+ set_fullscreen(shsurf, true, output); 133+ dirty = true; 134+ } 135+ if (weston_desktop_surface_get_maximized(desktop_surface)) { 136+ set_maximized(shsurf, true); 137+ dirty = true; 138+ } 139+ 140+ if (dirty) { 141+ weston_view_geometry_dirty(view); 142+ weston_surface_damage(view->surface); 143+ } 144+ } 145+} 146 147 static void 148 handle_output_resized(struct wl_listener *listener, void *data) 149@@ -4391,8 +4430,13 @@ handle_output_resized(struct wl_listener *listener, void *data) 150 struct weston_output *output = (struct weston_output *)data; 151 struct shell_output *sh_output = find_shell_output_from_weston_output(shell, output); 152 153+ if (shell->lock_surface) 154+ shell->lock_surface->committed(shell->lock_surface, 0, 0); 155+ 156 shell_resize_surface_to_output(shell, sh_output->background_surface, output); 157 shell_resize_surface_to_output(shell, sh_output->panel_surface, output); 158+ 159+ shell_for_each_layer(shell, handle_output_resize_layer, data); 160 } 161 162 static void 163@@ -4441,7 +4485,9 @@ handle_output_move_layer(struct desktop_shell *shell, 164 165 x = view->geometry.x + output->move_x; 166 y = view->geometry.y + output->move_y; 167- weston_view_set_position(view, x, y); 168+ 169+ if (pixman_region32_contains_point(&output->region, x, y, NULL)) 170+ weston_view_set_position(view, x, y); 171 } 172 } 173 174diff --git a/include/libweston/libweston.h b/include/libweston/libweston.h 175index a8ec105..84b16fe 100644 176--- a/include/libweston/libweston.h 177+++ b/include/libweston/libweston.h 178@@ -575,6 +575,12 @@ struct weston_output { 179 struct weston_head *head); 180 181 bool unavailable; 182+ bool freezing; 183+ 184+ bool fixed_position; 185+ bool fixed_size; 186+ 187+ double down_scale; 188 }; 189 #define weston_output_valid(o) \ 190 ((o) && !(o)->destroying && !(o)->unavailable) 191@@ -1333,6 +1339,7 @@ struct weston_compositor { 192 bool warned_about_unmapped_surface_or_view; 193 194 enum weston_output_flow output_flow; 195+ struct weston_output *prefer_output; 196 }; 197 198 struct weston_solid_buffer_values { 199diff --git a/libweston/backend-drm/drm-internal.h b/libweston/backend-drm/drm-internal.h 200index 037c937..532593e 100644 201--- a/libweston/backend-drm/drm-internal.h 202+++ b/libweston/backend-drm/drm-internal.h 203@@ -115,6 +115,9 @@ 204 205 #define DRM_RESIZE_FREEZE_MS 600 206 207+#define WESTON_DRM_CONFIG_FILE "/tmp/.weston_drm.conf" 208+#define DRM_CONFIG_UPDATE_MS 100 209+ 210 /** 211 * Represents the values of an enum-type KMS property 212 */ 213@@ -364,6 +367,9 @@ struct drm_backend { 214 int virtual_height; 215 216 bool mirror_mode; 217+ 218+ struct wl_event_source *config_timer; 219+ struct stat config_stat; 220 }; 221 222 struct drm_mode { 223@@ -641,6 +647,9 @@ struct drm_output { 224 bool is_mirror; 225 226 pixman_box32_t plane_bounds; 227+ 228+ uint32_t original_transform; 229+ int64_t last_resize_ms; 230 }; 231 232 void 233@@ -739,6 +748,13 @@ drm_mode_list_destroy(struct drm_device *device, struct wl_list *mode_list); 234 void 235 drm_output_print_modes(struct drm_output *output); 236 237+struct drm_mode * 238+drm_output_choose_initial_mode(struct drm_device *device, 239+ struct drm_output *output, 240+ enum weston_drm_backend_output_mode mode, 241+ const char *modeline, 242+ const drmModeModeInfo *current_mode); 243+ 244 int 245 drm_output_set_mode(struct weston_output *base, 246 enum weston_drm_backend_output_mode mode, 247diff --git a/libweston/backend-drm/drm.c b/libweston/backend-drm/drm.c 248index fc035b9..6c7a567 100644 249--- a/libweston/backend-drm/drm.c 250+++ b/libweston/backend-drm/drm.c 251@@ -41,6 +41,7 @@ 252 #include <linux/vt.h> 253 #include <assert.h> 254 #include <sys/mman.h> 255+#include <sys/stat.h> 256 #include <time.h> 257 258 #include <xf86drm.h> 259@@ -75,6 +76,8 @@ 260 261 static const char default_seat[] = "seat0"; 262 263+static int config_timer_handler(void *data); 264+ 265 static inline bool 266 drm_head_is_external(struct drm_head *head) 267 { 268@@ -510,6 +513,12 @@ drm_output_update_complete(struct drm_output *output, uint32_t flags, 269 return; 270 } 271 272+ if (!sec && !usec) { 273+ weston_output_finish_frame(&output->base, NULL, 274+ WP_PRESENTATION_FEEDBACK_INVALID); 275+ return; 276+ } 277+ 278 ts.tv_sec = sec; 279 ts.tv_nsec = usec * 1000; 280 281@@ -689,8 +698,13 @@ out: 282 return; 283 } 284 285- sw = fb->width; 286- sh = fb->height; 287+ if (output->base.down_scale != 1.0f && b->use_pixman) { 288+ weston_log("pixman renderer could not support down-scale\n"); 289+ output->base.down_scale = 1.0f; 290+ } 291+ 292+ sw = fb->width * output->base.down_scale; 293+ sh = fb->height * output->base.down_scale; 294 295 dx = output->plane_bounds.x1; 296 dy = output->plane_bounds.y1; 297@@ -832,7 +846,8 @@ drm_output_repaint(struct weston_output *output_base, pixman_region32_t *damage) 298 299 weston_compositor_read_presentation_clock(b->compositor, &now); 300 now_ms = timespec_to_msec(&now); 301- if (now_ms < b->last_resize_ms + b->resize_freeze_ms) { 302+ if (now_ms < b->last_resize_ms + b->resize_freeze_ms || 303+ now_ms < output->last_resize_ms + b->resize_freeze_ms) { 304 /* Resize fullscreen/maxmium views(not always success) */ 305 if (now_ms < b->last_resize_ms + DRM_RESIZE_FREEZE_MS) 306 wl_signal_emit(&b->compositor->output_resized_signal, 307@@ -841,7 +856,7 @@ drm_output_repaint(struct weston_output *output_base, pixman_region32_t *damage) 308 weston_output_damage(output_base); 309 weston_output_finish_frame(output_base, NULL, 310 WP_PRESENTATION_FEEDBACK_INVALID); 311- return 0; 312+ goto not_repainted; 313 } 314 315 /* If planes have been disabled in the core, we might not have 316@@ -872,7 +887,8 @@ drm_output_repaint(struct weston_output *output_base, pixman_region32_t *damage) 317 318 err: 319 drm_output_state_free(state); 320- return 0; 321+not_repainted: 322+ return 1; 323 } 324 325 /* Determine the type of vblank synchronization to use for the output. 326@@ -2296,6 +2312,8 @@ drm_output_enable(struct weston_output *base) 327 output->base.switch_mode = drm_output_switch_mode; 328 output->base.set_gamma = drm_output_set_gamma; 329 330+ output->original_transform = output->base.transform; 331+ 332 output->state_invalid = true; 333 334 weston_log("Output %s (crtc %d) video modes:\n", 335@@ -3188,6 +3206,7 @@ drm_destroy(struct weston_compositor *ec) 336 337 udev_input_destroy(&b->input); 338 339+ wl_event_source_remove(b->config_timer); 340 wl_event_source_remove(b->hotplug_timer); 341 wl_event_source_remove(b->udev_drm_source); 342 wl_event_source_remove(b->drm_source); 343@@ -3608,6 +3627,10 @@ output_create_notify(struct wl_listener *listener, void *data) 344 output_create_listener); 345 346 drm_backend_update_outputs(b); 347+ 348+ /* Force reload config */ 349+ memset(&b->config_stat, 0, sizeof(b->config_stat)); 350+ config_timer_handler(b); 351 } 352 353 static const struct weston_drm_output_api api = { 354@@ -3617,6 +3640,235 @@ static const struct weston_drm_output_api api = { 355 drm_output_set_max_bpc, 356 }; 357 358+static void 359+drm_output_rotate(struct drm_output *output, int rotate) 360+{ 361+ struct drm_backend *b = to_drm_backend(output->base.compositor); 362+ uint32_t transform = output->original_transform; 363+ struct timespec now; 364+ 365+ /* Hacky way to rotate transform */ 366+ transform = (transform / 4) * 4 + (transform + rotate) % 4; 367+ 368+ if (output->base.transform == transform) 369+ return; 370+ 371+ /* Freeze output when rotating */ 372+ weston_compositor_read_presentation_clock(b->compositor, &now); 373+ output->last_resize_ms = timespec_to_msec(&now); 374+ 375+ weston_output_set_transform(&output->base, transform); 376+} 377+ 378+static void 379+drm_output_modeset(struct drm_output *output, const char *modeline) 380+{ 381+ struct drm_backend *b = to_drm_backend(output->base.compositor); 382+ struct drm_head *head = 383+ to_drm_head(weston_output_get_first_head(&output->base)); 384+ struct drm_mode *mode; 385+ struct timespec now; 386+ 387+ /* Unable to switch mode, let's retry later */ 388+ if (output->page_flip_pending || output->atomic_complete_pending) { 389+ memset(&b->config_stat, 0, sizeof(b->config_stat)); 390+ return; 391+ } 392+ 393+ mode = drm_output_choose_initial_mode(b->drm, output, 394+ WESTON_DRM_BACKEND_OUTPUT_PREFERRED, 395+ modeline, 396+ &head->inherited_mode); 397+ 398+ weston_output_mode_set_native(&output->base, &mode->base, 399+ output->base.current_scale); 400+ weston_output_damage(&output->base); 401+ 402+ mode = to_drm_mode(output->base.current_mode); 403+ 404+ weston_log("Output %s changed to %dx%d@%d for mode(%s)\n", 405+ output->base.name, 406+ mode->mode_info.hdisplay, mode->mode_info.vdisplay, 407+ mode->mode_info.vrefresh, 408+ modeline); 409+ 410+ weston_compositor_read_presentation_clock(b->compositor, &now); 411+ b->last_update_ms = timespec_to_msec(&now); 412+} 413+ 414+static void 415+drm_output_set_size(struct drm_output *output, const int w, const int h) 416+{ 417+ struct drm_backend *b = to_drm_backend(output->base.compositor); 418+ struct weston_mode *mode; 419+ struct timespec now; 420+ 421+ if (output->base.fixed_size && 422+ output->base.current_mode->width == w && 423+ output->base.current_mode->height == h) 424+ return; 425+ 426+ wl_list_for_each(mode, &output->base.mode_list, link) { 427+ mode->width = w; 428+ mode->height = h; 429+ } 430+ 431+ output->base.fixed_size = true; 432+ 433+ /* Freeze output when resizing */ 434+ weston_compositor_read_presentation_clock(b->compositor, &now); 435+ output->last_resize_ms = timespec_to_msec(&now); 436+ 437+ weston_output_set_transform(&output->base, output->base.transform); 438+ 439+ if (b->use_pixman) { 440+ drm_output_fini_pixman(output); 441+ if (drm_output_init_pixman(output, b) < 0) 442+ weston_log("failed to init output pixman state with " 443+ "new mode\n"); 444+ } else { 445+ drm_output_fini_egl(output); 446+ if (drm_output_init_egl(output, b) < 0) 447+ weston_log("failed to init output egl state with " 448+ "new mode"); 449+ } 450+ 451+ drm_output_print_modes(output); 452+} 453+ 454+static void 455+config_handle_output(struct drm_backend *b, const char *name, 456+ const char *config) 457+{ 458+ struct drm_output *output; 459+ bool is_all = !strcmp(name, "all"); 460+ 461+ wl_list_for_each(output, &b->compositor->output_list, base.link) { 462+ if (!is_all && strcmp(name, output->base.name)) 463+ continue; 464+ 465+ if (!strcmp(config, "primary")) { 466+ setenv("WESTON_DRM_PRIMARY", name, 1); 467+ hotplug_timer_handler(b->drm); 468+ } else if (!strcmp(config, "prefer")) { 469+ b->compositor->prefer_output = &output->base; 470+ } else if (!strncmp(config, "rotate", strlen("rotate"))) { 471+ int rotate = atoi(config + strlen("rotate")) / 90; 472+ drm_output_rotate(output, rotate); 473+ } else if (!strncmp(config, "mode=", strlen("mode="))) { 474+ drm_output_modeset(output, config + strlen("mode=")); 475+ } else if (!strcmp(config, "freeze")) { 476+ output->base.freezing = true; 477+ } else if (!strcmp(config, "off")) { 478+ output->base.freezing = true; 479+ if (!output->virtual) 480+ drm_set_dpms(&output->base, WESTON_DPMS_OFF); 481+ } else if (!strcmp(config, "unfreeze") || 482+ !strcmp(config, "on")) { 483+ if (!output->base.freezing) 484+ continue; 485+ 486+ output->base.freezing = false; 487+ 488+ if (!output->virtual) 489+ drm_set_dpms(&output->base, WESTON_DPMS_ON); 490+ 491+ weston_output_damage(&output->base); 492+ } else if (!strncmp(config, "down-scale=", 493+ strlen("down-scale="))) { 494+ double down_scale = 495+ atof(config + strlen("down-scale=")); 496+ if (down_scale == output->base.down_scale || 497+ down_scale < 0.125 || down_scale > 1) 498+ continue; 499+ 500+ output->base.down_scale = down_scale; 501+ weston_output_damage(&output->base); 502+ } else if (!strncmp(config, "size=", strlen("size="))) { 503+ int w, h; 504+ 505+ if (sscanf(config, "size=%dx%d", &w, &h) != 2) 506+ continue; 507+ 508+ drm_output_set_size(output, w, h); 509+ } else if (!strncmp(config, "pos=", strlen("pos="))) { 510+ int x, y; 511+ 512+ if (sscanf(config, "pos=%d,%d", &x, &y) != 2) 513+ continue; 514+ 515+ weston_output_move(&output->base, x, y); 516+ output->base.fixed_position = true; 517+ 518+ weston_compositor_reflow_outputs(b->compositor); 519+ } else if (!strncmp(config, "rect=", strlen("rect="))) { 520+ int x1, y1, x2, y2, ret; 521+ 522+ ret = sscanf(config, "rect=<%d,%d,%d,%d>", 523+ &x1, &y1, &x2, &y2); 524+ if (ret != 4) 525+ continue; 526+ 527+ output->plane_bounds.x1 = x1; 528+ output->plane_bounds.y1 = y1; 529+ output->plane_bounds.x2 = x2; 530+ output->plane_bounds.y2 = y2; 531+ weston_output_schedule_repaint(&output->base); 532+ } else if (!strncmp(config, "input=", strlen("input="))) { 533+ weston_output_bind_input(&output->base, 534+ config + strlen("input=")); 535+ } 536+ } 537+} 538+ 539+static int 540+config_timer_handler(void *data) 541+{ 542+#define MAX_CONF_LEN 512 543+#define _STR(x) #x 544+#define STR(x) _STR(x) 545+ 546+ struct drm_backend *b = data; 547+ struct stat st; 548+ char type[MAX_CONF_LEN], key[MAX_CONF_LEN], value[MAX_CONF_LEN]; 549+ const char *config_file; 550+ FILE *conf_fp; 551+ 552+ wl_event_source_timer_update(b->config_timer, DRM_CONFIG_UPDATE_MS); 553+ 554+ config_file = getenv("WESTON_DRM_CONFIG"); 555+ if (!config_file) 556+ config_file = WESTON_DRM_CONFIG_FILE; 557+ 558+ if (stat(config_file, &st) < 0) 559+ return 0; 560+ 561+ if (st.st_mtime && !memcmp(&st, &b->config_stat, sizeof(st))) 562+ return 0; 563+ 564+ conf_fp = fopen(config_file, "r"); 565+ if (!conf_fp) 566+ return 0; 567+ 568+ /** 569+ * Parse configs, formated with <type>:<key>:<value> 570+ * For example: "output:all:rotate90" 571+ */ 572+ while (3 == fscanf(conf_fp, 573+ "%" STR(MAX_CONF_LEN) "[^:]:" 574+ "%" STR(MAX_CONF_LEN) "[^:]:" 575+ "%" STR(MAX_CONF_LEN) "[^\n]%*c", type, key, value)) { 576+ if (!strcmp(type, "output")) 577+ config_handle_output(b, key, value); 578+ } 579+ 580+ fclose(conf_fp); 581+ 582+ stat(config_file, &st); 583+ b->config_stat = st; 584+ return 0; 585+} 586+ 587 enum drm_head_mode { 588 DRM_HEAD_MODE_DEFAULT, 589 DRM_HEAD_MODE_PRIMARY, 590@@ -3960,6 +4212,10 @@ drm_backend_create(struct weston_compositor *compositor, 591 b->hotplug_timer = 592 wl_event_loop_add_timer(loop, hotplug_timer_handler, b->drm); 593 594+ b->config_timer = 595+ wl_event_loop_add_timer(loop, config_timer_handler, b); 596+ config_timer_handler(b); 597+ 598 return b; 599 600 err_udev_monitor: 601diff --git a/libweston/backend-drm/modes.c b/libweston/backend-drm/modes.c 602index 7e7865b..f3d2c00 100644 603--- a/libweston/backend-drm/modes.c 604+++ b/libweston/backend-drm/modes.c 605@@ -405,15 +405,19 @@ drm_output_add_mode(struct drm_output *output, const drmModeModeInfo *info) 606 if (mode == NULL) 607 return NULL; 608 609- mode->base.flags = 0; 610- mode->base.width = info->hdisplay; 611- mode->base.height = info->vdisplay; 612- 613- if (b->virtual_width && b->virtual_height) { 614+ if (output->base.fixed_size) { 615+ mode->base.width = output->base.width; 616+ mode->base.height = output->base.height; 617+ } else if (b->virtual_width && b->virtual_height) { 618 mode->base.width = b->virtual_width; 619 mode->base.height = b->virtual_height; 620+ } else { 621+ mode->base.width = info->hdisplay; 622+ mode->base.height = info->vdisplay; 623 } 624 625+ mode->base.flags = 0; 626+ 627 mode->base.refresh = drm_refresh_rate_mHz(info); 628 mode->mode_info = *info; 629 mode->blob_id = 0; 630@@ -589,7 +593,7 @@ update_head_from_connector(struct drm_head *head) 631 * @param current_mode Mode currently being displayed on this output 632 * @returns A mode from the output's mode list, or NULL if none available 633 */ 634-static struct drm_mode * 635+struct drm_mode * 636 drm_output_choose_initial_mode(struct drm_device *device, 637 struct drm_output *output, 638 enum weston_drm_backend_output_mode mode, 639@@ -642,8 +646,8 @@ drm_output_choose_initial_mode(struct drm_device *device, 640 } 641 642 wl_list_for_each_reverse(drm_mode, &output->base.mode_list, base.link) { 643- if (width == drm_mode->base.width && 644- height == drm_mode->base.height && 645+ if (width == drm_mode->mode_info.hdisplay && 646+ height == drm_mode->mode_info.vdisplay && 647 (refresh == 0 || refresh == drm_mode->mode_info.vrefresh)) { 648 if (!device->aspect_ratio_supported || 649 aspect_ratio == drm_mode->base.aspect_ratio) 650diff --git a/libweston/compositor.c b/libweston/compositor.c 651index eea8da2..d9f6682 100644 652--- a/libweston/compositor.c 653+++ b/libweston/compositor.c 654@@ -3372,6 +3372,11 @@ weston_output_repaint(struct weston_output *output) 655 static void 656 weston_output_schedule_repaint_reset(struct weston_output *output) 657 { 658+ if (output->idle_repaint_source) { 659+ wl_event_source_remove(output->idle_repaint_source); 660+ output->idle_repaint_source = NULL; 661+ } 662+ 663 output->repaint_status = REPAINT_NOT_SCHEDULED; 664 TL_POINT(output->compositor, "core_repaint_exit_loop", 665 TLP_OUTPUT(output), TLP_END); 666@@ -3384,6 +3389,11 @@ weston_output_maybe_repaint(struct weston_output *output, struct timespec *now) 667 int ret = 0; 668 int64_t msec_to_repaint; 669 670+ /* If we're sleeping, drop the repaint machinery entirely; we will 671+ * explicitly repaint it when we come back. */ 672+ if (output->freezing) 673+ goto err; 674+ 675 /* We're not ready yet; come back to make a decision later. */ 676 if (output->repaint_status != REPAINT_SCHEDULED) 677 return ret; 678@@ -3410,11 +3420,11 @@ weston_output_maybe_repaint(struct weston_output *output, struct timespec *now) 679 * output. */ 680 ret = weston_output_repaint(output); 681 weston_compositor_read_presentation_clock(compositor, now); 682- if (ret != 0) 683+ if (ret < 0) 684 goto err; 685 686- output->repainted = true; 687- return ret; 688+ output->repainted = !ret; 689+ return 0; 690 691 err: 692 weston_output_schedule_repaint_reset(output); 693@@ -3480,7 +3490,7 @@ output_repaint_timer_handler(void *data) 694 struct weston_compositor *compositor = data; 695 struct weston_output *output; 696 struct timespec now; 697- int ret = 0; 698+ int ret = 0, repainted = 0; 699 700 if (!access(getenv("WESTON_FREEZE_DISPLAY") ? : "", F_OK)) { 701 usleep(DEFAULT_REPAINT_WINDOW * 1000); 702@@ -3497,9 +3507,11 @@ output_repaint_timer_handler(void *data) 703 ret = weston_output_maybe_repaint(output, &now); 704 if (ret) 705 break; 706+ 707+ repainted |= output->repainted; 708 } 709 710- if (ret == 0) { 711+ if (ret == 0 && repainted) { 712 if (compositor->backend->repaint_flush) 713 ret = compositor->backend->repaint_flush(compositor); 714 } else { 715@@ -6544,7 +6556,7 @@ weston_compositor_reflow_outputs(struct weston_compositor *compositor) 716 wl_list_for_each(head, &output->head_list, output_link) 717 weston_head_update_global(head); 718 719- if (!weston_output_valid(output)) 720+ if (!weston_output_valid(output) || output->fixed_position) 721 continue; 722 723 x = next_x; 724@@ -7050,6 +7062,9 @@ weston_output_set_transform(struct weston_output *output, 725 726 weston_compositor_reflow_outputs(output->compositor); 727 728+ wl_signal_emit(&output->compositor->output_resized_signal, 729+ output); 730+ 731 /* Notify clients of the change for output transform. */ 732 wl_list_for_each(head, &output->head_list, output_link) { 733 wl_resource_for_each(resource, &head->resource_list) { 734@@ -7288,6 +7303,8 @@ weston_output_init(struct weston_output *output, 735 /* Can't use -1 on uint32_t and 0 is valid enum value */ 736 output->transform = UINT32_MAX; 737 738+ output->down_scale = 1.0f; 739+ 740 pixman_region32_init(&output->damage); 741 pixman_region32_init(&output->region); 742 wl_list_init(&output->mode_list); 743@@ -7420,7 +7437,6 @@ weston_output_enable(struct weston_output *output) 744 weston_output_transform_scale_init(output, output->transform, output->scale); 745 746 weston_output_init_geometry(output, output->x, output->y); 747- weston_output_damage(output); 748 749 wl_list_init(&output->animation_list); 750 wl_list_init(&output->feedback_list); 751diff --git a/libweston/libinput-seat.c b/libweston/libinput-seat.c 752index 57ff181..100b47d 100644 753--- a/libweston/libinput-seat.c 754+++ b/libweston/libinput-seat.c 755@@ -534,3 +534,46 @@ udev_seat_get_named(struct udev_input *input, const char *seat_name) 756 757 return udev_seat_create(input, seat_name); 758 } 759+ 760+void 761+weston_output_bind_input(struct weston_output *output, const char *match) 762+{ 763+ struct weston_compositor *compositor = output->compositor; 764+ struct evdev_device *device; 765+ struct udev_seat *seat; 766+ const char *sysname, *name; 767+ int len = strlen(match); 768+ int clear = !len; 769+ 770+ /* Handle pattern match */ 771+ if (len && match[len - 1] == '*') 772+ len--; 773+ 774+ wl_list_for_each(seat, &compositor->seat_list, base.link) { 775+ wl_list_for_each(device, &seat->devices_list, link) { 776+ if (clear) { 777+ /* Clear all bounded inputs */ 778+ if (!device->output_name || 779+ strcmp(device->output_name, output->name)) 780+ continue; 781+ 782+ free(device->output_name); 783+ device->output_name = NULL; 784+ continue; 785+ } 786+ 787+ sysname = libinput_device_get_sysname(device->device); 788+ name = libinput_device_get_name(device->device); 789+ 790+ if (!len || !strncmp(name, match, len) || 791+ !strncmp(sysname, match, len)) { 792+ if (device->output_name) 793+ free(device->output_name); 794+ 795+ device->output_name = strdup(output->name); 796+ } 797+ } 798+ 799+ udev_seat_update_output(seat); 800+ } 801+} 802diff --git a/libweston/libweston-internal.h b/libweston/libweston-internal.h 803index 8bdac33..39d9e85 100644 804--- a/libweston/libweston-internal.h 805+++ b/libweston/libweston-internal.h 806@@ -193,6 +193,9 @@ weston_output_disable_planes_incr(struct weston_output *output); 807 void 808 weston_output_disable_planes_decr(struct weston_output *output); 809 810+void 811+weston_output_bind_input(struct weston_output *output, const char *name); 812+ 813 /* weston_plane */ 814 815 void 816diff --git a/libweston/renderer-gl/gl-renderer.c b/libweston/renderer-gl/gl-renderer.c 817index db4c7b1..3437bf2 100644 818--- a/libweston/renderer-gl/gl-renderer.c 819+++ b/libweston/renderer-gl/gl-renderer.c 820@@ -1685,6 +1685,10 @@ gl_renderer_repaint_output(struct weston_output *output, 821 822 /* Calculate the global GL matrix */ 823 go->output_matrix = output->matrix; 824+ 825+ weston_matrix_scale(&go->output_matrix, 826+ output->down_scale, output->down_scale, 1); 827+ 828 weston_matrix_translate(&go->output_matrix, 829 -(output->current_mode->width / 2.0), 830 -(output->current_mode->height / 2.0), 0); 831-- 8322.20.1 833 834