drm/qxl: rework cursor plane
Add helper functions to create and move the cursor. Create the cursor_bo in prepare_fb callback, in the atomic_commit callback we only send the update command to the host. Signed-off-by: Gerd Hoffmann <kraxel@redhat.com> Acked-by: Thomas Zimmermann <tzimmermann@suse.de> Link: http://patchwork.freedesktop.org/patch/msgid/20210217123213.2199186-11-kraxel@redhat.com
This commit is contained in:
parent
ab422b01e0
commit
b4b27f08f9
@ -476,12 +476,11 @@ static int qxl_primary_atomic_check(struct drm_plane *plane,
|
||||
return qxl_check_framebuffer(qdev, bo);
|
||||
}
|
||||
|
||||
static int qxl_primary_apply_cursor(struct drm_plane *plane)
|
||||
static int qxl_primary_apply_cursor(struct qxl_device *qdev,
|
||||
struct drm_plane_state *plane_state)
|
||||
{
|
||||
struct drm_device *dev = plane->dev;
|
||||
struct qxl_device *qdev = to_qxl(dev);
|
||||
struct drm_framebuffer *fb = plane->state->fb;
|
||||
struct qxl_crtc *qcrtc = to_qxl_crtc(plane->state->crtc);
|
||||
struct drm_framebuffer *fb = plane_state->fb;
|
||||
struct qxl_crtc *qcrtc = to_qxl_crtc(plane_state->crtc);
|
||||
struct qxl_cursor_cmd *cmd;
|
||||
struct qxl_release *release;
|
||||
int ret = 0;
|
||||
@ -505,8 +504,8 @@ static int qxl_primary_apply_cursor(struct drm_plane *plane)
|
||||
|
||||
cmd = (struct qxl_cursor_cmd *)qxl_release_map(qdev, release);
|
||||
cmd->type = QXL_CURSOR_SET;
|
||||
cmd->u.set.position.x = plane->state->crtc_x + fb->hot_x;
|
||||
cmd->u.set.position.y = plane->state->crtc_y + fb->hot_y;
|
||||
cmd->u.set.position.x = plane_state->crtc_x + fb->hot_x;
|
||||
cmd->u.set.position.y = plane_state->crtc_y + fb->hot_y;
|
||||
|
||||
cmd->u.set.shape = qxl_bo_physical_address(qdev, qcrtc->cursor_bo, 0);
|
||||
|
||||
@ -523,6 +522,113 @@ out_free_release:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int qxl_primary_move_cursor(struct qxl_device *qdev,
|
||||
struct drm_plane_state *plane_state)
|
||||
{
|
||||
struct drm_framebuffer *fb = plane_state->fb;
|
||||
struct qxl_crtc *qcrtc = to_qxl_crtc(plane_state->crtc);
|
||||
struct qxl_cursor_cmd *cmd;
|
||||
struct qxl_release *release;
|
||||
int ret = 0;
|
||||
|
||||
if (!qcrtc->cursor_bo)
|
||||
return 0;
|
||||
|
||||
ret = qxl_alloc_release_reserved(qdev, sizeof(*cmd),
|
||||
QXL_RELEASE_CURSOR_CMD,
|
||||
&release, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = qxl_release_reserve_list(release, true);
|
||||
if (ret) {
|
||||
qxl_release_free(qdev, release);
|
||||
return ret;
|
||||
}
|
||||
|
||||
cmd = (struct qxl_cursor_cmd *)qxl_release_map(qdev, release);
|
||||
cmd->type = QXL_CURSOR_MOVE;
|
||||
cmd->u.position.x = plane_state->crtc_x + fb->hot_x;
|
||||
cmd->u.position.y = plane_state->crtc_y + fb->hot_y;
|
||||
qxl_release_unmap(qdev, release, &cmd->release_info);
|
||||
|
||||
qxl_release_fence_buffer_objects(release);
|
||||
qxl_push_cursor_ring_release(qdev, release, QXL_CMD_CURSOR, false);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct qxl_bo *qxl_create_cursor(struct qxl_device *qdev,
|
||||
struct qxl_bo *user_bo,
|
||||
int hot_x, int hot_y)
|
||||
{
|
||||
static const u32 size = 64 * 64 * 4;
|
||||
struct qxl_bo *cursor_bo;
|
||||
struct dma_buf_map cursor_map;
|
||||
struct dma_buf_map user_map;
|
||||
struct qxl_cursor cursor;
|
||||
int ret;
|
||||
|
||||
if (!user_bo)
|
||||
return NULL;
|
||||
|
||||
ret = qxl_bo_create(qdev, sizeof(struct qxl_cursor) + size,
|
||||
false, true, QXL_GEM_DOMAIN_VRAM, 1,
|
||||
NULL, &cursor_bo);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
ret = qxl_bo_vmap(cursor_bo, &cursor_map);
|
||||
if (ret)
|
||||
goto err_unref;
|
||||
|
||||
ret = qxl_bo_vmap(user_bo, &user_map);
|
||||
if (ret)
|
||||
goto err_unmap;
|
||||
|
||||
cursor.header.unique = 0;
|
||||
cursor.header.type = SPICE_CURSOR_TYPE_ALPHA;
|
||||
cursor.header.width = 64;
|
||||
cursor.header.height = 64;
|
||||
cursor.header.hot_spot_x = hot_x;
|
||||
cursor.header.hot_spot_y = hot_y;
|
||||
cursor.data_size = size;
|
||||
cursor.chunk.next_chunk = 0;
|
||||
cursor.chunk.prev_chunk = 0;
|
||||
cursor.chunk.data_size = size;
|
||||
if (cursor_map.is_iomem) {
|
||||
memcpy_toio(cursor_map.vaddr_iomem,
|
||||
&cursor, sizeof(cursor));
|
||||
memcpy_toio(cursor_map.vaddr_iomem + sizeof(cursor),
|
||||
user_map.vaddr, size);
|
||||
} else {
|
||||
memcpy(cursor_map.vaddr,
|
||||
&cursor, sizeof(cursor));
|
||||
memcpy(cursor_map.vaddr + sizeof(cursor),
|
||||
user_map.vaddr, size);
|
||||
}
|
||||
|
||||
qxl_bo_vunmap(user_bo);
|
||||
qxl_bo_vunmap(cursor_bo);
|
||||
return cursor_bo;
|
||||
|
||||
err_unmap:
|
||||
qxl_bo_vunmap(cursor_bo);
|
||||
err_unref:
|
||||
qxl_bo_unpin(cursor_bo);
|
||||
qxl_bo_unref(&cursor_bo);
|
||||
err:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void qxl_free_cursor(struct qxl_bo *cursor_bo)
|
||||
{
|
||||
if (!cursor_bo)
|
||||
return;
|
||||
|
||||
qxl_bo_unpin(cursor_bo);
|
||||
qxl_bo_unref(&cursor_bo);
|
||||
}
|
||||
|
||||
static void qxl_primary_atomic_update(struct drm_plane *plane,
|
||||
struct drm_plane_state *old_state)
|
||||
{
|
||||
@ -543,7 +649,7 @@ static void qxl_primary_atomic_update(struct drm_plane *plane,
|
||||
if (qdev->primary_bo)
|
||||
qxl_io_destroy_primary(qdev);
|
||||
qxl_io_create_primary(qdev, primary);
|
||||
qxl_primary_apply_cursor(plane);
|
||||
qxl_primary_apply_cursor(qdev, plane->state);
|
||||
}
|
||||
|
||||
if (bo->is_dumb)
|
||||
@ -574,124 +680,21 @@ static void qxl_primary_atomic_disable(struct drm_plane *plane,
|
||||
static void qxl_cursor_atomic_update(struct drm_plane *plane,
|
||||
struct drm_plane_state *old_state)
|
||||
{
|
||||
struct drm_device *dev = plane->dev;
|
||||
struct qxl_device *qdev = to_qxl(dev);
|
||||
struct qxl_device *qdev = to_qxl(plane->dev);
|
||||
struct drm_framebuffer *fb = plane->state->fb;
|
||||
struct qxl_crtc *qcrtc = to_qxl_crtc(plane->state->crtc);
|
||||
struct qxl_release *release;
|
||||
struct qxl_cursor_cmd *cmd;
|
||||
struct qxl_cursor *cursor;
|
||||
struct drm_gem_object *obj;
|
||||
struct qxl_bo *cursor_bo = NULL, *user_bo = NULL, *old_cursor_bo = NULL;
|
||||
int ret;
|
||||
struct dma_buf_map user_map;
|
||||
struct dma_buf_map cursor_map;
|
||||
void *user_ptr;
|
||||
int size = 64*64*4;
|
||||
|
||||
ret = qxl_alloc_release_reserved(qdev, sizeof(*cmd),
|
||||
QXL_RELEASE_CURSOR_CMD,
|
||||
&release, NULL);
|
||||
if (ret)
|
||||
return;
|
||||
|
||||
if (fb != old_state->fb) {
|
||||
obj = fb->obj[0];
|
||||
user_bo = gem_to_qxl_bo(obj);
|
||||
|
||||
/* pinning is done in the prepare/cleanup framevbuffer */
|
||||
ret = qxl_bo_vmap_locked(user_bo, &user_map);
|
||||
if (ret)
|
||||
goto out_free_release;
|
||||
user_ptr = user_map.vaddr; /* TODO: Use mapping abstraction properly */
|
||||
|
||||
ret = qxl_alloc_bo_reserved(qdev, release,
|
||||
sizeof(struct qxl_cursor) + size,
|
||||
&cursor_bo);
|
||||
if (ret)
|
||||
goto out_kunmap;
|
||||
|
||||
ret = qxl_bo_pin(cursor_bo);
|
||||
if (ret)
|
||||
goto out_free_bo;
|
||||
|
||||
ret = qxl_release_reserve_list(release, true);
|
||||
if (ret)
|
||||
goto out_unpin;
|
||||
|
||||
ret = qxl_bo_vmap_locked(cursor_bo, &cursor_map);
|
||||
if (ret)
|
||||
goto out_backoff;
|
||||
if (cursor_map.is_iomem) /* TODO: Use mapping abstraction properly */
|
||||
cursor = (struct qxl_cursor __force *)cursor_map.vaddr_iomem;
|
||||
else
|
||||
cursor = (struct qxl_cursor *)cursor_map.vaddr;
|
||||
|
||||
cursor->header.unique = 0;
|
||||
cursor->header.type = SPICE_CURSOR_TYPE_ALPHA;
|
||||
cursor->header.width = 64;
|
||||
cursor->header.height = 64;
|
||||
cursor->header.hot_spot_x = fb->hot_x;
|
||||
cursor->header.hot_spot_y = fb->hot_y;
|
||||
cursor->data_size = size;
|
||||
cursor->chunk.next_chunk = 0;
|
||||
cursor->chunk.prev_chunk = 0;
|
||||
cursor->chunk.data_size = size;
|
||||
memcpy(cursor->chunk.data, user_ptr, size);
|
||||
qxl_bo_vunmap_locked(cursor_bo);
|
||||
qxl_bo_vunmap_locked(user_bo);
|
||||
|
||||
cmd = (struct qxl_cursor_cmd *) qxl_release_map(qdev, release);
|
||||
cmd->u.set.visible = 1;
|
||||
cmd->u.set.shape = qxl_bo_physical_address(qdev,
|
||||
cursor_bo, 0);
|
||||
cmd->type = QXL_CURSOR_SET;
|
||||
|
||||
old_cursor_bo = qcrtc->cursor_bo;
|
||||
qcrtc->cursor_bo = cursor_bo;
|
||||
cursor_bo = NULL;
|
||||
qxl_primary_apply_cursor(qdev, plane->state);
|
||||
} else {
|
||||
|
||||
ret = qxl_release_reserve_list(release, true);
|
||||
if (ret)
|
||||
goto out_free_release;
|
||||
|
||||
cmd = (struct qxl_cursor_cmd *) qxl_release_map(qdev, release);
|
||||
cmd->type = QXL_CURSOR_MOVE;
|
||||
qxl_primary_move_cursor(qdev, plane->state);
|
||||
}
|
||||
|
||||
cmd->u.position.x = plane->state->crtc_x + fb->hot_x;
|
||||
cmd->u.position.y = plane->state->crtc_y + fb->hot_y;
|
||||
|
||||
qxl_release_unmap(qdev, release, &cmd->release_info);
|
||||
qxl_release_fence_buffer_objects(release);
|
||||
qxl_push_cursor_ring_release(qdev, release, QXL_CMD_CURSOR, false);
|
||||
|
||||
if (old_cursor_bo != NULL)
|
||||
qxl_bo_unpin(old_cursor_bo);
|
||||
qxl_bo_unref(&old_cursor_bo);
|
||||
qxl_bo_unref(&cursor_bo);
|
||||
|
||||
return;
|
||||
|
||||
out_backoff:
|
||||
qxl_release_backoff_reserve_list(release);
|
||||
out_unpin:
|
||||
qxl_bo_unpin(cursor_bo);
|
||||
out_free_bo:
|
||||
qxl_bo_unref(&cursor_bo);
|
||||
out_kunmap:
|
||||
qxl_bo_vunmap_locked(user_bo);
|
||||
out_free_release:
|
||||
qxl_release_free(qdev, release);
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
static void qxl_cursor_atomic_disable(struct drm_plane *plane,
|
||||
struct drm_plane_state *old_state)
|
||||
{
|
||||
struct qxl_device *qdev = to_qxl(plane->dev);
|
||||
struct qxl_crtc *qcrtc;
|
||||
struct qxl_release *release;
|
||||
struct qxl_cursor_cmd *cmd;
|
||||
int ret;
|
||||
@ -714,6 +717,10 @@ static void qxl_cursor_atomic_disable(struct drm_plane *plane,
|
||||
|
||||
qxl_release_fence_buffer_objects(release);
|
||||
qxl_push_cursor_ring_release(qdev, release, QXL_CMD_CURSOR, false);
|
||||
|
||||
qcrtc = to_qxl_crtc(old_state->crtc);
|
||||
qxl_free_cursor(qcrtc->cursor_bo);
|
||||
qcrtc->cursor_bo = NULL;
|
||||
}
|
||||
|
||||
static void qxl_update_dumb_head(struct qxl_device *qdev,
|
||||
@ -822,6 +829,17 @@ static int qxl_plane_prepare_fb(struct drm_plane *plane,
|
||||
qxl_prepare_shadow(qdev, user_bo, new_state->crtc->index);
|
||||
}
|
||||
|
||||
if (plane->type == DRM_PLANE_TYPE_CURSOR &&
|
||||
plane->state->fb != new_state->fb) {
|
||||
struct qxl_crtc *qcrtc = to_qxl_crtc(new_state->crtc);
|
||||
struct qxl_bo *old_cursor_bo = qcrtc->cursor_bo;
|
||||
|
||||
qcrtc->cursor_bo = qxl_create_cursor(qdev, user_bo,
|
||||
new_state->fb->hot_x,
|
||||
new_state->fb->hot_y);
|
||||
qxl_free_cursor(old_cursor_bo);
|
||||
}
|
||||
|
||||
return qxl_bo_pin(user_bo);
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user