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