377 lines
12 KiB
Diff
377 lines
12 KiB
Diff
From 4f864b4d7b292ec45901f1731e6d641588bf0042 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 22/95] 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 | 12 +++
|
|
libweston/backend-drm/drm-kms-enums.h | 10 +++
|
|
libweston/backend-drm/drm.c | 20 ++++-
|
|
libweston/backend-drm/kms.c | 111 +++++++++++++++++++++-----
|
|
libweston/backend-drm/modes.c | 18 +++++
|
|
5 files changed, 150 insertions(+), 21 deletions(-)
|
|
|
|
diff --git a/libweston/backend-drm/drm-internal.h b/libweston/backend-drm/drm-internal.h
|
|
index f8f3d93..24845d2 100644
|
|
--- a/libweston/backend-drm/drm-internal.h
|
|
+++ b/libweston/backend-drm/drm-internal.h
|
|
@@ -280,6 +280,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 {
|
|
@@ -451,6 +454,8 @@ struct drm_plane {
|
|
struct wl_list link;
|
|
|
|
struct weston_drm_format_array formats;
|
|
+
|
|
+ bool can_scale;
|
|
};
|
|
|
|
struct drm_connector {
|
|
@@ -611,6 +616,9 @@ struct drm_output {
|
|
enum wdrm_content_type content_type;
|
|
|
|
bool state_invalid;
|
|
+
|
|
+ /* The dummy framebuffer for SET_CRTC. */
|
|
+ struct drm_fb *fb_dummy;
|
|
};
|
|
|
|
void
|
|
@@ -744,6 +752,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-kms-enums.h b/libweston/backend-drm/drm-kms-enums.h
|
|
index f848ec3..e2b2bc1 100644
|
|
--- a/libweston/backend-drm/drm-kms-enums.h
|
|
+++ b/libweston/backend-drm/drm-kms-enums.h
|
|
@@ -56,6 +56,7 @@ enum wdrm_plane_property {
|
|
WDRM_PLANE_ZPOS,
|
|
WDRM_PLANE_ROTATION,
|
|
WDRM_PLANE_ALPHA,
|
|
+ WDRM_PLANE_FEATURE,
|
|
WDRM_PLANE__COUNT
|
|
};
|
|
|
|
@@ -82,6 +83,15 @@ enum wdrm_plane_rotation {
|
|
WDRM_PLANE_ROTATION__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
|
|
*/
|
|
diff --git a/libweston/backend-drm/drm.c b/libweston/backend-drm/drm.c
|
|
index 4a6e30b..20b5be8 100644
|
|
--- a/libweston/backend-drm/drm.c
|
|
+++ b/libweston/backend-drm/drm.c
|
|
@@ -366,6 +366,11 @@ drm_output_update_complete(struct drm_output *output, uint32_t flags,
|
|
drm_output_state_free(output->state_last);
|
|
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;
|
|
@@ -442,6 +447,7 @@ drm_output_render(struct drm_output_state *state)
|
|
struct drm_plane *scanout_plane = output->scanout_plane;
|
|
struct drm_property_info *damage_info =
|
|
&scanout_plane->props[WDRM_PLANE_FB_DAMAGE_CLIPS];
|
|
+ struct drm_mode *mode;
|
|
struct drm_fb *fb;
|
|
pixman_region32_t damage, scanout_damage;
|
|
pixman_box32_t *rects;
|
|
@@ -490,10 +496,11 @@ drm_output_render(struct drm_output_state *state)
|
|
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;
|
|
|
|
scanout_state->zpos = scanout_plane->zpos_min;
|
|
|
|
@@ -1224,6 +1231,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);
|
|
@@ -4278,6 +4290,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);
|
|
+
|
|
device = zalloc(sizeof *device);
|
|
if (device == NULL)
|
|
goto err_backend;
|
|
diff --git a/libweston/backend-drm/kms.c b/libweston/backend-drm/kms.c
|
|
index 30a9519..f974c90 100644
|
|
--- a/libweston/backend-drm/kms.c
|
|
+++ b/libweston/backend-drm/kms.c
|
|
@@ -81,6 +81,15 @@ struct drm_property_enum_info plane_rotation_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",
|
|
@@ -107,6 +116,11 @@ const struct drm_property_info plane_props[] = {
|
|
.num_enum_values = WDRM_PLANE_ROTATION__COUNT,
|
|
},
|
|
[WDRM_PLANE_ALPHA] = { .name = "alpha" },
|
|
+ [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[] = {
|
|
@@ -294,6 +308,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
|
|
*
|
|
@@ -481,9 +520,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;
|
|
}
|
|
@@ -816,6 +857,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);
|
|
@@ -863,30 +905,40 @@ 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);
|
|
+
|
|
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;
|
|
+
|
|
+ if (scanout_state->dest_x || scanout_state->dest_y ||
|
|
+ scanout_state->dest_w != mode->mode_info.hdisplay ||
|
|
+ scanout_state->dest_h != mode->mode_info.vdisplay ||
|
|
+ scanout_state->src_x || scanout_state->src_y ||
|
|
+ (scanout_state->src_w >> 16) != scanout_state->dest_w ||
|
|
+ (scanout_state->src_h >> 16) != scanout_state->dest_h) {
|
|
+ /* Use a dummy fb for initial mode setting */
|
|
+ if (output->fb_dummy)
|
|
+ drm_fb_unref(output->fb_dummy);
|
|
+
|
|
+ output->fb_dummy =
|
|
+ drm_fb_create_dumb(device,
|
|
+ mode->mode_info.hdisplay,
|
|
+ mode->mode_info.vdisplay,
|
|
+ output->format->format);
|
|
+ if (!output->fb_dummy) {
|
|
+ weston_log("failed to create fb_dummy\n");
|
|
+ goto err;
|
|
+ }
|
|
+
|
|
+ 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) {
|
|
@@ -900,6 +952,27 @@ drm_output_apply_state_legacy(struct drm_output_state *state)
|
|
drm_output_reset_legacy_gamma(output);
|
|
}
|
|
|
|
+ scaling = scanout_state->src_w >> 16 != scanout_state->dest_w ||
|
|
+ scanout_state->src_h >> 16 != scanout_state->dest_h;
|
|
+ if (scaling && !output->scanout_plane->can_scale) {
|
|
+ weston_log("Couldn't do scaling on output %s\n",
|
|
+ output->base.name);
|
|
+ goto err;
|
|
+ }
|
|
+
|
|
+ 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 aecd406..4f17d7b 100644
|
|
--- a/libweston/backend-drm/modes.c
|
|
+++ b/libweston/backend-drm/modes.c
|
|
@@ -463,6 +463,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);
|
|
@@ -473,6 +474,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;
|
|
@@ -519,6 +525,7 @@ 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);
|
|
@@ -532,7 +539,18 @@ drm_output_print_modes(struct drm_output *output)
|
|
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
|
|
|