aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/gpu/drm/qxl/qxl_display.c123
-rw-r--r--drivers/gpu/drm/qxl/qxl_draw.c9
-rw-r--r--drivers/gpu/drm/qxl/qxl_drv.h5
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);