new/buildroot/package/weston/0016-backend-drm-Support-virtual-screen-size.patch
2025-05-10 21:58:58 +08:00

401 lines
13 KiB
Diff

From 2a839667bac950c484e109560cd380af760e3781 Mon Sep 17 00:00:00 2001
From: Jeffy Chen <jeffy.chen@rock-chips.com>
Date: Wed, 24 Jun 2020 11:59:42 +0800
Subject: [PATCH 16/93] backend-drm: Support virtual screen size
Support setting virtual screen size, for example:
export WESTON_DRM_VIRTUAL_SIZE=1024x768
Signed-off-by: Jeffy Chen <jeffy.chen@rock-chips.com>
---
libweston/backend-drm/drm-internal.h | 22 +++++
libweston/backend-drm/drm.c | 22 ++++-
libweston/backend-drm/kms.c | 115 ++++++++++++++++++++++-----
libweston/backend-drm/modes.c | 22 ++++-
4 files changed, 155 insertions(+), 26 deletions(-)
diff --git a/libweston/backend-drm/drm-internal.h b/libweston/backend-drm/drm-internal.h
index ec8bf0e..af82922 100644
--- a/libweston/backend-drm/drm-internal.h
+++ b/libweston/backend-drm/drm-internal.h
@@ -166,6 +166,7 @@ enum wdrm_plane_property {
WDRM_PLANE_IN_FENCE_FD,
WDRM_PLANE_FB_DAMAGE_CLIPS,
WDRM_PLANE_ZPOS,
+ WDRM_PLANE_FEATURE,
WDRM_PLANE__COUNT
};
@@ -179,6 +180,15 @@ enum wdrm_plane_type {
WDRM_PLANE_TYPE__COUNT
};
+/**
+ * Possible values for the WDRM_PLANE_FEATURE property.
+ */
+enum wdrm_plane_feature {
+ WDRM_PLANE_FEATURE_SCALE = 0,
+ WDRM_PLANE_FEATURE_ALPHA,
+ WDRM_PLANE_FEATURE__COUNT
+};
+
/**
* List of properties attached to a DRM connector
*/
@@ -349,6 +359,9 @@ struct drm_backend {
drm_head_match_t *head_matches;
struct drm_head *primary_head;
struct wl_listener output_create_listener;
+
+ int virtual_width;
+ int virtual_height;
};
struct drm_mode {
@@ -508,6 +521,8 @@ struct drm_plane {
struct wl_list link;
struct weston_drm_format_array formats;
+
+ bool can_scale;
};
struct drm_connector {
@@ -613,6 +628,9 @@ struct drm_output {
submit_frame_cb virtual_submit_frame;
bool state_invalid;
+
+ /* The dummy framebuffer for SET_CRTC. */
+ struct drm_fb *fb_dummy;
};
void
@@ -726,6 +744,10 @@ uint64_t
drm_property_get_value(struct drm_property_info *info,
const drmModeObjectProperties *props,
uint64_t def);
+bool
+drm_property_has_feature(struct drm_property_info *infos,
+ const drmModeObjectProperties *props,
+ enum wdrm_plane_feature feature);
uint64_t *
drm_property_get_range_values(struct drm_property_info *info,
const drmModeObjectProperties *props);
diff --git a/libweston/backend-drm/drm.c b/libweston/backend-drm/drm.c
index f5ac1b6..a2f215f 100644
--- a/libweston/backend-drm/drm.c
+++ b/libweston/backend-drm/drm.c
@@ -331,6 +331,11 @@ drm_output_update_complete(struct drm_output *output, uint32_t flags,
output->state_last = NULL;
}
+ if (output->fb_dummy) {
+ drm_fb_unref(output->fb_dummy);
+ output->fb_dummy = NULL;
+ }
+
if (output->destroy_pending) {
output->destroy_pending = false;
output->disable_pending = false;
@@ -411,6 +416,7 @@ drm_output_render(struct drm_output_state *state, pixman_region32_t *damage)
struct drm_property_info *damage_info =
&scanout_plane->props[WDRM_PLANE_FB_DAMAGE_CLIPS];
struct drm_backend *b = device->backend;
+ struct drm_mode *mode;
struct drm_fb *fb;
pixman_region32_t scanout_damage;
pixman_box32_t *rects;
@@ -454,10 +460,11 @@ drm_output_render(struct drm_output_state *state, pixman_region32_t *damage)
scanout_state->src_w = fb->width << 16;
scanout_state->src_h = fb->height << 16;
+ mode = to_drm_mode(output->base.current_mode);
scanout_state->dest_x = 0;
scanout_state->dest_y = 0;
- scanout_state->dest_w = output->base.current_mode->width;
- scanout_state->dest_h = output->base.current_mode->height;
+ scanout_state->dest_w = mode->mode_info.hdisplay;
+ scanout_state->dest_h = mode->mode_info.vdisplay;
pixman_region32_subtract(&c->primary_plane.damage,
&c->primary_plane.damage, damage);
@@ -521,7 +528,7 @@ drm_output_repaint(struct weston_output *output_base, pixman_region32_t *damage)
weston_compositor_read_presentation_clock(b->compositor, &now);
now_ms = timespec_to_msec(&now);
- if (now_ms < b->last_resize_ms + DRM_RESIZE_FREEZE_MS) {
+ if (now_ms < b->last_resize_ms + b->resize_freeze_ms) {
/* Resize fullscreen/maxmium views(not always success) */
if (now_ms < b->last_resize_ms + DRM_RESIZE_FREEZE_MS)
wl_signal_emit(&b->compositor->output_resized_signal,
@@ -879,6 +886,11 @@ drm_plane_create(struct drm_device *device, const drmModePlane *kplane)
props,
WDRM_PLANE_TYPE__COUNT);
+ plane->can_scale =
+ drm_property_has_feature(plane->props,
+ props,
+ WDRM_PLANE_FEATURE_SCALE);
+
zpos_range_values =
drm_property_get_range_values(&plane->props[WDRM_PLANE_ZPOS],
props);
@@ -3420,6 +3432,10 @@ drm_backend_create(struct weston_compositor *compositor,
b->head_matches = drm_head_matches[head_mode];
+ buf = getenv("WESTON_DRM_VIRTUAL_SIZE");
+ if (buf)
+ sscanf(buf, "%dx%d", &b->virtual_width, &b->virtual_height);
+
buf = getenv("WESTON_DRM_RESIZE_FREEZE_MS");
if (buf)
b->resize_freeze_ms = atoi(buf);
diff --git a/libweston/backend-drm/kms.c b/libweston/backend-drm/kms.c
index c7dc2f8..0008e83 100644
--- a/libweston/backend-drm/kms.c
+++ b/libweston/backend-drm/kms.c
@@ -56,6 +56,15 @@ struct drm_property_enum_info plane_type_enums[] = {
},
};
+struct drm_property_enum_info plane_feature_enums[] = {
+ [WDRM_PLANE_FEATURE_SCALE] = {
+ .name = "scale",
+ },
+ [WDRM_PLANE_FEATURE_ALPHA] = {
+ .name = "alpha",
+ },
+};
+
const struct drm_property_info plane_props[] = {
[WDRM_PLANE_TYPE] = {
.name = "type",
@@ -76,6 +85,11 @@ const struct drm_property_info plane_props[] = {
[WDRM_PLANE_IN_FENCE_FD] = { .name = "IN_FENCE_FD" },
[WDRM_PLANE_FB_DAMAGE_CLIPS] = { .name = "FB_DAMAGE_CLIPS" },
[WDRM_PLANE_ZPOS] = { .name = "zpos" },
+ [WDRM_PLANE_FEATURE] = {
+ .name = "FEATURE",
+ .enum_values = plane_feature_enums,
+ .num_enum_values = WDRM_PLANE_FEATURE__COUNT,
+ },
};
struct drm_property_enum_info dpms_state_enums[] = {
@@ -217,6 +231,31 @@ drm_property_get_value(struct drm_property_info *info,
return def;
}
+bool
+drm_property_has_feature(struct drm_property_info *infos,
+ const drmModeObjectProperties *props,
+ enum wdrm_plane_feature feature)
+{
+ struct drm_property_info *info = &infos[WDRM_PLANE_FEATURE];
+ unsigned int i;
+
+ if (info->prop_id == 0 ||
+ feature >= info->num_enum_values ||
+ !info->enum_values[feature].valid)
+ return false;
+
+ for (i = 0; i < props->count_props; i++) {
+ if (props->props[i] != info->prop_id)
+ continue;
+
+ if (props->prop_values[i] &
+ (1LL << info->enum_values[feature].value))
+ return true;
+ }
+
+ return false;
+}
+
/**
* Get the current range values of a KMS property
*
@@ -337,9 +376,11 @@ drm_property_info_populate(struct drm_device *device,
}
if (info[j].num_enum_values == 0 &&
- (prop->flags & DRM_MODE_PROP_ENUM)) {
+ (prop->flags & DRM_MODE_PROP_ENUM ||
+ prop->flags & DRM_MODE_PROP_BITMASK)) {
weston_log("DRM: expected property %s to not be an"
- " enum, but it is; ignoring\n", prop->name);
+ " enum or bitmask, but it is; ignoring\n",
+ prop->name);
drmModeFreeProperty(prop);
continue;
}
@@ -360,9 +401,11 @@ drm_property_info_populate(struct drm_device *device,
continue;
}
- if (!(prop->flags & DRM_MODE_PROP_ENUM)) {
- weston_log("DRM: expected property %s to be an enum,"
- " but it is not; ignoring\n", prop->name);
+ if (!(prop->flags & DRM_MODE_PROP_ENUM ||
+ prop->flags & DRM_MODE_PROP_BITMASK)) {
+ weston_log("DRM: expected property %s to be an enum or "
+ "bitmask, but it is not; ignoring\n",
+ prop->name);
drmModeFreeProperty(prop);
info[j].prop_id = 0;
continue;
@@ -639,6 +682,7 @@ drm_output_apply_state_legacy(struct drm_output_state *state)
int n_conn = 0;
struct timespec now;
int ret = 0;
+ bool scaling;
wl_list_for_each(head, &output->base.head_list, base.output_link) {
assert(n_conn < MAX_CLONED_CONNECTORS);
@@ -686,30 +730,36 @@ drm_output_apply_state_legacy(struct drm_output_state *state)
if (!scanout_state || !scanout_state->fb)
return 0;
- /* The legacy SetCrtc API doesn't allow us to do scaling, and the
- * legacy PageFlip API doesn't allow us to do clipping either. */
- assert(scanout_state->src_x == 0);
- assert(scanout_state->src_y == 0);
- assert(scanout_state->src_w ==
- (unsigned) (output->base.current_mode->width << 16));
- assert(scanout_state->src_h ==
- (unsigned) (output->base.current_mode->height << 16));
- assert(scanout_state->dest_x == 0);
- assert(scanout_state->dest_y == 0);
- assert(scanout_state->dest_w == scanout_state->src_w >> 16);
- assert(scanout_state->dest_h == scanout_state->src_h >> 16);
/* The legacy SetCrtc API doesn't support fences */
assert(scanout_state->in_fence_fd == -1);
mode = to_drm_mode(output->base.current_mode);
+
+ scaling = scanout_state->src_w >> 16 != scanout_state->dest_w ||
+ scanout_state->src_h >> 16 != scanout_state->dest_h;
+
if (output->state_invalid ||
- !scanout_plane->state_cur->fb ||
- scanout_plane->state_cur->fb->strides[0] !=
- scanout_state->fb->strides[0]) {
+ !scanout_plane->state_cur->fb) {
+ int fb_id = scanout_state->fb->fb_id;
+
+ /* Use a dummy fb for initial mode setting */
+ if (!output->fb_dummy) {
+ output->fb_dummy =
+ drm_fb_create_dumb(device,
+ mode->mode_info.hdisplay,
+ mode->mode_info.vdisplay,
+ output->gbm_format);
+ if (!output->fb_dummy) {
+ weston_log("failed to create fb_dummy\n");
+ goto err;
+ }
+ }
+
+ if (n_conn == 1 || scaling)
+ fb_id = output->fb_dummy->fb_id;
ret = drmModeSetCrtc(device->drm.fd, crtc->crtc_id,
- scanout_state->fb->fb_id,
- 0, 0,
+ fb_id, 0, 0,
connectors, n_conn,
&mode->mode_info);
if (ret) {
@@ -720,6 +770,27 @@ drm_output_apply_state_legacy(struct drm_output_state *state)
output->state_invalid = false;
}
+ if (scaling && !output->scanout_plane->can_scale) {
+ weston_log("Couldn't do scaling on output %s\n",
+ output->base.name);
+ weston_output_finish_frame(&output->base, NULL,
+ WP_PRESENTATION_FEEDBACK_INVALID);
+ return 0;
+ }
+
+ ret = drmModeSetPlane(device->drm.fd,
+ scanout_state->plane->plane_id,
+ crtc->crtc_id,
+ scanout_state->fb->fb_id, 0,
+ scanout_state->dest_x, scanout_state->dest_y,
+ scanout_state->dest_w, scanout_state->dest_h,
+ scanout_state->src_x, scanout_state->src_y,
+ scanout_state->src_w, scanout_state->src_h);
+ if (ret) {
+ weston_log("set plane failed: %s\n", strerror(errno));
+ goto err;
+ }
+
pinfo = scanout_state->fb->format;
drm_debug(backend, "\t[CRTC:%u, PLANE:%u] FORMAT: %s\n",
crtc->crtc_id, scanout_state->plane->plane_id,
diff --git a/libweston/backend-drm/modes.c b/libweston/backend-drm/modes.c
index ae3a35d..7e7865b 100644
--- a/libweston/backend-drm/modes.c
+++ b/libweston/backend-drm/modes.c
@@ -398,6 +398,7 @@ drm_refresh_rate_mHz(const drmModeModeInfo *info)
static struct drm_mode *
drm_output_add_mode(struct drm_output *output, const drmModeModeInfo *info)
{
+ struct drm_backend *b = to_drm_backend(output->base.compositor);
struct drm_mode *mode;
mode = malloc(sizeof *mode);
@@ -408,6 +409,11 @@ drm_output_add_mode(struct drm_output *output, const drmModeModeInfo *info)
mode->base.width = info->hdisplay;
mode->base.height = info->vdisplay;
+ if (b->virtual_width && b->virtual_height) {
+ mode->base.width = b->virtual_width;
+ mode->base.height = b->virtual_height;
+ }
+
mode->base.refresh = drm_refresh_rate_mHz(info);
mode->mode_info = *info;
mode->blob_id = 0;
@@ -454,20 +460,34 @@ drm_output_print_modes(struct drm_output *output)
struct weston_mode *m;
struct drm_mode *dm;
const char *aspect_ratio;
+ bool virtual_size = false;
wl_list_for_each(m, &output->base.mode_list, link) {
dm = to_drm_mode(m);
aspect_ratio = aspect_ratio_to_string(m->aspect_ratio);
weston_log_continue(STAMP_SPACE "%dx%d@%.1f%s%s%s, %.1f MHz\n",
- m->width, m->height, m->refresh / 1000.0,
+ dm->mode_info.hdisplay,
+ dm->mode_info.vdisplay,
+ m->refresh / 1000.0,
aspect_ratio,
m->flags & WL_OUTPUT_MODE_PREFERRED ?
", preferred" : "",
m->flags & WL_OUTPUT_MODE_CURRENT ?
", current" : "",
dm->mode_info.clock / 1000.0);
+
+ if(m->flags & WL_OUTPUT_MODE_CURRENT &&
+ (dm->mode_info.hdisplay != m->width ||
+ dm->mode_info.vdisplay != m->height))
+ virtual_size = true;
}
+
+ if (virtual_size)
+ weston_log("Output %s: using virtual size %dx%d\n",
+ output->base.name,
+ output->base.current_mode->width,
+ output->base.current_mode->height);
}
--
2.20.1