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