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