drm: qxl: Atomic phase 1: convert cursor to universal plane
In preparation for atomic conversion, let's use the transitional atomic helpers drm_plane_helper_update/disable. Signed-off-by: Gabriel Krisman Bertazi <krisman@collabora.co.uk> Link: http://patchwork.freedesktop.org/patch/msgid/20170227204328.18761-6-krisman@collabora.co.uk Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
This commit is contained in:
parent
d3e7e42db2
commit
1277eed5fe
|
@ -30,6 +30,7 @@
|
|||
#include "qxl_object.h"
|
||||
#include "drm_crtc_helper.h"
|
||||
#include <drm/drm_plane_helper.h>
|
||||
#include <drm/drm_atomic_helper.h>
|
||||
|
||||
static bool qxl_head_enabled(struct qxl_head *head)
|
||||
{
|
||||
|
@ -256,7 +257,6 @@ static void qxl_crtc_destroy(struct drm_crtc *crtc)
|
|||
struct qxl_crtc *qxl_crtc = to_qxl_crtc(crtc);
|
||||
|
||||
drm_crtc_cleanup(crtc);
|
||||
qxl_bo_unref(&qxl_crtc->cursor_bo);
|
||||
kfree(qxl_crtc);
|
||||
}
|
||||
|
||||
|
@ -304,234 +304,7 @@ static int qxl_crtc_page_flip(struct drm_crtc *crtc,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
qxl_hide_cursor(struct qxl_device *qdev)
|
||||
{
|
||||
struct qxl_release *release;
|
||||
struct qxl_cursor_cmd *cmd;
|
||||
int ret;
|
||||
|
||||
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_HIDE;
|
||||
qxl_release_unmap(qdev, release, &cmd->release_info);
|
||||
|
||||
qxl_push_cursor_ring_release(qdev, release, QXL_CMD_CURSOR, false);
|
||||
qxl_release_fence_buffer_objects(release);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int qxl_crtc_apply_cursor(struct drm_crtc *crtc)
|
||||
{
|
||||
struct qxl_crtc *qcrtc = to_qxl_crtc(crtc);
|
||||
struct drm_device *dev = crtc->dev;
|
||||
struct qxl_device *qdev = dev->dev_private;
|
||||
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_list_add(release, qcrtc->cursor_bo);
|
||||
if (ret)
|
||||
goto out_free_release;
|
||||
|
||||
ret = qxl_release_reserve_list(release, false);
|
||||
if (ret)
|
||||
goto out_free_release;
|
||||
|
||||
cmd = (struct qxl_cursor_cmd *)qxl_release_map(qdev, release);
|
||||
cmd->type = QXL_CURSOR_SET;
|
||||
cmd->u.set.position.x = qcrtc->cur_x + qcrtc->hot_spot_x;
|
||||
cmd->u.set.position.y = qcrtc->cur_y + qcrtc->hot_spot_y;
|
||||
|
||||
cmd->u.set.shape = qxl_bo_physical_address(qdev, qcrtc->cursor_bo, 0);
|
||||
|
||||
cmd->u.set.visible = 1;
|
||||
qxl_release_unmap(qdev, release, &cmd->release_info);
|
||||
|
||||
qxl_push_cursor_ring_release(qdev, release, QXL_CMD_CURSOR, false);
|
||||
qxl_release_fence_buffer_objects(release);
|
||||
|
||||
return ret;
|
||||
|
||||
out_free_release:
|
||||
qxl_release_free(qdev, release);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int qxl_crtc_cursor_set2(struct drm_crtc *crtc,
|
||||
struct drm_file *file_priv,
|
||||
uint32_t handle,
|
||||
uint32_t width,
|
||||
uint32_t height, int32_t hot_x, int32_t hot_y)
|
||||
{
|
||||
struct drm_device *dev = crtc->dev;
|
||||
struct qxl_device *qdev = dev->dev_private;
|
||||
struct qxl_crtc *qcrtc = to_qxl_crtc(crtc);
|
||||
struct drm_gem_object *obj;
|
||||
struct qxl_cursor *cursor;
|
||||
struct qxl_cursor_cmd *cmd;
|
||||
struct qxl_bo *cursor_bo, *user_bo;
|
||||
struct qxl_release *release;
|
||||
void *user_ptr;
|
||||
|
||||
int size = 64*64*4;
|
||||
int ret = 0;
|
||||
if (!handle)
|
||||
return qxl_hide_cursor(qdev);
|
||||
|
||||
obj = drm_gem_object_lookup(file_priv, handle);
|
||||
if (!obj) {
|
||||
DRM_ERROR("cannot find cursor object\n");
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
user_bo = gem_to_qxl_bo(obj);
|
||||
|
||||
ret = qxl_bo_pin(user_bo, QXL_GEM_DOMAIN_CPU, NULL);
|
||||
if (ret)
|
||||
goto out_unref;
|
||||
|
||||
ret = qxl_bo_kmap(user_bo, &user_ptr);
|
||||
if (ret)
|
||||
goto out_unpin;
|
||||
|
||||
ret = qxl_alloc_release_reserved(qdev, sizeof(*cmd),
|
||||
QXL_RELEASE_CURSOR_CMD,
|
||||
&release, NULL);
|
||||
if (ret)
|
||||
goto out_kunmap;
|
||||
|
||||
ret = qxl_alloc_bo_reserved(qdev, release, sizeof(struct qxl_cursor) + size,
|
||||
&cursor_bo);
|
||||
if (ret)
|
||||
goto out_free_release;
|
||||
|
||||
ret = qxl_release_reserve_list(release, false);
|
||||
if (ret)
|
||||
goto out_free_bo;
|
||||
|
||||
ret = qxl_bo_kmap(cursor_bo, (void **)&cursor);
|
||||
if (ret)
|
||||
goto out_backoff;
|
||||
|
||||
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;
|
||||
|
||||
memcpy(cursor->chunk.data, user_ptr, size);
|
||||
|
||||
qxl_bo_kunmap(cursor_bo);
|
||||
|
||||
qxl_bo_kunmap(user_bo);
|
||||
|
||||
qcrtc->cur_x += qcrtc->hot_spot_x - hot_x;
|
||||
qcrtc->cur_y += qcrtc->hot_spot_y - hot_y;
|
||||
qcrtc->hot_spot_x = hot_x;
|
||||
qcrtc->hot_spot_y = hot_y;
|
||||
|
||||
cmd = (struct qxl_cursor_cmd *)qxl_release_map(qdev, release);
|
||||
cmd->type = QXL_CURSOR_SET;
|
||||
cmd->u.set.position.x = qcrtc->cur_x + qcrtc->hot_spot_x;
|
||||
cmd->u.set.position.y = qcrtc->cur_y + qcrtc->hot_spot_y;
|
||||
|
||||
cmd->u.set.shape = qxl_bo_physical_address(qdev, cursor_bo, 0);
|
||||
|
||||
cmd->u.set.visible = 1;
|
||||
qxl_release_unmap(qdev, release, &cmd->release_info);
|
||||
|
||||
qxl_push_cursor_ring_release(qdev, release, QXL_CMD_CURSOR, false);
|
||||
qxl_release_fence_buffer_objects(release);
|
||||
|
||||
/* finish with the userspace bo */
|
||||
qxl_bo_unpin(user_bo);
|
||||
|
||||
drm_gem_object_unreference_unlocked(obj);
|
||||
|
||||
qxl_bo_unref (&qcrtc->cursor_bo);
|
||||
qcrtc->cursor_bo = cursor_bo;
|
||||
|
||||
return ret;
|
||||
|
||||
out_backoff:
|
||||
qxl_release_backoff_reserve_list(release);
|
||||
out_free_bo:
|
||||
qxl_bo_unref(&cursor_bo);
|
||||
out_free_release:
|
||||
qxl_release_free(qdev, release);
|
||||
out_kunmap:
|
||||
qxl_bo_kunmap(user_bo);
|
||||
out_unpin:
|
||||
qxl_bo_unpin(user_bo);
|
||||
out_unref:
|
||||
drm_gem_object_unreference_unlocked(obj);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int qxl_crtc_cursor_move(struct drm_crtc *crtc,
|
||||
int x, int y)
|
||||
{
|
||||
struct drm_device *dev = crtc->dev;
|
||||
struct qxl_device *qdev = dev->dev_private;
|
||||
struct qxl_crtc *qcrtc = to_qxl_crtc(crtc);
|
||||
struct qxl_release *release;
|
||||
struct qxl_cursor_cmd *cmd;
|
||||
int ret;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
qcrtc->cur_x = x;
|
||||
qcrtc->cur_y = y;
|
||||
|
||||
cmd = (struct qxl_cursor_cmd *)qxl_release_map(qdev, release);
|
||||
cmd->type = QXL_CURSOR_MOVE;
|
||||
cmd->u.position.x = qcrtc->cur_x + qcrtc->hot_spot_x;
|
||||
cmd->u.position.y = qcrtc->cur_y + qcrtc->hot_spot_y;
|
||||
qxl_release_unmap(qdev, release, &cmd->release_info);
|
||||
|
||||
qxl_push_cursor_ring_release(qdev, release, QXL_CMD_CURSOR, false);
|
||||
qxl_release_fence_buffer_objects(release);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct drm_crtc_funcs qxl_crtc_funcs = {
|
||||
.cursor_set2 = qxl_crtc_cursor_set2,
|
||||
.cursor_move = qxl_crtc_cursor_move,
|
||||
.set_config = drm_crtc_helper_set_config,
|
||||
.destroy = qxl_crtc_destroy,
|
||||
.page_flip = qxl_crtc_page_flip,
|
||||
|
@ -723,12 +496,6 @@ static int qxl_crtc_mode_set(struct drm_crtc *crtc,
|
|||
bo->surf.stride, bo->surf.format);
|
||||
qxl_io_create_primary(qdev, 0, bo);
|
||||
bo->is_primary = true;
|
||||
|
||||
ret = qxl_crtc_apply_cursor(crtc);
|
||||
if (ret) {
|
||||
DRM_ERROR("could not set cursor after modeset");
|
||||
ret = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (bo->is_primary) {
|
||||
|
@ -788,6 +555,188 @@ static const struct drm_crtc_helper_funcs qxl_crtc_helper_funcs = {
|
|||
.commit = qxl_crtc_commit,
|
||||
};
|
||||
|
||||
int qxl_plane_atomic_check(struct drm_plane *plane,
|
||||
struct drm_plane_state *state)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
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 = dev->dev_private;
|
||||
struct drm_framebuffer *fb = plane->state->fb;
|
||||
struct qxl_release *release;
|
||||
struct qxl_cursor_cmd *cmd;
|
||||
struct qxl_cursor *cursor;
|
||||
struct drm_gem_object *obj;
|
||||
struct qxl_bo *cursor_bo, *user_bo = NULL;
|
||||
int ret;
|
||||
void *user_ptr;
|
||||
int size = 64*64*4;
|
||||
|
||||
ret = qxl_alloc_release_reserved(qdev, sizeof(*cmd),
|
||||
QXL_RELEASE_CURSOR_CMD,
|
||||
&release, NULL);
|
||||
|
||||
cmd = (struct qxl_cursor_cmd *) qxl_release_map(qdev, release);
|
||||
|
||||
if (fb != old_state->fb) {
|
||||
obj = to_qxl_framebuffer(fb)->obj;
|
||||
user_bo = gem_to_qxl_bo(obj);
|
||||
|
||||
/* pinning is done in the prepare/cleanup framevbuffer */
|
||||
ret = qxl_bo_kmap(user_bo, &user_ptr);
|
||||
if (ret)
|
||||
goto out_free_release;
|
||||
|
||||
ret = qxl_alloc_bo_reserved(qdev, release,
|
||||
sizeof(struct qxl_cursor) + size,
|
||||
&cursor_bo);
|
||||
if (ret)
|
||||
goto out_kunmap;
|
||||
|
||||
ret = qxl_release_reserve_list(release, true);
|
||||
if (ret)
|
||||
goto out_free_bo;
|
||||
|
||||
ret = qxl_bo_kmap(cursor_bo, (void **)&cursor);
|
||||
if (ret)
|
||||
goto out_backoff;
|
||||
|
||||
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_kunmap(cursor_bo);
|
||||
qxl_bo_kunmap(user_bo);
|
||||
|
||||
cmd->u.set.visible = 1;
|
||||
cmd->u.set.shape = qxl_bo_physical_address(qdev,
|
||||
cursor_bo, 0);
|
||||
cmd->type = QXL_CURSOR_SET;
|
||||
} else {
|
||||
|
||||
ret = qxl_release_reserve_list(release, true);
|
||||
if (ret)
|
||||
goto out_free_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_push_cursor_ring_release(qdev, release, QXL_CMD_CURSOR, false);
|
||||
qxl_release_fence_buffer_objects(release);
|
||||
|
||||
return;
|
||||
|
||||
out_backoff:
|
||||
qxl_release_backoff_reserve_list(release);
|
||||
out_free_bo:
|
||||
qxl_bo_unref(&cursor_bo);
|
||||
out_kunmap:
|
||||
qxl_bo_kunmap(user_bo);
|
||||
out_free_release:
|
||||
qxl_release_free(qdev, release);
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
void qxl_cursor_atomic_disable(struct drm_plane *plane,
|
||||
struct drm_plane_state *old_state)
|
||||
{
|
||||
struct qxl_device *qdev = plane->dev->dev_private;
|
||||
struct qxl_release *release;
|
||||
struct qxl_cursor_cmd *cmd;
|
||||
int ret;
|
||||
|
||||
ret = qxl_alloc_release_reserved(qdev, sizeof(*cmd),
|
||||
QXL_RELEASE_CURSOR_CMD,
|
||||
&release, NULL);
|
||||
if (ret)
|
||||
return;
|
||||
|
||||
ret = qxl_release_reserve_list(release, true);
|
||||
if (ret) {
|
||||
qxl_release_free(qdev, release);
|
||||
return;
|
||||
}
|
||||
|
||||
cmd = (struct qxl_cursor_cmd *)qxl_release_map(qdev, release);
|
||||
cmd->type = QXL_CURSOR_HIDE;
|
||||
qxl_release_unmap(qdev, release, &cmd->release_info);
|
||||
|
||||
qxl_push_cursor_ring_release(qdev, release, QXL_CMD_CURSOR, false);
|
||||
qxl_release_fence_buffer_objects(release);
|
||||
}
|
||||
|
||||
int qxl_plane_prepare_fb(struct drm_plane *plane,
|
||||
struct drm_plane_state *new_state)
|
||||
{
|
||||
struct drm_gem_object *obj;
|
||||
struct qxl_bo *user_bo;
|
||||
int ret;
|
||||
|
||||
if (!new_state->fb)
|
||||
return 0;
|
||||
|
||||
obj = to_qxl_framebuffer(new_state->fb)->obj;
|
||||
user_bo = gem_to_qxl_bo(obj);
|
||||
|
||||
ret = qxl_bo_pin(user_bo, QXL_GEM_DOMAIN_CPU, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void qxl_plane_cleanup_fb(struct drm_plane *plane,
|
||||
struct drm_plane_state *old_state)
|
||||
{
|
||||
struct drm_gem_object *obj;
|
||||
struct qxl_bo *user_bo;
|
||||
|
||||
if (!plane->state->fb) {
|
||||
/* we never executed prepare_fb, so there's nothing to
|
||||
* unpin.
|
||||
*/
|
||||
return;
|
||||
}
|
||||
|
||||
obj = to_qxl_framebuffer(plane->state->fb)->obj;
|
||||
user_bo = gem_to_qxl_bo(obj);
|
||||
qxl_bo_unpin(user_bo);
|
||||
}
|
||||
|
||||
static const uint32_t qxl_cursor_plane_formats[] = {
|
||||
DRM_FORMAT_ARGB8888,
|
||||
};
|
||||
|
||||
static const struct drm_plane_helper_funcs qxl_cursor_helper_funcs = {
|
||||
.atomic_check = qxl_plane_atomic_check,
|
||||
.atomic_update = qxl_cursor_atomic_update,
|
||||
.atomic_disable = qxl_cursor_atomic_disable,
|
||||
.prepare_fb = qxl_plane_prepare_fb,
|
||||
.cleanup_fb = qxl_plane_cleanup_fb,
|
||||
};
|
||||
|
||||
static const struct drm_plane_funcs qxl_cursor_plane_funcs = {
|
||||
.update_plane = drm_plane_helper_update,
|
||||
.disable_plane = drm_plane_helper_disable,
|
||||
.destroy = drm_primary_helper_destroy,
|
||||
};
|
||||
|
||||
static const uint32_t qxl_primary_plane_formats[] = {
|
||||
DRM_FORMAT_XRGB8888,
|
||||
DRM_FORMAT_ARGB8888,
|
||||
|
@ -814,6 +763,11 @@ static struct drm_plane *qxl_create_plane(struct qxl_device *qdev,
|
|||
funcs = &qxl_primary_plane_funcs;
|
||||
formats = qxl_primary_plane_formats;
|
||||
num_formats = ARRAY_SIZE(qxl_primary_plane_formats);
|
||||
} else if (type == DRM_PLANE_TYPE_CURSOR) {
|
||||
funcs = &qxl_cursor_plane_funcs;
|
||||
formats = qxl_cursor_plane_formats;
|
||||
helper_funcs = &qxl_cursor_helper_funcs;
|
||||
num_formats = ARRAY_SIZE(qxl_cursor_plane_formats);
|
||||
} else {
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
@ -840,7 +794,7 @@ free_plane:
|
|||
static int qdev_crtc_init(struct drm_device *dev, int crtc_id)
|
||||
{
|
||||
struct qxl_crtc *qxl_crtc;
|
||||
struct drm_plane *primary;
|
||||
struct drm_plane *primary, *cursor;
|
||||
struct qxl_device *qdev = dev->dev_private;
|
||||
int r;
|
||||
|
||||
|
@ -854,15 +808,24 @@ static int qdev_crtc_init(struct drm_device *dev, int crtc_id)
|
|||
goto free_mem;
|
||||
}
|
||||
|
||||
r = drm_crtc_init_with_planes(dev, &qxl_crtc->base, primary, NULL,
|
||||
cursor = qxl_create_plane(qdev, 1 << crtc_id, DRM_PLANE_TYPE_CURSOR);
|
||||
if (IS_ERR(cursor)) {
|
||||
r = -ENOMEM;
|
||||
goto clean_primary;
|
||||
}
|
||||
|
||||
r = drm_crtc_init_with_planes(dev, &qxl_crtc->base, primary, cursor,
|
||||
&qxl_crtc_funcs, NULL);
|
||||
if (r)
|
||||
goto clean_primary;
|
||||
goto clean_cursor;
|
||||
|
||||
qxl_crtc->index = crtc_id;
|
||||
drm_crtc_helper_add(&qxl_crtc->base, &qxl_crtc_helper_funcs);
|
||||
return 0;
|
||||
|
||||
clean_cursor:
|
||||
drm_plane_cleanup(cursor);
|
||||
kfree(cursor);
|
||||
clean_primary:
|
||||
drm_plane_cleanup(primary);
|
||||
kfree(primary);
|
||||
|
@ -1213,8 +1176,8 @@ int qxl_modeset_init(struct qxl_device *qdev)
|
|||
qdev->ddev.mode_config.funcs = (void *)&qxl_mode_funcs;
|
||||
|
||||
/* modes will be validated against the framebuffer size */
|
||||
qdev->ddev.mode_config.min_width = 320;
|
||||
qdev->ddev.mode_config.min_height = 200;
|
||||
qdev->ddev.mode_config.min_width = 0;
|
||||
qdev->ddev.mode_config.min_height = 0;
|
||||
qdev->ddev.mode_config.max_width = 8192;
|
||||
qdev->ddev.mode_config.max_height = 8192;
|
||||
|
||||
|
|
|
@ -134,11 +134,6 @@ struct qxl_bo_list {
|
|||
struct qxl_crtc {
|
||||
struct drm_crtc base;
|
||||
int index;
|
||||
int cur_x;
|
||||
int cur_y;
|
||||
int hot_spot_x;
|
||||
int hot_spot_y;
|
||||
struct qxl_bo *cursor_bo;
|
||||
};
|
||||
|
||||
struct qxl_output {
|
||||
|
|
Loading…
Reference in a new issue