1From 54619af12a927bbef47382587f977e8ca6062625 Mon Sep 17 00:00:00 2001
2From: Jeffy Chen <jeffy.chen@rock-chips.com>
3Date: Thu, 12 Nov 2020 16:59:50 +0800
4Subject: [PATCH 28/79] backend-drm: Add dummy output when no screens connected
5
6Some clients are not expecting no screens, add a dummy output for them.
7
8Signed-off-by: Jeffy Chen <jeffy.chen@rock-chips.com>
9---
10 compositor/main.c                    |   3 +
11 desktop-shell/shell.c                |   7 +-
12 libweston/backend-drm/drm-internal.h |   3 +
13 libweston/backend-drm/drm.c          | 203 ++++++++++++++++++++++++++-
14 libweston/backend-drm/kms.c          |   3 +
15 libweston/compositor.c               |   3 +
16 6 files changed, 216 insertions(+), 6 deletions(-)
17
18diff --git a/compositor/main.c b/compositor/main.c
19index 128016b..3824404 100644
20--- a/compositor/main.c
21+++ b/compositor/main.c
22@@ -2337,6 +2337,9 @@ drm_heads_changed(struct wl_listener *listener, void *arg)
23 	 * output.
24 	 */
25 	while ((head = weston_compositor_iterate_heads(compositor, head))) {
26+		if (!strcasecmp(weston_head_get_name(head), "dummy"))
27+			continue;
28+
29 		drm_head_update_output_section(head);
30
31 		connected = weston_head_is_connected(head);
32diff --git a/desktop-shell/shell.c b/desktop-shell/shell.c
33index 4cb29dd..a8b8f35 100644
34--- a/desktop-shell/shell.c
35+++ b/desktop-shell/shell.c
36@@ -4820,10 +4820,6 @@ shell_reposition_view_on_output_change(struct weston_view *view)
37 	shsurf = get_shell_surface(view->surface);
38 	if (!shsurf)
39 		return;
40-
41-	shsurf->saved_position_valid = false;
42-	set_maximized(shsurf, false);
43-	set_fullscreen(shsurf, false, NULL);
44 }
45
46 void
47@@ -4955,6 +4951,9 @@ handle_output_resized(struct wl_listener *listener, void *data)
48 	struct weston_output *output = (struct weston_output *)data;
49 	struct shell_output *sh_output = find_shell_output_from_weston_output(shell, output);
50
51+	if (!sh_output)
52+		return;
53+
54 	if (shell->lock_surface)
55 		shell->lock_surface->committed(shell->lock_surface, 0, 0);
56
57diff --git a/libweston/backend-drm/drm-internal.h b/libweston/backend-drm/drm-internal.h
58index 9d24017..67e6dd2 100644
59--- a/libweston/backend-drm/drm-internal.h
60+++ b/libweston/backend-drm/drm-internal.h
61@@ -354,6 +354,9 @@ struct drm_backend {
62
63 	struct wl_event_source *config_timer;
64 	struct stat config_stat;
65+
66+	struct weston_output *dummy_output;
67+	struct drm_head *dummy_head;
68 };
69
70 struct drm_mode {
71diff --git a/libweston/backend-drm/drm.c b/libweston/backend-drm/drm.c
72index 53a3d49..e829d77 100644
73--- a/libweston/backend-drm/drm.c
74+++ b/libweston/backend-drm/drm.c
75@@ -210,8 +210,14 @@ drm_backend_update_outputs(struct drm_backend *b)
76 {
77 	struct weston_output *base, *primary;
78
79-	if (!b->primary_head)
80+	if (!b->primary_head) {
81+		if (!b->dummy_output->enabled)
82+			weston_output_enable(b->dummy_output);
83 		return;
84+	} else {
85+		if (b->dummy_output->enabled)
86+			weston_output_disable(b->dummy_output);
87+	}
88
89 	primary = b->primary_head->base.output;
90
91@@ -1245,7 +1251,7 @@ drm_output_find_special_plane(struct drm_backend *b, struct drm_output *output,
92 		    num_primary - 1 != output->crtc->pipe)
93 			continue;
94
95-		if (plane->type != type)
96+		if (!plane->plane_id || plane->type != type)
97 			continue;
98 		if (!drm_plane_is_available(plane, output))
99 			continue;
100@@ -2591,11 +2597,15 @@ drm_head_destroy(struct drm_head *head)
101 {
102 	weston_head_release(&head->base);
103
104+	if (!head->connector.connector_id)
105+		goto out;
106+
107 	drm_connector_fini(&head->connector);
108
109 	if (head->backlight)
110 		backlight_destroy(head->backlight);
111
112+out:
113 	free(head);
114 }
115
116@@ -2827,6 +2837,9 @@ drm_backend_update_connectors(struct drm_backend *b, struct udev_device *drm_dev
117 	wl_list_for_each_safe(base, base_next,
118 			      &b->compositor->head_list, compositor_link) {
119 		head = to_drm_head(base);
120+		if (!head->connector.connector_id)
121+			continue;
122+
123 		connector_id = head->connector.connector_id;
124
125 		if (resources_has_connector(resources, connector_id))
126@@ -2871,6 +2884,9 @@ drm_backend_update_connectors(struct drm_backend *b, struct udev_device *drm_dev
127 				continue;
128
129 			head = to_drm_head(base);
130+			if (!head->connector.connector_id)
131+				continue;
132+
133 			conn = head->connector.conn;
134
135 			if (conn->connection != DRM_MODE_CONNECTED ||
136@@ -2900,6 +2916,8 @@ drm_backend_update_connectors(struct drm_backend *b, struct udev_device *drm_dev
137 	}
138 match_done:
139
140+	weston_head_set_connection_status(&b->dummy_head->base,
141+					  !b->primary_head);
142 	drm_backend_update_outputs(b);
143
144 	weston_compositor_read_presentation_clock(b->compositor, &now);
145@@ -3072,6 +3090,8 @@ drm_destroy(struct weston_compositor *ec)
146 	struct drm_crtc *crtc, *crtc_tmp;
147 	struct drm_writeback *writeback, *writeback_tmp;
148
149+	weston_output_destroy(b->dummy_output);
150+
151 	udev_input_destroy(&b->input);
152
153 	wl_event_source_remove(b->config_timer);
154@@ -3776,6 +3796,180 @@ config_timer_handler(void *data)
155 	return 0;
156 }
157
158+static int
159+drm_dummy_output_start_repaint_loop(struct weston_output *output_base)
160+{
161+	weston_output_finish_frame(output_base, NULL,
162+				   WP_PRESENTATION_FEEDBACK_INVALID);
163+
164+	return 0;
165+}
166+
167+static int
168+drm_dummy_output_repaint(struct weston_output *output_base,
169+			   pixman_region32_t *damage,
170+			   void *repaint_data)
171+{
172+	struct drm_backend *b = to_drm_backend(output_base->compositor);
173+
174+	wl_signal_emit(&output_base->frame_signal, damage);
175+
176+	if (b->use_pixman)
177+		return -1;
178+
179+	/* Switch GL output context to avoid corruption */
180+	output_base->compositor->renderer->repaint_output(output_base, damage);
181+	return -1;
182+}
183+
184+static int
185+drm_dummy_output_enable(struct weston_output *output_base)
186+{
187+	struct drm_backend *b = to_drm_backend(output_base->compositor);
188+	struct drm_output *output = to_drm_output(output_base);
189+
190+	if (b->use_pixman)
191+		return 0;
192+
193+	return drm_output_init_egl(output, b);
194+}
195+
196+static int
197+drm_dummy_output_disable(struct weston_output *output_base)
198+{
199+	struct drm_backend *b = to_drm_backend(output_base->compositor);
200+	struct drm_output *output = to_drm_output(output_base);
201+
202+	if (!b->use_pixman)
203+		drm_output_fini_egl(output);
204+
205+	return 0;
206+}
207+
208+static void
209+drm_dummy_output_destroy(struct weston_output *output_base)
210+{
211+	struct drm_output *output = to_drm_output(output_base);
212+	struct drm_plane *plane = output->scanout_plane;
213+	struct weston_mode *mode, *next;
214+
215+	if (output->base.enabled)
216+		drm_dummy_output_disable(&output->base);
217+
218+	wl_list_for_each_safe(mode, next, &output_base->mode_list, link) {
219+		wl_list_remove(&mode->link);
220+		free(mode);
221+	}
222+
223+	drm_plane_state_free(plane->state_cur, true);
224+	weston_plane_release(&plane->base);
225+	wl_list_remove(&plane->link);
226+	weston_drm_format_array_fini(&plane->formats);
227+	free(plane);
228+
229+	weston_output_release(output_base);
230+	free(output);
231+}
232+
233+static struct weston_output *
234+drm_dummy_output_create(struct drm_backend *b)
235+{
236+	struct drm_output *output;
237+	struct drm_plane *plane;
238+	struct weston_drm_format *fmt;
239+
240+	output = zalloc(sizeof *output);
241+	if (!output)
242+		return NULL;
243+
244+	weston_output_init(&output->base, b->compositor, "DUMMY");
245+
246+	output->base.enable = drm_dummy_output_enable;
247+	output->base.destroy = drm_dummy_output_destroy;
248+	output->base.disable = drm_dummy_output_disable;
249+
250+	output->base.start_repaint_loop = drm_dummy_output_start_repaint_loop;
251+	output->base.repaint = drm_dummy_output_repaint;
252+	output->base.set_dpms = NULL;
253+	output->base.switch_mode = NULL;
254+	output->base.gamma_size = 0;
255+	output->base.set_gamma = NULL;
256+	output->base.unavailable = true;
257+
258+	weston_compositor_add_pending_output(&output->base, b->compositor);
259+
260+#ifdef BUILD_DRM_GBM
261+	output->gbm_bo_flags = GBM_BO_USE_LINEAR | GBM_BO_USE_RENDERING;
262+	output->gbm_format = DRM_FORMAT_XRGB8888;
263+#endif
264+
265+	plane = zalloc(sizeof(*plane));
266+	if (!plane) {
267+		weston_output_release(&output->base);
268+		free(output);
269+		return NULL;
270+	}
271+
272+	plane->type = WDRM_PLANE_TYPE_PRIMARY;
273+	plane->backend = b;
274+	plane->state_cur = drm_plane_state_alloc(NULL, plane);
275+	plane->state_cur->complete = true;
276+
277+	weston_drm_format_array_init(&plane->formats);
278+	fmt = weston_drm_format_array_add_format(&plane->formats,
279+						 output->gbm_format);
280+	weston_drm_format_add_modifier(fmt, DRM_FORMAT_MOD_LINEAR);
281+
282+	weston_plane_init(&plane->base, b->compositor, 0, 0);
283+	wl_list_insert(&b->plane_list, &plane->link);
284+
285+	output->scanout_plane = plane;
286+
287+	return &output->base;
288+}
289+
290+static int drm_backend_init_dummy(struct drm_backend *b)
291+{
292+	struct weston_mode *mode;
293+
294+	b->dummy_output = drm_dummy_output_create(b);
295+	if (!b->dummy_output)
296+		return -1;
297+
298+	mode = zalloc(sizeof *mode);
299+	if (!mode)
300+		goto err;
301+
302+	mode->flags = WL_OUTPUT_MODE_CURRENT;
303+	mode->width = 1920;
304+	mode->height = 1080;
305+	mode->refresh = 60 * 1000LL;
306+
307+	wl_list_insert(b->dummy_output->mode_list.prev, &mode->link);
308+
309+	b->dummy_output->current_mode = mode;
310+
311+	weston_output_set_scale(b->dummy_output, 1);
312+	weston_output_set_transform(b->dummy_output,
313+				    WL_OUTPUT_TRANSFORM_NORMAL);
314+
315+	b->dummy_head = zalloc(sizeof *b->dummy_head);
316+	if (!b->dummy_head)
317+		goto err;
318+
319+	weston_head_init(&b->dummy_head->base, "DUMMY");
320+	weston_head_set_monitor_strings(&b->dummy_head->base,
321+					"DUMMY", "DUMMY", "DUMMY");
322+	weston_compositor_add_head(b->compositor, &b->dummy_head->base);
323+	weston_output_attach_head(b->dummy_output, &b->dummy_head->base);
324+
325+	return 0;
326+err:
327+	drm_dummy_output_destroy(b->dummy_output);
328+	b->dummy_output = NULL;
329+	return -1;
330+}
331+
332 enum drm_head_mode {
333 	DRM_HEAD_MODE_DEFAULT,
334 	DRM_HEAD_MODE_PRIMARY,
335@@ -4007,6 +4201,11 @@ drm_backend_create(struct weston_compositor *compositor,
336 		goto err_sprite;
337 	}
338
339+	if (drm_backend_init_dummy(b) < 0) {
340+		weston_log("Failed to init dummy output\n");
341+		goto err_udev_input;
342+	}
343+
344 	wl_list_init(&b->writeback_connector_list);
345 	if (drm_backend_update_connectors(b, drm_device) < 0) {
346 		weston_log("Failed to create heads for %s\n", b->drm.filename);
347diff --git a/libweston/backend-drm/kms.c b/libweston/backend-drm/kms.c
348index 4b5ba42..a3c55bd 100644
349--- a/libweston/backend-drm/kms.c
350+++ b/libweston/backend-drm/kms.c
351@@ -1170,6 +1170,9 @@ drm_pending_state_apply_atomic(struct drm_pending_state *pending_state,
352 				continue;
353
354 			head = to_drm_head(head_base);
355+			if (head == b->dummy_head)
356+				continue;
357+
358 			connector_id = head->connector.connector_id;
359
360 			drm_debug(b, "\t\t[atomic] disabling inactive head %s\n",
361diff --git a/libweston/compositor.c b/libweston/compositor.c
362index 121871c..67766df 100644
363--- a/libweston/compositor.c
364+++ b/libweston/compositor.c
365@@ -6436,6 +6436,9 @@ weston_output_set_color_transforms(struct weston_output *output)
366 	struct weston_color_transform *sRGB_to_blend = NULL;
367 	bool ok;
368
369+	if (!cm)
370+		return false;
371+
372 	ok = cm->get_output_color_transform(cm, output, &blend_to_output);
373 	ok = ok && cm->get_sRGB_to_output_color_transform(cm, output,
374 							  &sRGB_to_output);
375--
3762.20.1
377
378