diff options
| author | Gerd Hoffmann <kraxel@redhat.com> | 2018-04-20 03:19:03 -0400 |
|---|---|---|
| committer | Gerd Hoffmann <kraxel@redhat.com> | 2018-04-27 02:58:05 -0400 |
| commit | a6d3c4d79822658e7f2f9c4b73237fe2b057ed67 (patch) | |
| tree | 515f73bff6567d208e3825392bea3e1dac2c157d /drivers/gpu | |
| parent | 998010bfae6ebaac68af905bef9f6e276f775254 (diff) | |
qxl: hook monitors_config updates into crtc, not encoder.
The encoder callbacks are only called in case the video mode changes.
So any layout changes without mode changes will go unnoticed.
Add qxl_crtc_update_monitors_config(), based on the old
qxl_write_monitors_config_for_encoder() function. Hook it into the
enable, disable and flush atomic crtc callbacks. Remove monitors_config
updates from all other places.
Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1544322
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Reviewed-by: Dave Airlie <airlied@redhat.com>
Link: http://patchwork.freedesktop.org/patch/msgid/20180420071904.24276-4-kraxel@redhat.com
Diffstat (limited to 'drivers/gpu')
| -rw-r--r-- | drivers/gpu/drm/qxl/qxl_cmd.c | 2 | ||||
| -rw-r--r-- | drivers/gpu/drm/qxl/qxl_display.c | 156 |
2 files changed, 66 insertions, 92 deletions
diff --git a/drivers/gpu/drm/qxl/qxl_cmd.c b/drivers/gpu/drm/qxl/qxl_cmd.c index 850f8d7d37ce..95db20f2145f 100644 --- a/drivers/gpu/drm/qxl/qxl_cmd.c +++ b/drivers/gpu/drm/qxl/qxl_cmd.c | |||
| @@ -371,6 +371,7 @@ void qxl_io_flush_surfaces(struct qxl_device *qdev) | |||
| 371 | void qxl_io_destroy_primary(struct qxl_device *qdev) | 371 | void qxl_io_destroy_primary(struct qxl_device *qdev) |
| 372 | { | 372 | { |
| 373 | wait_for_io_cmd(qdev, 0, QXL_IO_DESTROY_PRIMARY_ASYNC); | 373 | wait_for_io_cmd(qdev, 0, QXL_IO_DESTROY_PRIMARY_ASYNC); |
| 374 | qdev->primary_created = false; | ||
| 374 | } | 375 | } |
| 375 | 376 | ||
| 376 | void qxl_io_create_primary(struct qxl_device *qdev, | 377 | void qxl_io_create_primary(struct qxl_device *qdev, |
| @@ -396,6 +397,7 @@ void qxl_io_create_primary(struct qxl_device *qdev, | |||
| 396 | create->type = QXL_SURF_TYPE_PRIMARY; | 397 | create->type = QXL_SURF_TYPE_PRIMARY; |
| 397 | 398 | ||
| 398 | wait_for_io_cmd(qdev, 0, QXL_IO_CREATE_PRIMARY_ASYNC); | 399 | wait_for_io_cmd(qdev, 0, QXL_IO_CREATE_PRIMARY_ASYNC); |
| 400 | qdev->primary_created = true; | ||
| 399 | } | 401 | } |
| 400 | 402 | ||
| 401 | void qxl_io_memslot_add(struct qxl_device *qdev, uint8_t id) | 403 | void qxl_io_memslot_add(struct qxl_device *qdev, uint8_t id) |
diff --git a/drivers/gpu/drm/qxl/qxl_display.c b/drivers/gpu/drm/qxl/qxl_display.c index 7d08a26c3a8b..58959733ae16 100644 --- a/drivers/gpu/drm/qxl/qxl_display.c +++ b/drivers/gpu/drm/qxl/qxl_display.c | |||
| @@ -281,6 +281,66 @@ static void qxl_send_monitors_config(struct qxl_device *qdev) | |||
| 281 | qxl_io_monitors_config(qdev); | 281 | qxl_io_monitors_config(qdev); |
| 282 | } | 282 | } |
| 283 | 283 | ||
| 284 | static void qxl_crtc_update_monitors_config(struct drm_crtc *crtc, | ||
| 285 | const char *reason) | ||
| 286 | { | ||
| 287 | struct drm_device *dev = crtc->dev; | ||
| 288 | struct qxl_device *qdev = dev->dev_private; | ||
| 289 | struct qxl_crtc *qcrtc = to_qxl_crtc(crtc); | ||
| 290 | struct qxl_head head; | ||
| 291 | int oldcount, i = qcrtc->index; | ||
| 292 | |||
| 293 | if (!qdev->primary_created) { | ||
| 294 | DRM_DEBUG_KMS("no primary surface, skip (%s)\n", reason); | ||
| 295 | return; | ||
| 296 | } | ||
| 297 | |||
| 298 | if (!qdev->monitors_config || | ||
| 299 | qdev->monitors_config->max_allowed <= i) | ||
| 300 | return; | ||
| 301 | |||
| 302 | head.id = i; | ||
| 303 | head.flags = 0; | ||
| 304 | oldcount = qdev->monitors_config->count; | ||
| 305 | if (crtc->state->active) { | ||
| 306 | struct drm_display_mode *mode = &crtc->mode; | ||
| 307 | head.width = mode->hdisplay; | ||
| 308 | head.height = mode->vdisplay; | ||
| 309 | head.x = crtc->x; | ||
| 310 | head.y = crtc->y; | ||
| 311 | if (qdev->monitors_config->count < i + 1) | ||
| 312 | qdev->monitors_config->count = i + 1; | ||
| 313 | } else if (i > 0) { | ||
| 314 | head.width = 0; | ||
| 315 | head.height = 0; | ||
| 316 | head.x = 0; | ||
| 317 | head.y = 0; | ||
| 318 | if (qdev->monitors_config->count == i + 1) | ||
| 319 | qdev->monitors_config->count = i; | ||
| 320 | } else { | ||
| 321 | DRM_DEBUG_KMS("inactive head 0, skip (%s)\n", reason); | ||
| 322 | return; | ||
| 323 | } | ||
| 324 | |||
| 325 | if (head.width == qdev->monitors_config->heads[i].width && | ||
| 326 | head.height == qdev->monitors_config->heads[i].height && | ||
| 327 | head.x == qdev->monitors_config->heads[i].x && | ||
| 328 | head.y == qdev->monitors_config->heads[i].y && | ||
| 329 | oldcount == qdev->monitors_config->count) | ||
| 330 | return; | ||
| 331 | |||
| 332 | DRM_DEBUG_KMS("head %d, %dx%d, at +%d+%d, %s (%s)\n", | ||
| 333 | i, head.width, head.height, head.x, head.y, | ||
| 334 | crtc->state->active ? "on" : "off", reason); | ||
| 335 | if (oldcount != qdev->monitors_config->count) | ||
| 336 | DRM_DEBUG_KMS("active heads %d -> %d (%d total)\n", | ||
| 337 | oldcount, qdev->monitors_config->count, | ||
| 338 | qdev->monitors_config->max_allowed); | ||
| 339 | |||
| 340 | qdev->monitors_config->heads[i] = head; | ||
| 341 | qxl_send_monitors_config(qdev); | ||
| 342 | } | ||
| 343 | |||
| 284 | static void qxl_crtc_atomic_flush(struct drm_crtc *crtc, | 344 | static void qxl_crtc_atomic_flush(struct drm_crtc *crtc, |
| 285 | struct drm_crtc_state *old_crtc_state) | 345 | struct drm_crtc_state *old_crtc_state) |
| 286 | { | 346 | { |
| @@ -296,6 +356,8 @@ static void qxl_crtc_atomic_flush(struct drm_crtc *crtc, | |||
| 296 | drm_crtc_send_vblank_event(crtc, event); | 356 | drm_crtc_send_vblank_event(crtc, event); |
| 297 | spin_unlock_irqrestore(&dev->event_lock, flags); | 357 | spin_unlock_irqrestore(&dev->event_lock, flags); |
| 298 | } | 358 | } |
| 359 | |||
| 360 | qxl_crtc_update_monitors_config(crtc, "flush"); | ||
| 299 | } | 361 | } |
| 300 | 362 | ||
| 301 | static void qxl_crtc_destroy(struct drm_crtc *crtc) | 363 | static void qxl_crtc_destroy(struct drm_crtc *crtc) |
| @@ -401,55 +463,20 @@ static bool qxl_crtc_mode_fixup(struct drm_crtc *crtc, | |||
| 401 | return true; | 463 | return true; |
| 402 | } | 464 | } |
| 403 | 465 | ||
| 404 | static void qxl_monitors_config_set(struct qxl_device *qdev, | ||
| 405 | int index, | ||
| 406 | unsigned x, unsigned y, | ||
| 407 | unsigned width, unsigned height, | ||
| 408 | unsigned surf_id) | ||
| 409 | { | ||
| 410 | DRM_DEBUG_KMS("%d:%dx%d+%d+%d\n", index, width, height, x, y); | ||
| 411 | qdev->monitors_config->heads[index].x = x; | ||
| 412 | qdev->monitors_config->heads[index].y = y; | ||
| 413 | qdev->monitors_config->heads[index].width = width; | ||
| 414 | qdev->monitors_config->heads[index].height = height; | ||
| 415 | qdev->monitors_config->heads[index].surface_id = surf_id; | ||
| 416 | |||
| 417 | } | ||
| 418 | |||
| 419 | static void qxl_mode_set_nofb(struct drm_crtc *crtc) | ||
| 420 | { | ||
| 421 | struct qxl_device *qdev = crtc->dev->dev_private; | ||
| 422 | struct qxl_crtc *qcrtc = to_qxl_crtc(crtc); | ||
| 423 | struct drm_display_mode *mode = &crtc->mode; | ||
| 424 | |||
| 425 | DRM_DEBUG("Mode set (%d,%d)\n", | ||
| 426 | mode->hdisplay, mode->vdisplay); | ||
| 427 | |||
| 428 | qxl_monitors_config_set(qdev, qcrtc->index, 0, 0, | ||
| 429 | mode->hdisplay, mode->vdisplay, 0); | ||
| 430 | |||
| 431 | } | ||
| 432 | |||
| 433 | static void qxl_crtc_atomic_enable(struct drm_crtc *crtc, | 466 | static void qxl_crtc_atomic_enable(struct drm_crtc *crtc, |
| 434 | struct drm_crtc_state *old_state) | 467 | struct drm_crtc_state *old_state) |
| 435 | { | 468 | { |
| 436 | DRM_DEBUG("\n"); | 469 | qxl_crtc_update_monitors_config(crtc, "enable"); |
| 437 | } | 470 | } |
| 438 | 471 | ||
| 439 | static void qxl_crtc_atomic_disable(struct drm_crtc *crtc, | 472 | static void qxl_crtc_atomic_disable(struct drm_crtc *crtc, |
| 440 | struct drm_crtc_state *old_state) | 473 | struct drm_crtc_state *old_state) |
| 441 | { | 474 | { |
| 442 | struct qxl_crtc *qcrtc = to_qxl_crtc(crtc); | 475 | qxl_crtc_update_monitors_config(crtc, "disable"); |
| 443 | struct qxl_device *qdev = crtc->dev->dev_private; | ||
| 444 | |||
| 445 | qxl_monitors_config_set(qdev, qcrtc->index, 0, 0, 0, 0, 0); | ||
| 446 | |||
| 447 | qxl_send_monitors_config(qdev); | ||
| 448 | } | 476 | } |
| 449 | 477 | ||
| 450 | static const struct drm_crtc_helper_funcs qxl_crtc_helper_funcs = { | 478 | static const struct drm_crtc_helper_funcs qxl_crtc_helper_funcs = { |
| 451 | .mode_fixup = qxl_crtc_mode_fixup, | 479 | .mode_fixup = qxl_crtc_mode_fixup, |
| 452 | .mode_set_nofb = qxl_mode_set_nofb, | ||
| 453 | .atomic_flush = qxl_crtc_atomic_flush, | 480 | .atomic_flush = qxl_crtc_atomic_flush, |
| 454 | .atomic_enable = qxl_crtc_atomic_enable, | 481 | .atomic_enable = qxl_crtc_atomic_enable, |
| 455 | .atomic_disable = qxl_crtc_atomic_disable, | 482 | .atomic_disable = qxl_crtc_atomic_disable, |
| @@ -939,61 +966,8 @@ static void qxl_enc_prepare(struct drm_encoder *encoder) | |||
| 939 | DRM_DEBUG("\n"); | 966 | DRM_DEBUG("\n"); |
| 940 | } | 967 | } |
| 941 | 968 | ||
| 942 | static void qxl_write_monitors_config_for_encoder(struct qxl_device *qdev, | ||
| 943 | struct drm_encoder *encoder) | ||
| 944 | { | ||
| 945 | int i; | ||
| 946 | struct qxl_output *output = drm_encoder_to_qxl_output(encoder); | ||
| 947 | struct qxl_head *head; | ||
| 948 | struct drm_display_mode *mode; | ||
| 949 | |||
| 950 | BUG_ON(!encoder); | ||
| 951 | /* TODO: ugly, do better */ | ||
| 952 | i = output->index; | ||
| 953 | if (!qdev->monitors_config || | ||
| 954 | qdev->monitors_config->max_allowed <= i) { | ||
| 955 | DRM_ERROR( | ||
| 956 | "head number too large or missing monitors config: %p, %d", | ||
| 957 | qdev->monitors_config, | ||
| 958 | qdev->monitors_config ? | ||
| 959 | qdev->monitors_config->max_allowed : -1); | ||
| 960 | return; | ||
| 961 | } | ||
| 962 | if (!encoder->crtc) { | ||
| 963 | DRM_ERROR("missing crtc on encoder %p\n", encoder); | ||
| 964 | return; | ||
| 965 | } | ||
| 966 | if (i != 0) | ||
| 967 | DRM_DEBUG("missing for multiple monitors: no head holes\n"); | ||
| 968 | head = &qdev->monitors_config->heads[i]; | ||
| 969 | head->id = i; | ||
| 970 | if (encoder->crtc->enabled) { | ||
| 971 | mode = &encoder->crtc->mode; | ||
| 972 | head->width = mode->hdisplay; | ||
| 973 | head->height = mode->vdisplay; | ||
| 974 | head->x = encoder->crtc->x; | ||
| 975 | head->y = encoder->crtc->y; | ||
| 976 | if (qdev->monitors_config->count < i + 1) | ||
| 977 | qdev->monitors_config->count = i + 1; | ||
| 978 | } else { | ||
| 979 | head->width = 0; | ||
| 980 | head->height = 0; | ||
| 981 | head->x = 0; | ||
| 982 | head->y = 0; | ||
| 983 | } | ||
| 984 | DRM_DEBUG_KMS("setting head %d to +%d+%d %dx%d out of %d\n", | ||
| 985 | i, head->x, head->y, head->width, head->height, qdev->monitors_config->count); | ||
| 986 | head->flags = 0; | ||
| 987 | /* TODO - somewhere else to call this for multiple monitors | ||
| 988 | * (config_commit?) */ | ||
| 989 | qxl_send_monitors_config(qdev); | ||
| 990 | } | ||
| 991 | |||
| 992 | static void qxl_enc_commit(struct drm_encoder *encoder) | 969 | static void qxl_enc_commit(struct drm_encoder *encoder) |
| 993 | { | 970 | { |
| 994 | struct qxl_device *qdev = encoder->dev->dev_private; | ||
| 995 | |||
| 996 | qxl_write_monitors_config_for_encoder(qdev, encoder); | ||
| 997 | DRM_DEBUG("\n"); | 971 | DRM_DEBUG("\n"); |
| 998 | } | 972 | } |
| 999 | 973 | ||
| @@ -1080,8 +1054,6 @@ static enum drm_connector_status qxl_conn_detect( | |||
| 1080 | qxl_head_enabled(&qdev->client_monitors_config->heads[output->index]); | 1054 | qxl_head_enabled(&qdev->client_monitors_config->heads[output->index]); |
| 1081 | 1055 | ||
| 1082 | DRM_DEBUG("#%d connected: %d\n", output->index, connected); | 1056 | DRM_DEBUG("#%d connected: %d\n", output->index, connected); |
| 1083 | if (!connected) | ||
| 1084 | qxl_monitors_config_set(qdev, output->index, 0, 0, 0, 0, 0); | ||
| 1085 | 1057 | ||
| 1086 | return connected ? connector_status_connected | 1058 | return connected ? connector_status_connected |
| 1087 | : connector_status_disconnected; | 1059 | : connector_status_disconnected; |
