diff options
-rw-r--r-- | drivers/gpu/drm/qxl/qxl_display.c | 123 | ||||
-rw-r--r-- | drivers/gpu/drm/qxl/qxl_draw.c | 9 | ||||
-rw-r--r-- | drivers/gpu/drm/qxl/qxl_drv.h | 5 |
3 files changed, 108 insertions, 29 deletions
diff --git a/drivers/gpu/drm/qxl/qxl_display.c b/drivers/gpu/drm/qxl/qxl_display.c index 455b1b595a09..3f2e253f7244 100644 --- a/drivers/gpu/drm/qxl/qxl_display.c +++ b/drivers/gpu/drm/qxl/qxl_display.c @@ -323,6 +323,8 @@ static void qxl_crtc_update_monitors_config(struct drm_crtc *crtc, head.y = crtc->y; if (qdev->monitors_config->count < i + 1) qdev->monitors_config->count = i + 1; + if (qdev->primary_bo == qdev->dumb_shadow_bo) + head.x += qdev->dumb_heads[i].x; } else if (i > 0) { head.width = 0; head.height = 0; @@ -426,7 +428,7 @@ static int qxl_framebuffer_surface_dirty(struct drm_framebuffer *fb, } qxl_draw_dirty_fb(qdev, fb, qobj, flags, color, - clips, num_clips, inc); + clips, num_clips, inc, 0); drm_modeset_unlock_all(fb->dev); @@ -535,6 +537,7 @@ static void qxl_primary_atomic_update(struct drm_plane *plane, .x2 = plane->state->fb->width, .y2 = plane->state->fb->height }; + uint32_t dumb_shadow_offset = 0; if (old_state->fb) { bo_old = gem_to_qxl_bo(old_state->fb->obj[0]); @@ -551,7 +554,12 @@ static void qxl_primary_atomic_update(struct drm_plane *plane, qxl_primary_apply_cursor(plane); } - qxl_draw_dirty_fb(qdev, plane->state->fb, bo, 0, 0, &norect, 1, 1); + if (bo->is_dumb) + dumb_shadow_offset = + qdev->dumb_heads[plane->state->crtc->index].x; + + qxl_draw_dirty_fb(qdev, plane->state->fb, bo, 0, 0, &norect, 1, 1, + dumb_shadow_offset); } static void qxl_primary_atomic_disable(struct drm_plane *plane, @@ -707,12 +715,68 @@ static void qxl_cursor_atomic_disable(struct drm_plane *plane, qxl_release_fence_buffer_objects(release); } +static void qxl_update_dumb_head(struct qxl_device *qdev, + int index, struct qxl_bo *bo) +{ + uint32_t width, height; + + if (index >= qdev->monitors_config->max_allowed) + return; + + if (bo && bo->is_dumb) { + width = bo->surf.width; + height = bo->surf.height; + } else { + width = 0; + height = 0; + } + + if (qdev->dumb_heads[index].width == width && + qdev->dumb_heads[index].height == height) + return; + + DRM_DEBUG("#%d: %dx%d -> %dx%d\n", index, + qdev->dumb_heads[index].width, + qdev->dumb_heads[index].height, + width, height); + qdev->dumb_heads[index].width = width; + qdev->dumb_heads[index].height = height; +} + +static void qxl_calc_dumb_shadow(struct qxl_device *qdev, + struct qxl_surface *surf) +{ + struct qxl_head *head; + int i; + + memset(surf, 0, sizeof(*surf)); + for (i = 0; i < qdev->monitors_config->max_allowed; i++) { + head = qdev->dumb_heads + i; + head->x = surf->width; + surf->width += head->width; + if (surf->height < head->height) + surf->height = head->height; + } + if (surf->width < 64) + surf->width = 64; + if (surf->height < 64) + surf->height = 64; + surf->format = SPICE_SURFACE_FMT_32_xRGB; + surf->stride = surf->width * 4; + + if (!qdev->dumb_shadow_bo || + qdev->dumb_shadow_bo->surf.width != surf->width || + qdev->dumb_shadow_bo->surf.height != surf->height) + DRM_DEBUG("%dx%d\n", surf->width, surf->height); +} + static int qxl_plane_prepare_fb(struct drm_plane *plane, struct drm_plane_state *new_state) { struct qxl_device *qdev = plane->dev->dev_private; struct drm_gem_object *obj; - struct qxl_bo *user_bo, *old_bo = NULL; + struct qxl_bo *user_bo; + struct qxl_surface surf; int ret; if (!new_state->fb) @@ -722,29 +786,30 @@ static int qxl_plane_prepare_fb(struct drm_plane *plane, user_bo = gem_to_qxl_bo(obj); if (plane->type == DRM_PLANE_TYPE_PRIMARY && - user_bo->is_dumb && !user_bo->shadow) { - if (plane->state->fb) { - obj = plane->state->fb->obj[0]; - old_bo = gem_to_qxl_bo(obj); + user_bo->is_dumb) { + qxl_update_dumb_head(qdev, new_state->crtc->index, + user_bo); + qxl_calc_dumb_shadow(qdev, &surf); + if (!qdev->dumb_shadow_bo || + qdev->dumb_shadow_bo->surf.width != surf.width || + qdev->dumb_shadow_bo->surf.height != surf.height) { + if (qdev->dumb_shadow_bo) { + drm_gem_object_put_unlocked + (&qdev->dumb_shadow_bo->gem_base); + qdev->dumb_shadow_bo = NULL; + } + qxl_bo_create(qdev, surf.height * surf.stride, + true, true, QXL_GEM_DOMAIN_SURFACE, &surf, + &qdev->dumb_shadow_bo); } - if (old_bo && old_bo->shadow && - user_bo->gem_base.size == old_bo->gem_base.size && - plane->state->crtc == new_state->crtc && - plane->state->crtc_w == new_state->crtc_w && - plane->state->crtc_h == new_state->crtc_h && - plane->state->src_x == new_state->src_x && - plane->state->src_y == new_state->src_y && - plane->state->src_w == new_state->src_w && - plane->state->src_h == new_state->src_h && - plane->state->rotation == new_state->rotation && - plane->state->zpos == new_state->zpos) { - drm_gem_object_get(&old_bo->shadow->gem_base); - user_bo->shadow = old_bo->shadow; - } else { - qxl_bo_create(qdev, user_bo->gem_base.size, - true, true, QXL_GEM_DOMAIN_SURFACE, NULL, - &user_bo->shadow); - user_bo->shadow->surf = user_bo->surf; + if (user_bo->shadow != qdev->dumb_shadow_bo) { + if (user_bo->shadow) { + drm_gem_object_put_unlocked + (&user_bo->shadow->gem_base); + user_bo->shadow = NULL; + } + drm_gem_object_get(&qdev->dumb_shadow_bo->gem_base); + user_bo->shadow = qdev->dumb_shadow_bo; } } @@ -773,7 +838,7 @@ static void qxl_plane_cleanup_fb(struct drm_plane *plane, user_bo = gem_to_qxl_bo(obj); qxl_bo_unpin(user_bo); - if (user_bo->shadow && !user_bo->shadow->is_primary) { + if (old_state->fb != plane->state->fb && user_bo->shadow) { drm_gem_object_put_unlocked(&user_bo->shadow->gem_base); user_bo->shadow = NULL; } @@ -1106,6 +1171,12 @@ int qxl_create_monitors_object(struct qxl_device *qdev) memset(qdev->monitors_config, 0, monitors_config_size); qdev->monitors_config->max_allowed = max_allowed; + + qdev->dumb_heads = kcalloc(max_allowed, sizeof(qdev->dumb_heads[0]), GFP_KERNEL); + if (!qdev->dumb_heads) { + qxl_destroy_monitors_object(qdev); + return -ENOMEM; + } return 0; } diff --git a/drivers/gpu/drm/qxl/qxl_draw.c b/drivers/gpu/drm/qxl/qxl_draw.c index c408bb83c7a9..5313ad21c1bb 100644 --- a/drivers/gpu/drm/qxl/qxl_draw.c +++ b/drivers/gpu/drm/qxl/qxl_draw.c @@ -267,7 +267,8 @@ void qxl_draw_dirty_fb(struct qxl_device *qdev, struct qxl_bo *bo, unsigned int flags, unsigned int color, struct drm_clip_rect *clips, - unsigned int num_clips, int inc) + unsigned int num_clips, int inc, + uint32_t dumb_shadow_offset) { /* * TODO: if flags & DRM_MODE_FB_DIRTY_ANNOTATE_FILL then we should @@ -295,6 +296,9 @@ void qxl_draw_dirty_fb(struct qxl_device *qdev, if (ret) return; + clips->x1 += dumb_shadow_offset; + clips->x2 += dumb_shadow_offset; + left = clips->x1; right = clips->x2; top = clips->y1; @@ -342,7 +346,8 @@ void qxl_draw_dirty_fb(struct qxl_device *qdev, goto out_release_backoff; ret = qxl_image_init(qdev, release, dimage, surface_base, - left, top, width, height, depth, stride); + left - dumb_shadow_offset, + top, width, height, depth, stride); qxl_bo_kunmap(bo); if (ret) goto out_release_backoff; diff --git a/drivers/gpu/drm/qxl/qxl_drv.h b/drivers/gpu/drm/qxl/qxl_drv.h index 150b1a4f667a..43c6df9cf98e 100644 --- a/drivers/gpu/drm/qxl/qxl_drv.h +++ b/drivers/gpu/drm/qxl/qxl_drv.h @@ -230,6 +230,8 @@ struct qxl_device { struct qxl_ram_header *ram_header; struct qxl_bo *primary_bo; + struct qxl_bo *dumb_shadow_bo; + struct qxl_head *dumb_heads; struct qxl_memslot main_slot; struct qxl_memslot surfaces_slot; @@ -437,7 +439,8 @@ void qxl_draw_dirty_fb(struct qxl_device *qdev, struct qxl_bo *bo, unsigned int flags, unsigned int color, struct drm_clip_rect *clips, - unsigned int num_clips, int inc); + unsigned int num_clips, int inc, + uint32_t dumb_shadow_offset); void qxl_draw_fill(struct qxl_draw_fill *qxl_draw_fill_rec); |