Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1277eed5 authored by Gabriel Krisman Bertazi's avatar Gabriel Krisman Bertazi Committed by Gerd Hoffmann
Browse files

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: default avatarGabriel Krisman Bertazi <krisman@collabora.co.uk>
Link: http://patchwork.freedesktop.org/patch/msgid/20170227204328.18761-6-krisman@collabora.co.uk


Signed-off-by: default avatarGerd Hoffmann <kraxel@redhat.com>
parent d3e7e42d
Loading
Loading
Loading
Loading
+202 −239
Original line number Original line Diff line number Diff line
@@ -30,6 +30,7 @@
#include "qxl_object.h"
#include "qxl_object.h"
#include "drm_crtc_helper.h"
#include "drm_crtc_helper.h"
#include <drm/drm_plane_helper.h>
#include <drm/drm_plane_helper.h>
#include <drm/drm_atomic_helper.h>


static bool qxl_head_enabled(struct qxl_head *head)
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);
	struct qxl_crtc *qxl_crtc = to_qxl_crtc(crtc);


	drm_crtc_cleanup(crtc);
	drm_crtc_cleanup(crtc);
	qxl_bo_unref(&qxl_crtc->cursor_bo);
	kfree(qxl_crtc);
	kfree(qxl_crtc);
}
}


@@ -304,234 +304,7 @@ static int qxl_crtc_page_flip(struct drm_crtc *crtc,
	return 0;
	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 = {
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,
	.set_config = drm_crtc_helper_set_config,
	.destroy = qxl_crtc_destroy,
	.destroy = qxl_crtc_destroy,
	.page_flip = qxl_crtc_page_flip,
	.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);
			   bo->surf.stride, bo->surf.format);
		qxl_io_create_primary(qdev, 0, bo);
		qxl_io_create_primary(qdev, 0, bo);
		bo->is_primary = true;
		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) {
	if (bo->is_primary) {
@@ -788,6 +555,188 @@ static const struct drm_crtc_helper_funcs qxl_crtc_helper_funcs = {
	.commit = qxl_crtc_commit,
	.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[] = {
static const uint32_t qxl_primary_plane_formats[] = {
	DRM_FORMAT_XRGB8888,
	DRM_FORMAT_XRGB8888,
	DRM_FORMAT_ARGB8888,
	DRM_FORMAT_ARGB8888,
@@ -814,6 +763,11 @@ static struct drm_plane *qxl_create_plane(struct qxl_device *qdev,
		funcs = &qxl_primary_plane_funcs;
		funcs = &qxl_primary_plane_funcs;
		formats = qxl_primary_plane_formats;
		formats = qxl_primary_plane_formats;
		num_formats = ARRAY_SIZE(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 {
	} else {
		return ERR_PTR(-EINVAL);
		return ERR_PTR(-EINVAL);
	}
	}
@@ -840,7 +794,7 @@ static struct drm_plane *qxl_create_plane(struct qxl_device *qdev,
static int qdev_crtc_init(struct drm_device *dev, int crtc_id)
static int qdev_crtc_init(struct drm_device *dev, int crtc_id)
{
{
	struct qxl_crtc *qxl_crtc;
	struct qxl_crtc *qxl_crtc;
	struct drm_plane *primary;
	struct drm_plane *primary, *cursor;
	struct qxl_device *qdev = dev->dev_private;
	struct qxl_device *qdev = dev->dev_private;
	int r;
	int r;


@@ -854,15 +808,24 @@ static int qdev_crtc_init(struct drm_device *dev, int crtc_id)
		goto free_mem;
		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);
				      &qxl_crtc_funcs, NULL);
	if (r)
	if (r)
		goto clean_primary;
		goto clean_cursor;


	qxl_crtc->index = crtc_id;
	qxl_crtc->index = crtc_id;
	drm_crtc_helper_add(&qxl_crtc->base, &qxl_crtc_helper_funcs);
	drm_crtc_helper_add(&qxl_crtc->base, &qxl_crtc_helper_funcs);
	return 0;
	return 0;


clean_cursor:
	drm_plane_cleanup(cursor);
	kfree(cursor);
clean_primary:
clean_primary:
	drm_plane_cleanup(primary);
	drm_plane_cleanup(primary);
	kfree(primary);
	kfree(primary);
@@ -1213,8 +1176,8 @@ int qxl_modeset_init(struct qxl_device *qdev)
	qdev->ddev.mode_config.funcs = (void *)&qxl_mode_funcs;
	qdev->ddev.mode_config.funcs = (void *)&qxl_mode_funcs;


	/* modes will be validated against the framebuffer size */
	/* modes will be validated against the framebuffer size */
	qdev->ddev.mode_config.min_width = 320;
	qdev->ddev.mode_config.min_width = 0;
	qdev->ddev.mode_config.min_height = 200;
	qdev->ddev.mode_config.min_height = 0;
	qdev->ddev.mode_config.max_width = 8192;
	qdev->ddev.mode_config.max_width = 8192;
	qdev->ddev.mode_config.max_height = 8192;
	qdev->ddev.mode_config.max_height = 8192;


+0 −5
Original line number Original line Diff line number Diff line
@@ -134,11 +134,6 @@ struct qxl_bo_list {
struct qxl_crtc {
struct qxl_crtc {
	struct drm_crtc base;
	struct drm_crtc base;
	int index;
	int index;
	int cur_x;
	int cur_y;
	int hot_spot_x;
	int hot_spot_y;
	struct qxl_bo *cursor_bo;
};
};


struct qxl_output {
struct qxl_output {