1From bed745ad33c089e72475db462714079630903730 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 31/95] 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 |   6 +
13 libweston/backend-drm/drm.c          | 210 ++++++++++++++++++++++++++-
14 libweston/backend-drm/kms.c          |   2 +-
15 libweston/compositor.c               |   3 +
16 6 files changed, 224 insertions(+), 7 deletions(-)
17
18diff --git a/compositor/main.c b/compositor/main.c
19index 987c8f9..f151a77 100644
20--- a/compositor/main.c
21+++ b/compositor/main.c
22@@ -2595,6 +2595,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 463c64e..e48db31 100644
34--- a/desktop-shell/shell.c
35+++ b/desktop-shell/shell.c
36@@ -4317,10 +4317,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@@ -4447,6 +4443,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 532593e..e175f16 100644
59--- a/libweston/backend-drm/drm-internal.h
60+++ b/libweston/backend-drm/drm-internal.h
61@@ -370,6 +370,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 {
71@@ -667,6 +670,8 @@ void
72 drm_output_destroy(struct weston_output *output_base);
73 void
74 drm_virtual_output_destroy(struct weston_output *output_base);
75+void
76+drm_dummy_output_destroy(struct weston_output *output_base);
77
78 static inline struct drm_output *
79 to_drm_output(struct weston_output *base)
80@@ -675,6 +680,7 @@ to_drm_output(struct weston_output *base)
81 #ifdef BUILD_DRM_VIRTUAL
82 	    base->destroy != drm_virtual_output_destroy &&
83 #endif
84+	    base->destroy != drm_dummy_output_destroy &&
85 	    base->destroy != drm_output_destroy)
86 		return NULL;
87 	return container_of(base, struct drm_output, base);
88diff --git a/libweston/backend-drm/drm.c b/libweston/backend-drm/drm.c
89index 2dc38b5..9d4354d 100644
90--- a/libweston/backend-drm/drm.c
91+++ b/libweston/backend-drm/drm.c
92@@ -213,8 +213,14 @@ drm_backend_update_outputs(struct drm_backend *b)
93 {
94 	struct weston_output *primary;
95
96-	if (!b->primary_head)
97+	if (!b->primary_head) {
98+		if (!b->dummy_output->enabled)
99+			weston_output_enable(b->dummy_output);
100 		return;
101+	} else {
102+		if (b->dummy_output->enabled)
103+			weston_output_disable(b->dummy_output);
104+	}
105
106 	primary = b->primary_head->base.output;
107
108@@ -1275,6 +1281,10 @@ drm_output_find_special_plane(struct drm_device *device,
109 		struct weston_output *base;
110 		bool found_elsewhere = false;
111
112+		/* Ignore non-real planes */
113+		if (!plane->plane_id)
114+			continue;
115+
116 		if (plane->type != type)
117 			continue;
118 		if (!drm_plane_is_available(plane, output))
119@@ -2710,11 +2720,15 @@ drm_head_destroy(struct weston_head *base)
120
121 	weston_head_release(&head->base);
122
123+	if (!head->connector.connector_id)
124+		goto out;
125+
126 	drm_connector_fini(&head->connector);
127
128 	if (head->backlight)
129 		backlight_destroy(head->backlight);
130
131+out:
132 	free(head);
133 }
134
135@@ -2951,8 +2965,9 @@ drm_backend_update_connectors(struct drm_device *device,
136 	wl_list_for_each_safe(base, base_next,
137 			      &b->compositor->head_list, compositor_link) {
138 		head = to_drm_head(base);
139-		if (!head)
140+		if (!head || !head->connector.connector_id)
141 			continue;
142+
143 		connector_id = head->connector.connector_id;
144
145 		if (head->connector.device != device)
146@@ -3000,6 +3015,9 @@ drm_backend_update_connectors(struct drm_device *device,
147 				continue;
148
149 			head = to_drm_head(base);
150+			if (!head || !head->connector.connector_id)
151+				continue;
152+
153 			conn = head->connector.conn;
154
155 			if (conn->connection != DRM_MODE_CONNECTED ||
156@@ -3029,6 +3047,8 @@ drm_backend_update_connectors(struct drm_device *device,
157 	}
158 match_done:
159
160+	weston_head_set_connection_status(&b->dummy_head->base,
161+					  !b->primary_head);
162 	drm_backend_update_outputs(b);
163
164 	weston_compositor_read_presentation_clock(b->compositor, &now);
165@@ -3204,6 +3224,11 @@ drm_destroy(struct weston_compositor *ec)
166 	struct drm_crtc *crtc, *crtc_tmp;
167 	struct drm_writeback *writeback, *writeback_tmp;
168
169+	weston_output_destroy(b->dummy_output);
170+
171+	if (b->dummy_head)
172+		drm_head_destroy(&b->dummy_head->base);
173+
174 	udev_input_destroy(&b->input);
175
176 	wl_event_source_remove(b->config_timer);
177@@ -3906,6 +3931,182 @@ config_timer_handler(void *data)
178 	return 0;
179 }
180
181+static int
182+drm_dummy_output_start_repaint_loop(struct weston_output *output_base)
183+{
184+	weston_output_finish_frame(output_base, NULL,
185+				   WP_PRESENTATION_FEEDBACK_INVALID);
186+
187+	return 0;
188+}
189+
190+static int
191+drm_dummy_output_repaint(struct weston_output *output_base,
192+			   pixman_region32_t *damage)
193+{
194+	struct drm_backend *b = to_drm_backend(output_base->compositor);
195+
196+	wl_signal_emit(&output_base->frame_signal, damage);
197+
198+	if (b->use_pixman)
199+		return -1;
200+
201+	/* Switch GL output context to avoid corruption */
202+	output_base->compositor->renderer->repaint_output(output_base, damage);
203+	return -1;
204+}
205+
206+static int
207+drm_dummy_output_enable(struct weston_output *output_base)
208+{
209+	struct drm_backend *b = to_drm_backend(output_base->compositor);
210+	struct drm_output *output = to_drm_output(output_base);
211+
212+	if (b->use_pixman)
213+		return 0;
214+
215+	return drm_output_init_egl(output, b);
216+}
217+
218+static int
219+drm_dummy_output_disable(struct weston_output *output_base)
220+{
221+	struct drm_backend *b = to_drm_backend(output_base->compositor);
222+	struct drm_output *output = to_drm_output(output_base);
223+
224+	if (!b->use_pixman)
225+		drm_output_fini_egl(output);
226+
227+	return 0;
228+}
229+
230+void
231+drm_dummy_output_destroy(struct weston_output *output_base)
232+{
233+	struct drm_output *output = to_drm_output(output_base);
234+	struct drm_plane *plane = output->scanout_plane;
235+	struct weston_mode *mode, *next;
236+
237+	if (output->base.enabled)
238+		drm_dummy_output_disable(&output->base);
239+
240+	wl_list_for_each_safe(mode, next, &output_base->mode_list, link) {
241+		wl_list_remove(&mode->link);
242+		free(mode);
243+	}
244+
245+	drm_plane_state_free(plane->state_cur, true);
246+	weston_plane_release(&plane->base);
247+	wl_list_remove(&plane->link);
248+	weston_drm_format_array_fini(&plane->formats);
249+	free(plane);
250+
251+	weston_output_release(output_base);
252+	free(output);
253+}
254+
255+static struct weston_output *
256+drm_dummy_output_create(struct drm_device *device)
257+{
258+	struct drm_backend *b = device->backend;
259+	struct drm_output *output;
260+	struct drm_plane *plane;
261+	struct weston_drm_format *fmt;
262+
263+	output = zalloc(sizeof *output);
264+	if (!output)
265+		return NULL;
266+
267+	output->device = device;
268+	output->crtc = NULL;
269+
270+#ifdef BUILD_DRM_GBM
271+	output->gbm_bo_flags = GBM_BO_USE_LINEAR | GBM_BO_USE_RENDERING;
272+	output->gbm_format = DRM_FORMAT_XRGB8888;
273+#endif
274+
275+	weston_output_init(&output->base, b->compositor, "DUMMY");
276+
277+	output->base.enable = drm_dummy_output_enable;
278+	output->base.destroy = drm_dummy_output_destroy;
279+	output->base.disable = drm_dummy_output_disable;
280+
281+	output->base.start_repaint_loop = drm_dummy_output_start_repaint_loop;
282+	output->base.repaint = drm_dummy_output_repaint;
283+	output->base.unavailable = true;
284+
285+	weston_compositor_add_pending_output(&output->base, b->compositor);
286+
287+	plane = zalloc(sizeof(*plane));
288+	if (!plane) {
289+		weston_output_release(&output->base);
290+		free(output);
291+		return NULL;
292+	}
293+
294+	plane->type = WDRM_PLANE_TYPE_PRIMARY;
295+	plane->device = device;
296+	plane->state_cur = drm_plane_state_alloc(NULL, plane);
297+	plane->state_cur->complete = true;
298+
299+	weston_drm_format_array_init(&plane->formats);
300+	fmt = weston_drm_format_array_add_format(&plane->formats,
301+						 output->gbm_format);
302+	weston_drm_format_add_modifier(fmt, DRM_FORMAT_MOD_LINEAR);
303+
304+	weston_plane_init(&plane->base, b->compositor, 0, 0);
305+	wl_list_insert(&device->plane_list, &plane->link);
306+
307+	output->scanout_plane = plane;
308+
309+	return &output->base;
310+}
311+
312+static int drm_backend_init_dummy(struct drm_backend *b)
313+{
314+	struct weston_mode *mode;
315+
316+	b->dummy_output = drm_dummy_output_create(b->drm);
317+	if (!b->dummy_output)
318+		return -1;
319+
320+	mode = zalloc(sizeof *mode);
321+	if (!mode)
322+		goto err;
323+
324+	mode->flags = WL_OUTPUT_MODE_CURRENT;
325+	mode->width = 1920;
326+	mode->height = 1080;
327+	mode->refresh = 60 * 1000LL;
328+
329+	wl_list_insert(b->dummy_output->mode_list.prev, &mode->link);
330+
331+	b->dummy_output->current_mode = mode;
332+
333+	weston_output_set_scale(b->dummy_output, 1);
334+	weston_output_set_transform(b->dummy_output,
335+				    WL_OUTPUT_TRANSFORM_NORMAL);
336+
337+	b->dummy_head = zalloc(sizeof *b->dummy_head);
338+	if (!b->dummy_head)
339+		goto err;
340+
341+	weston_head_init(&b->dummy_head->base, "DUMMY");
342+
343+	b->dummy_head->base.backend_id = drm_head_destroy;
344+
345+	weston_head_set_monitor_strings(&b->dummy_head->base,
346+					"DUMMY", "DUMMY", "DUMMY");
347+	weston_compositor_add_head(b->compositor, &b->dummy_head->base);
348+	weston_output_attach_head(b->dummy_output, &b->dummy_head->base);
349+
350+	return 0;
351+err:
352+	drm_dummy_output_destroy(b->dummy_output);
353+	b->dummy_output = NULL;
354+	return -1;
355+}
356+
357 enum drm_head_mode {
358 	DRM_HEAD_MODE_DEFAULT,
359 	DRM_HEAD_MODE_PRIMARY,
360@@ -4143,6 +4344,11 @@ drm_backend_create(struct weston_compositor *compositor,
361 		goto err_sprite;
362 	}
363
364+	if (drm_backend_init_dummy(b) < 0) {
365+		weston_log("Failed to init dummy output\n");
366+		goto err_udev_input;
367+	}
368+
369 	wl_list_init(&b->drm->writeback_connector_list);
370 	if (drm_backend_update_connectors(b->drm, drm_device) < 0) {
371 		weston_log("Failed to create heads for %s\n", b->drm->drm.filename);
372diff --git a/libweston/backend-drm/kms.c b/libweston/backend-drm/kms.c
373index 0008e83..fb43c43 100644
374--- a/libweston/backend-drm/kms.c
375+++ b/libweston/backend-drm/kms.c
376@@ -1196,7 +1196,7 @@ drm_pending_state_apply_atomic(struct drm_pending_state *pending_state,
377 				 &b->compositor->head_list, compositor_link) {
378 			struct drm_property_info *info;
379 			head = to_drm_head(head_base);
380-			if (!head)
381+			if (!head || head == b->dummy_head)
382 				continue;
383
384 			if (weston_head_is_enabled(head_base))
385diff --git a/libweston/compositor.c b/libweston/compositor.c
386index 74b21ac..1f48796 100644
387--- a/libweston/compositor.c
388+++ b/libweston/compositor.c
389@@ -6932,6 +6932,9 @@ weston_output_set_color_outcome(struct weston_output *output)
390 	struct weston_color_manager *cm = output->compositor->color_manager;
391 	struct weston_output_color_outcome *colorout;
392
393+	if (!cm)
394+		return false;
395+
396 	colorout = cm->create_output_color_outcome(cm, output);
397 	if (!colorout) {
398 		weston_log("Creating color transformation for output \"%s\" failed.\n",
399--
4002.20.1
401
402