xref: /OK3568_Linux_fs/buildroot/package/weston/0016-backend-drm-Support-virtual-screen-size.patch (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1From 2a839667bac950c484e109560cd380af760e3781 Mon Sep 17 00:00:00 2001
2From: Jeffy Chen <jeffy.chen@rock-chips.com>
3Date: Wed, 24 Jun 2020 11:59:42 +0800
4Subject: [PATCH 16/93] backend-drm: Support virtual screen size
5
6Support setting virtual screen size, for example:
7export WESTON_DRM_VIRTUAL_SIZE=1024x768
8
9Signed-off-by: Jeffy Chen <jeffy.chen@rock-chips.com>
10---
11 libweston/backend-drm/drm-internal.h |  22 +++++
12 libweston/backend-drm/drm.c          |  22 ++++-
13 libweston/backend-drm/kms.c          | 115 ++++++++++++++++++++++-----
14 libweston/backend-drm/modes.c        |  22 ++++-
15 4 files changed, 155 insertions(+), 26 deletions(-)
16
17diff --git a/libweston/backend-drm/drm-internal.h b/libweston/backend-drm/drm-internal.h
18index ec8bf0e..af82922 100644
19--- a/libweston/backend-drm/drm-internal.h
20+++ b/libweston/backend-drm/drm-internal.h
21@@ -166,6 +166,7 @@ enum wdrm_plane_property {
22 	WDRM_PLANE_IN_FENCE_FD,
23 	WDRM_PLANE_FB_DAMAGE_CLIPS,
24 	WDRM_PLANE_ZPOS,
25+	WDRM_PLANE_FEATURE,
26 	WDRM_PLANE__COUNT
27 };
28
29@@ -179,6 +180,15 @@ enum wdrm_plane_type {
30 	WDRM_PLANE_TYPE__COUNT
31 };
32
33+/**
34+ * Possible values for the WDRM_PLANE_FEATURE property.
35+ */
36+enum wdrm_plane_feature {
37+	WDRM_PLANE_FEATURE_SCALE = 0,
38+	WDRM_PLANE_FEATURE_ALPHA,
39+	WDRM_PLANE_FEATURE__COUNT
40+};
41+
42 /**
43  * List of properties attached to a DRM connector
44  */
45@@ -349,6 +359,9 @@ struct drm_backend {
46 	drm_head_match_t *head_matches;
47 	struct drm_head *primary_head;
48 	struct wl_listener output_create_listener;
49+
50+	int virtual_width;
51+	int virtual_height;
52 };
53
54 struct drm_mode {
55@@ -508,6 +521,8 @@ struct drm_plane {
56 	struct wl_list link;
57
58 	struct weston_drm_format_array formats;
59+
60+	bool can_scale;
61 };
62
63 struct drm_connector {
64@@ -613,6 +628,9 @@ struct drm_output {
65 	submit_frame_cb virtual_submit_frame;
66
67 	bool state_invalid;
68+
69+	/* The dummy framebuffer for SET_CRTC. */
70+	struct drm_fb *fb_dummy;
71 };
72
73 void
74@@ -726,6 +744,10 @@ uint64_t
75 drm_property_get_value(struct drm_property_info *info,
76 		       const drmModeObjectProperties *props,
77 		       uint64_t def);
78+bool
79+drm_property_has_feature(struct drm_property_info *infos,
80+			 const drmModeObjectProperties *props,
81+			 enum wdrm_plane_feature feature);
82 uint64_t *
83 drm_property_get_range_values(struct drm_property_info *info,
84 			      const drmModeObjectProperties *props);
85diff --git a/libweston/backend-drm/drm.c b/libweston/backend-drm/drm.c
86index f5ac1b6..a2f215f 100644
87--- a/libweston/backend-drm/drm.c
88+++ b/libweston/backend-drm/drm.c
89@@ -331,6 +331,11 @@ drm_output_update_complete(struct drm_output *output, uint32_t flags,
90 		output->state_last = NULL;
91 	}
92
93+	if (output->fb_dummy) {
94+		drm_fb_unref(output->fb_dummy);
95+		output->fb_dummy = NULL;
96+	}
97+
98 	if (output->destroy_pending) {
99 		output->destroy_pending = false;
100 		output->disable_pending = false;
101@@ -411,6 +416,7 @@ drm_output_render(struct drm_output_state *state, pixman_region32_t *damage)
102 	struct drm_property_info *damage_info =
103 		&scanout_plane->props[WDRM_PLANE_FB_DAMAGE_CLIPS];
104 	struct drm_backend *b = device->backend;
105+	struct drm_mode *mode;
106 	struct drm_fb *fb;
107 	pixman_region32_t scanout_damage;
108 	pixman_box32_t *rects;
109@@ -454,10 +460,11 @@ drm_output_render(struct drm_output_state *state, pixman_region32_t *damage)
110 	scanout_state->src_w = fb->width << 16;
111 	scanout_state->src_h = fb->height << 16;
112
113+	mode = to_drm_mode(output->base.current_mode);
114 	scanout_state->dest_x = 0;
115 	scanout_state->dest_y = 0;
116-	scanout_state->dest_w = output->base.current_mode->width;
117-	scanout_state->dest_h = output->base.current_mode->height;
118+	scanout_state->dest_w = mode->mode_info.hdisplay;
119+	scanout_state->dest_h = mode->mode_info.vdisplay;
120
121 	pixman_region32_subtract(&c->primary_plane.damage,
122 				 &c->primary_plane.damage, damage);
123@@ -521,7 +528,7 @@ drm_output_repaint(struct weston_output *output_base, pixman_region32_t *damage)
124
125 	weston_compositor_read_presentation_clock(b->compositor, &now);
126 	now_ms = timespec_to_msec(&now);
127-	if (now_ms < b->last_resize_ms + DRM_RESIZE_FREEZE_MS) {
128+	if (now_ms < b->last_resize_ms + b->resize_freeze_ms) {
129 		/* Resize fullscreen/maxmium views(not always success) */
130 		if (now_ms < b->last_resize_ms + DRM_RESIZE_FREEZE_MS)
131 			wl_signal_emit(&b->compositor->output_resized_signal,
132@@ -879,6 +886,11 @@ drm_plane_create(struct drm_device *device, const drmModePlane *kplane)
133 				       props,
134 				       WDRM_PLANE_TYPE__COUNT);
135
136+	plane->can_scale =
137+		drm_property_has_feature(plane->props,
138+					 props,
139+					 WDRM_PLANE_FEATURE_SCALE);
140+
141 	zpos_range_values =
142 		drm_property_get_range_values(&plane->props[WDRM_PLANE_ZPOS],
143 					      props);
144@@ -3420,6 +3432,10 @@ drm_backend_create(struct weston_compositor *compositor,
145
146 	b->head_matches = drm_head_matches[head_mode];
147
148+	buf = getenv("WESTON_DRM_VIRTUAL_SIZE");
149+	if (buf)
150+		sscanf(buf, "%dx%d", &b->virtual_width, &b->virtual_height);
151+
152 	buf = getenv("WESTON_DRM_RESIZE_FREEZE_MS");
153 	if (buf)
154 		b->resize_freeze_ms = atoi(buf);
155diff --git a/libweston/backend-drm/kms.c b/libweston/backend-drm/kms.c
156index c7dc2f8..0008e83 100644
157--- a/libweston/backend-drm/kms.c
158+++ b/libweston/backend-drm/kms.c
159@@ -56,6 +56,15 @@ struct drm_property_enum_info plane_type_enums[] = {
160 	},
161 };
162
163+struct drm_property_enum_info plane_feature_enums[] = {
164+	[WDRM_PLANE_FEATURE_SCALE] = {
165+		.name = "scale",
166+	},
167+	[WDRM_PLANE_FEATURE_ALPHA] = {
168+		.name = "alpha",
169+	},
170+};
171+
172 const struct drm_property_info plane_props[] = {
173 	[WDRM_PLANE_TYPE] = {
174 		.name = "type",
175@@ -76,6 +85,11 @@ const struct drm_property_info plane_props[] = {
176 	[WDRM_PLANE_IN_FENCE_FD] = { .name = "IN_FENCE_FD" },
177 	[WDRM_PLANE_FB_DAMAGE_CLIPS] = { .name = "FB_DAMAGE_CLIPS" },
178 	[WDRM_PLANE_ZPOS] = { .name = "zpos" },
179+	[WDRM_PLANE_FEATURE] = {
180+		.name = "FEATURE",
181+		.enum_values = plane_feature_enums,
182+		.num_enum_values = WDRM_PLANE_FEATURE__COUNT,
183+	},
184 };
185
186 struct drm_property_enum_info dpms_state_enums[] = {
187@@ -217,6 +231,31 @@ drm_property_get_value(struct drm_property_info *info,
188 	return def;
189 }
190
191+bool
192+drm_property_has_feature(struct drm_property_info *infos,
193+			 const drmModeObjectProperties *props,
194+			 enum wdrm_plane_feature feature)
195+{
196+	struct drm_property_info *info = &infos[WDRM_PLANE_FEATURE];
197+	unsigned int i;
198+
199+	if (info->prop_id == 0 ||
200+	    feature >= info->num_enum_values ||
201+	    !info->enum_values[feature].valid)
202+		return false;
203+
204+	for (i = 0; i < props->count_props; i++) {
205+		if (props->props[i] != info->prop_id)
206+			continue;
207+
208+		if (props->prop_values[i] &
209+		    (1LL << info->enum_values[feature].value))
210+			return true;
211+	}
212+
213+	return false;
214+}
215+
216 /**
217  * Get the current range values of a KMS property
218  *
219@@ -337,9 +376,11 @@ drm_property_info_populate(struct drm_device *device,
220 		}
221
222 		if (info[j].num_enum_values == 0 &&
223-		    (prop->flags & DRM_MODE_PROP_ENUM)) {
224+		    (prop->flags & DRM_MODE_PROP_ENUM ||
225+		     prop->flags & DRM_MODE_PROP_BITMASK)) {
226 			weston_log("DRM: expected property %s to not be an"
227-			           " enum, but it is; ignoring\n", prop->name);
228+			           " enum or bitmask, but it is; ignoring\n",
229+				   prop->name);
230 			drmModeFreeProperty(prop);
231 			continue;
232 		}
233@@ -360,9 +401,11 @@ drm_property_info_populate(struct drm_device *device,
234 			continue;
235 		}
236
237-		if (!(prop->flags & DRM_MODE_PROP_ENUM)) {
238-			weston_log("DRM: expected property %s to be an enum,"
239-				   " but it is not; ignoring\n", prop->name);
240+		if (!(prop->flags & DRM_MODE_PROP_ENUM ||
241+		      prop->flags & DRM_MODE_PROP_BITMASK)) {
242+			weston_log("DRM: expected property %s to be an enum or "
243+				   "bitmask, but it is not; ignoring\n",
244+				   prop->name);
245 			drmModeFreeProperty(prop);
246 			info[j].prop_id = 0;
247 			continue;
248@@ -639,6 +682,7 @@ drm_output_apply_state_legacy(struct drm_output_state *state)
249 	int n_conn = 0;
250 	struct timespec now;
251 	int ret = 0;
252+	bool scaling;
253
254 	wl_list_for_each(head, &output->base.head_list, base.output_link) {
255 		assert(n_conn < MAX_CLONED_CONNECTORS);
256@@ -686,30 +730,36 @@ drm_output_apply_state_legacy(struct drm_output_state *state)
257 	if (!scanout_state || !scanout_state->fb)
258 		return 0;
259
260-	/* The legacy SetCrtc API doesn't allow us to do scaling, and the
261-	 * legacy PageFlip API doesn't allow us to do clipping either. */
262-	assert(scanout_state->src_x == 0);
263-	assert(scanout_state->src_y == 0);
264-	assert(scanout_state->src_w ==
265-		(unsigned) (output->base.current_mode->width << 16));
266-	assert(scanout_state->src_h ==
267-		(unsigned) (output->base.current_mode->height << 16));
268-	assert(scanout_state->dest_x == 0);
269-	assert(scanout_state->dest_y == 0);
270-	assert(scanout_state->dest_w == scanout_state->src_w >> 16);
271-	assert(scanout_state->dest_h == scanout_state->src_h >> 16);
272 	/* The legacy SetCrtc API doesn't support fences */
273 	assert(scanout_state->in_fence_fd == -1);
274
275 	mode = to_drm_mode(output->base.current_mode);
276+
277+	scaling = scanout_state->src_w >> 16 != scanout_state->dest_w ||
278+		scanout_state->src_h >> 16 != scanout_state->dest_h;
279+
280 	if (output->state_invalid ||
281-	    !scanout_plane->state_cur->fb ||
282-	    scanout_plane->state_cur->fb->strides[0] !=
283-	    scanout_state->fb->strides[0]) {
284+	    !scanout_plane->state_cur->fb) {
285+		int fb_id = scanout_state->fb->fb_id;
286+
287+		/* Use a dummy fb for initial mode setting */
288+		if (!output->fb_dummy) {
289+			output->fb_dummy =
290+				drm_fb_create_dumb(device,
291+						   mode->mode_info.hdisplay,
292+						   mode->mode_info.vdisplay,
293+						   output->gbm_format);
294+			if (!output->fb_dummy) {
295+				weston_log("failed to create fb_dummy\n");
296+				goto err;
297+			}
298+		}
299+
300+		if (n_conn == 1 || scaling)
301+			fb_id = output->fb_dummy->fb_id;
302
303 		ret = drmModeSetCrtc(device->drm.fd, crtc->crtc_id,
304-				     scanout_state->fb->fb_id,
305-				     0, 0,
306+				     fb_id, 0, 0,
307 				     connectors, n_conn,
308 				     &mode->mode_info);
309 		if (ret) {
310@@ -720,6 +770,27 @@ drm_output_apply_state_legacy(struct drm_output_state *state)
311 		output->state_invalid = false;
312 	}
313
314+	if (scaling && !output->scanout_plane->can_scale) {
315+		weston_log("Couldn't do scaling on output %s\n",
316+			   output->base.name);
317+		weston_output_finish_frame(&output->base, NULL,
318+					   WP_PRESENTATION_FEEDBACK_INVALID);
319+		return 0;
320+	}
321+
322+	ret = drmModeSetPlane(device->drm.fd,
323+			      scanout_state->plane->plane_id,
324+			      crtc->crtc_id,
325+			      scanout_state->fb->fb_id, 0,
326+			      scanout_state->dest_x, scanout_state->dest_y,
327+			      scanout_state->dest_w, scanout_state->dest_h,
328+			      scanout_state->src_x, scanout_state->src_y,
329+			      scanout_state->src_w, scanout_state->src_h);
330+	if (ret) {
331+		weston_log("set plane failed: %s\n", strerror(errno));
332+		goto err;
333+	}
334+
335 	pinfo = scanout_state->fb->format;
336 	drm_debug(backend, "\t[CRTC:%u, PLANE:%u] FORMAT: %s\n",
337 			   crtc->crtc_id, scanout_state->plane->plane_id,
338diff --git a/libweston/backend-drm/modes.c b/libweston/backend-drm/modes.c
339index ae3a35d..7e7865b 100644
340--- a/libweston/backend-drm/modes.c
341+++ b/libweston/backend-drm/modes.c
342@@ -398,6 +398,7 @@ drm_refresh_rate_mHz(const drmModeModeInfo *info)
343 static struct drm_mode *
344 drm_output_add_mode(struct drm_output *output, const drmModeModeInfo *info)
345 {
346+	struct drm_backend *b = to_drm_backend(output->base.compositor);
347 	struct drm_mode *mode;
348
349 	mode = malloc(sizeof *mode);
350@@ -408,6 +409,11 @@ drm_output_add_mode(struct drm_output *output, const drmModeModeInfo *info)
351 	mode->base.width = info->hdisplay;
352 	mode->base.height = info->vdisplay;
353
354+	if (b->virtual_width && b->virtual_height) {
355+		mode->base.width = b->virtual_width;
356+		mode->base.height = b->virtual_height;
357+	}
358+
359 	mode->base.refresh = drm_refresh_rate_mHz(info);
360 	mode->mode_info = *info;
361 	mode->blob_id = 0;
362@@ -454,20 +460,34 @@ drm_output_print_modes(struct drm_output *output)
363 	struct weston_mode *m;
364 	struct drm_mode *dm;
365 	const char *aspect_ratio;
366+	bool virtual_size = false;
367
368 	wl_list_for_each(m, &output->base.mode_list, link) {
369 		dm = to_drm_mode(m);
370
371 		aspect_ratio = aspect_ratio_to_string(m->aspect_ratio);
372 		weston_log_continue(STAMP_SPACE "%dx%d@%.1f%s%s%s, %.1f MHz\n",
373-				    m->width, m->height, m->refresh / 1000.0,
374+				    dm->mode_info.hdisplay,
375+				    dm->mode_info.vdisplay,
376+				    m->refresh / 1000.0,
377 				    aspect_ratio,
378 				    m->flags & WL_OUTPUT_MODE_PREFERRED ?
379 				    ", preferred" : "",
380 				    m->flags & WL_OUTPUT_MODE_CURRENT ?
381 				    ", current" : "",
382 				    dm->mode_info.clock / 1000.0);
383+
384+		if(m->flags & WL_OUTPUT_MODE_CURRENT &&
385+		   (dm->mode_info.hdisplay != m->width ||
386+		    dm->mode_info.vdisplay != m->height))
387+			virtual_size = true;
388 	}
389+
390+	if (virtual_size)
391+		weston_log("Output %s: using virtual size %dx%d\n",
392+			   output->base.name,
393+			   output->base.current_mode->width,
394+			   output->base.current_mode->height);
395 }
396
397
398--
3992.20.1
400
401