1From 267f9e075009cac9b4ac4dbd24d0d3cd2621f041 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/93] 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 | 265 ++++++++++++++++++++++++++- 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/pixman-renderer.c | 3 + 42 libweston/renderer-gl/gl-renderer.c | 4 + 43 11 files changed, 437 insertions(+), 26 deletions(-) 44 45diff --git a/compositor/main.c b/compositor/main.c 46index dcfe85b..d65f8aa 100644 47--- a/compositor/main.c 48+++ b/compositor/main.c 49@@ -2080,6 +2080,20 @@ drm_backend_output_configure(struct weston_output *output, 50 } 51 free(s); 52 53+ weston_config_section_get_string(section, "pos", &s, NULL); 54+ if (s) { 55+ if (sscanf(s, "%d,%d", &output->x, &output->y) == 2) 56+ output->fixed_position = true; 57+ free(s); 58+ } 59+ 60+ weston_config_section_get_string(section, "size", &s, NULL); 61+ if (s) { 62+ if (sscanf(s, "%dx%d", &output->width, &output->height) == 2) 63+ output->fixed_size = true; 64+ free(s); 65+ } 66+ 67 if (api->set_mode(output, mode, modeline) < 0) { 68 weston_log("Cannot configure an output using weston_drm_output_api.\n"); 69 free(modeline); 70diff --git a/desktop-shell/shell.c b/desktop-shell/shell.c 71index 7aa787c..be36b70 100644 72--- a/desktop-shell/shell.c 73+++ b/desktop-shell/shell.c 74@@ -3831,7 +3831,7 @@ weston_view_set_initial_position(struct weston_view *view, 75 int ix = 0, iy = 0; 76 int32_t range_x, range_y; 77 int32_t x, y; 78- struct weston_output *output, *target_output = NULL; 79+ struct weston_output *output, *target_output = NULL, *prefer_output = NULL; 80 struct weston_seat *seat; 81 pixman_rectangle32_t area; 82 83@@ -3856,16 +3856,20 @@ weston_view_set_initial_position(struct weston_view *view, 84 } 85 } 86 87- wl_list_for_each(output, &compositor->output_list, link) { 88+ wl_list_for_each_reverse(output, &compositor->output_list, link) { 89 if (output->unavailable) 90 continue; 91 92- if (pixman_region32_contains_point(&output->region, ix, iy, NULL)) { 93+ if (output == compositor->prefer_output) 94+ prefer_output = output; 95+ 96+ if (pixman_region32_contains_point(&output->region, ix, iy, NULL)) 97 target_output = output; 98- break; 99- } 100 } 101 102+ if (prefer_output) 103+ target_output = prefer_output; 104+ 105 if (!target_output) { 106 weston_view_set_position(view, 10 + random() % 400, 107 10 + random() % 400); 108@@ -4382,6 +4386,41 @@ shell_resize_surface_to_output(struct desktop_shell *shell, 109 output->height); 110 } 111 112+static void 113+handle_output_resize_layer(struct desktop_shell *shell, 114+ struct weston_layer *layer, void *data) 115+{ 116+ struct weston_output *output = data; 117+ struct weston_view *view; 118+ 119+ wl_list_for_each(view, &layer->view_list.link, layer_link.link) { 120+ struct weston_desktop_surface *desktop_surface; 121+ struct shell_surface *shsurf; 122+ bool dirty = false; 123+ 124+ if (view->output != output) 125+ continue; 126+ 127+ shsurf = get_shell_surface(view->surface); 128+ if (!shsurf) 129+ continue; 130+ 131+ desktop_surface = shsurf->desktop_surface; 132+ if (weston_desktop_surface_get_fullscreen(desktop_surface)) { 133+ set_fullscreen(shsurf, true, output); 134+ dirty = true; 135+ } 136+ if (weston_desktop_surface_get_maximized(desktop_surface)) { 137+ set_maximized(shsurf, true); 138+ dirty = true; 139+ } 140+ 141+ if (dirty) { 142+ weston_view_geometry_dirty(view); 143+ weston_surface_damage(view->surface); 144+ } 145+ } 146+} 147 148 static void 149 handle_output_resized(struct wl_listener *listener, void *data) 150@@ -4391,8 +4430,13 @@ handle_output_resized(struct wl_listener *listener, void *data) 151 struct weston_output *output = (struct weston_output *)data; 152 struct shell_output *sh_output = find_shell_output_from_weston_output(shell, output); 153 154+ if (shell->lock_surface) 155+ shell->lock_surface->committed(shell->lock_surface, 0, 0); 156+ 157 shell_resize_surface_to_output(shell, sh_output->background_surface, output); 158 shell_resize_surface_to_output(shell, sh_output->panel_surface, output); 159+ 160+ shell_for_each_layer(shell, handle_output_resize_layer, data); 161 } 162 163 static void 164@@ -4441,7 +4485,9 @@ handle_output_move_layer(struct desktop_shell *shell, 165 166 x = view->geometry.x + output->move_x; 167 y = view->geometry.y + output->move_y; 168- weston_view_set_position(view, x, y); 169+ 170+ if (pixman_region32_contains_point(&output->region, x, y, NULL)) 171+ weston_view_set_position(view, x, y); 172 } 173 } 174 175diff --git a/include/libweston/libweston.h b/include/libweston/libweston.h 176index a8ec105..84b16fe 100644 177--- a/include/libweston/libweston.h 178+++ b/include/libweston/libweston.h 179@@ -575,6 +575,12 @@ struct weston_output { 180 struct weston_head *head); 181 182 bool unavailable; 183+ bool freezing; 184+ 185+ bool fixed_position; 186+ bool fixed_size; 187+ 188+ double down_scale; 189 }; 190 #define weston_output_valid(o) \ 191 ((o) && !(o)->destroying && !(o)->unavailable) 192@@ -1333,6 +1339,7 @@ struct weston_compositor { 193 bool warned_about_unmapped_surface_or_view; 194 195 enum weston_output_flow output_flow; 196+ struct weston_output *prefer_output; 197 }; 198 199 struct weston_solid_buffer_values { 200diff --git a/libweston/backend-drm/drm-internal.h b/libweston/backend-drm/drm-internal.h 201index 037c937..532593e 100644 202--- a/libweston/backend-drm/drm-internal.h 203+++ b/libweston/backend-drm/drm-internal.h 204@@ -115,6 +115,9 @@ 205 206 #define DRM_RESIZE_FREEZE_MS 600 207 208+#define WESTON_DRM_CONFIG_FILE "/tmp/.weston_drm.conf" 209+#define DRM_CONFIG_UPDATE_MS 100 210+ 211 /** 212 * Represents the values of an enum-type KMS property 213 */ 214@@ -364,6 +367,9 @@ struct drm_backend { 215 int virtual_height; 216 217 bool mirror_mode; 218+ 219+ struct wl_event_source *config_timer; 220+ struct stat config_stat; 221 }; 222 223 struct drm_mode { 224@@ -641,6 +647,9 @@ struct drm_output { 225 bool is_mirror; 226 227 pixman_box32_t plane_bounds; 228+ 229+ uint32_t original_transform; 230+ int64_t last_resize_ms; 231 }; 232 233 void 234@@ -739,6 +748,13 @@ drm_mode_list_destroy(struct drm_device *device, struct wl_list *mode_list); 235 void 236 drm_output_print_modes(struct drm_output *output); 237 238+struct drm_mode * 239+drm_output_choose_initial_mode(struct drm_device *device, 240+ struct drm_output *output, 241+ enum weston_drm_backend_output_mode mode, 242+ const char *modeline, 243+ const drmModeModeInfo *current_mode); 244+ 245 int 246 drm_output_set_mode(struct weston_output *base, 247 enum weston_drm_backend_output_mode mode, 248diff --git a/libweston/backend-drm/drm.c b/libweston/backend-drm/drm.c 249index d366e2b..23dbe38 100644 250--- a/libweston/backend-drm/drm.c 251+++ b/libweston/backend-drm/drm.c 252@@ -41,6 +41,7 @@ 253 #include <linux/vt.h> 254 #include <assert.h> 255 #include <sys/mman.h> 256+#include <sys/stat.h> 257 #include <time.h> 258 259 #include <xf86drm.h> 260@@ -75,6 +76,8 @@ 261 262 static const char default_seat[] = "seat0"; 263 264+static int config_timer_handler(void *data); 265+ 266 static inline bool 267 drm_head_is_external(struct drm_head *head) 268 { 269@@ -508,6 +511,12 @@ drm_output_update_complete(struct drm_output *output, uint32_t flags, 270 return; 271 } 272 273+ if (!sec && !usec) { 274+ weston_output_finish_frame(&output->base, NULL, 275+ WP_PRESENTATION_FEEDBACK_INVALID); 276+ return; 277+ } 278+ 279 ts.tv_sec = sec; 280 ts.tv_nsec = usec * 1000; 281 282@@ -687,8 +696,8 @@ out: 283 return; 284 } 285 286- sw = fb->width; 287- sh = fb->height; 288+ sw = fb->width * output->base.down_scale; 289+ sh = fb->height * output->base.down_scale; 290 291 dx = output->plane_bounds.x1; 292 dy = output->plane_bounds.y1; 293@@ -830,7 +839,8 @@ drm_output_repaint(struct weston_output *output_base, pixman_region32_t *damage) 294 295 weston_compositor_read_presentation_clock(b->compositor, &now); 296 now_ms = timespec_to_msec(&now); 297- if (now_ms < b->last_resize_ms + b->resize_freeze_ms) { 298+ if (now_ms < b->last_resize_ms + b->resize_freeze_ms || 299+ now_ms < output->last_resize_ms + b->resize_freeze_ms) { 300 /* Resize fullscreen/maxmium views(not always success) */ 301 if (now_ms < b->last_resize_ms + DRM_RESIZE_FREEZE_MS) 302 wl_signal_emit(&b->compositor->output_resized_signal, 303@@ -839,7 +849,7 @@ drm_output_repaint(struct weston_output *output_base, pixman_region32_t *damage) 304 weston_output_damage(output_base); 305 weston_output_finish_frame(output_base, NULL, 306 WP_PRESENTATION_FEEDBACK_INVALID); 307- return 0; 308+ goto not_repainted; 309 } 310 311 /* If planes have been disabled in the core, we might not have 312@@ -870,7 +880,8 @@ drm_output_repaint(struct weston_output *output_base, pixman_region32_t *damage) 313 314 err: 315 drm_output_state_free(state); 316- return 0; 317+not_repainted: 318+ return 1; 319 } 320 321 /* Determine the type of vblank synchronization to use for the output. 322@@ -2294,6 +2305,8 @@ drm_output_enable(struct weston_output *base) 323 output->base.switch_mode = drm_output_switch_mode; 324 output->base.set_gamma = drm_output_set_gamma; 325 326+ output->original_transform = output->base.transform; 327+ 328 output->state_invalid = true; 329 330 weston_log("Output %s (crtc %d) video modes:\n", 331@@ -3186,6 +3199,7 @@ drm_destroy(struct weston_compositor *ec) 332 333 udev_input_destroy(&b->input); 334 335+ wl_event_source_remove(b->config_timer); 336 wl_event_source_remove(b->hotplug_timer); 337 wl_event_source_remove(b->udev_drm_source); 338 wl_event_source_remove(b->drm_source); 339@@ -3606,6 +3620,10 @@ output_create_notify(struct wl_listener *listener, void *data) 340 output_create_listener); 341 342 drm_backend_update_outputs(b); 343+ 344+ /* Force reload config */ 345+ memset(&b->config_stat, 0, sizeof(b->config_stat)); 346+ config_timer_handler(b); 347 } 348 349 static const struct weston_drm_output_api api = { 350@@ -3615,6 +3633,239 @@ static const struct weston_drm_output_api api = { 351 drm_output_set_max_bpc, 352 }; 353 354+static void 355+drm_output_rotate(struct drm_output *output, int rotate) 356+{ 357+ struct drm_backend *b = to_drm_backend(output->base.compositor); 358+ uint32_t transform = output->original_transform; 359+ struct timespec now; 360+ 361+ /* Hacky way to rotate transform */ 362+ transform = (transform / 4) * 4 + (transform + rotate) % 4; 363+ 364+ if (output->base.transform == transform) 365+ return; 366+ 367+ /* Freeze output when rotating */ 368+ weston_compositor_read_presentation_clock(b->compositor, &now); 369+ output->last_resize_ms = timespec_to_msec(&now); 370+ 371+ weston_output_set_transform(&output->base, transform); 372+} 373+ 374+static void 375+drm_output_modeset(struct drm_output *output, const char *modeline) 376+{ 377+ struct drm_backend *b = to_drm_backend(output->base.compositor); 378+ struct drm_head *head = 379+ to_drm_head(weston_output_get_first_head(&output->base)); 380+ struct drm_mode *mode; 381+ struct timespec now; 382+ 383+ /* Unable to switch mode, let's retry later */ 384+ if (output->page_flip_pending || output->atomic_complete_pending) { 385+ memset(&b->config_stat, 0, sizeof(b->config_stat)); 386+ return; 387+ } 388+ 389+ mode = drm_output_choose_initial_mode(b->drm, output, 390+ WESTON_DRM_BACKEND_OUTPUT_PREFERRED, 391+ modeline, 392+ &head->inherited_mode); 393+ 394+ weston_output_mode_set_native(&output->base, &mode->base, 395+ output->base.current_scale); 396+ weston_output_damage(&output->base); 397+ 398+ mode = to_drm_mode(output->base.current_mode); 399+ 400+ weston_log("Output %s changed to %dx%d@%d for mode(%s)\n", 401+ output->base.name, 402+ mode->mode_info.hdisplay, mode->mode_info.vdisplay, 403+ mode->mode_info.vrefresh, 404+ modeline); 405+ 406+ weston_compositor_read_presentation_clock(b->compositor, &now); 407+ b->last_update_ms = timespec_to_msec(&now); 408+} 409+ 410+static void 411+drm_output_set_size(struct drm_output *output, const int w, const int h) 412+{ 413+ struct drm_backend *b = to_drm_backend(output->base.compositor); 414+ struct weston_mode *mode; 415+ struct timespec now; 416+ 417+ if (output->base.fixed_size && 418+ output->base.current_mode->width == w && 419+ output->base.current_mode->height == h) 420+ return; 421+ 422+ wl_list_for_each(mode, &output->base.mode_list, link) { 423+ mode->width = w; 424+ mode->height = h; 425+ } 426+ 427+ output->base.fixed_size = true; 428+ 429+ /* Freeze output when resizing */ 430+ weston_compositor_read_presentation_clock(b->compositor, &now); 431+ output->last_resize_ms = timespec_to_msec(&now); 432+ 433+ weston_output_set_transform(&output->base, output->base.transform); 434+ 435+ if (b->use_pixman) { 436+ drm_output_fini_pixman(output); 437+ if (drm_output_init_pixman(output, b) < 0) 438+ weston_log("failed to init output pixman state with " 439+ "new mode\n"); 440+ } else { 441+ drm_output_fini_egl(output); 442+ if (drm_output_init_egl(output, b) < 0) 443+ weston_log("failed to init output egl state with " 444+ "new mode"); 445+ } 446+ 447+ drm_output_print_modes(output); 448+} 449+ 450+static void 451+config_handle_output(struct drm_backend *b, const char *name, 452+ const char *config) 453+{ 454+ struct drm_output *output; 455+ bool is_all = !strcmp(name, "all"); 456+ 457+ wl_list_for_each(output, &b->compositor->output_list, base.link) { 458+ if (!is_all && strcmp(name, output->base.name)) 459+ continue; 460+ 461+ if (!strcmp(config, "primary")) { 462+ setenv("WESTON_DRM_PRIMARY", name, 1); 463+ hotplug_timer_handler(b->drm); 464+ } else if (!strcmp(config, "prefer")) { 465+ b->compositor->prefer_output = &output->base; 466+ } else if (!strncmp(config, "rotate", strlen("rotate"))) { 467+ int rotate = atoi(config + strlen("rotate")) / 90; 468+ drm_output_rotate(output, rotate); 469+ } else if (!strncmp(config, "mode=", strlen("mode="))) { 470+ drm_output_modeset(output, config + strlen("mode=")); 471+ } else if (!strcmp(config, "freeze")) { 472+ output->base.freezing = true; 473+ } else if (!strcmp(config, "off")) { 474+ output->base.freezing = true; 475+ if (!output->virtual) 476+ drm_set_dpms(&output->base, WESTON_DPMS_OFF); 477+ } else if (!strcmp(config, "unfreeze") || 478+ !strcmp(config, "on")) { 479+ if (!output->base.freezing) 480+ continue; 481+ 482+ output->base.freezing = false; 483+ 484+ if (!output->virtual) 485+ drm_set_dpms(&output->base, WESTON_DPMS_ON); 486+ 487+ drm_output_update_complete(output, 0, 0, 0); 488+ output->page_flip_pending = false; 489+ output->atomic_complete_pending = false; 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@@ -3958,6 +4209,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 07743ff..877e7a7 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/pixman-renderer.c b/libweston/pixman-renderer.c 817index 62c2cb1..22e7a42 100644 818--- a/libweston/pixman-renderer.c 819+++ b/libweston/pixman-renderer.c 820@@ -158,6 +158,9 @@ pixman_renderer_compute_transform(pixman_transform_t *transform_out, 821 specified buffer transform/scale */ 822 matrix = output->inverse_matrix; 823 824+ weston_matrix_scale(&matrix, 825+ 1 / output->down_scale, 1 / output->down_scale, 1); 826+ 827 if (ev->transform.enabled) { 828 weston_matrix_multiply(&matrix, &ev->transform.inverse); 829 } else { 830diff --git a/libweston/renderer-gl/gl-renderer.c b/libweston/renderer-gl/gl-renderer.c 831index db4c7b1..3437bf2 100644 832--- a/libweston/renderer-gl/gl-renderer.c 833+++ b/libweston/renderer-gl/gl-renderer.c 834@@ -1685,6 +1685,10 @@ gl_renderer_repaint_output(struct weston_output *output, 835 836 /* Calculate the global GL matrix */ 837 go->output_matrix = output->matrix; 838+ 839+ weston_matrix_scale(&go->output_matrix, 840+ output->down_scale, output->down_scale, 1); 841+ 842 weston_matrix_translate(&go->output_matrix, 843 -(output->current_mode->width / 2.0), 844 -(output->current_mode->height / 2.0), 0); 845-- 8462.20.1 847 848