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