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