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