diff --git a/qxl-reapply-cursor-after-SetCrtc-calls.patch b/qxl-reapply-cursor-after-SetCrtc-calls.patch new file mode 100644 index 000000000..2787cf7d1 --- /dev/null +++ b/qxl-reapply-cursor-after-SetCrtc-calls.patch @@ -0,0 +1,167 @@ +From 99ea1a3c387899424fb5c6b17baa56e8d68a3484 Mon Sep 17 00:00:00 2001 +From: Ray Strode +Date: Tue, 12 May 2015 12:51:18 -0400 +Subject: [PATCH] drm/qxl: reapply cursor after SetCrtc calls + +The qxl driver currently destroys and recreates the +qxl "primary" any time the first crtc is set. + +A side-effect of destroying the primary is mouse state +associated with the crtc is lost, which leads to +disappearing mouse cursors on wayland sessions. + +This commit changes the driver to reapply the cursor +any time SetCrtc is called. It achieves this by keeping +a copy of the cursor data on the qxl_crtc struct. + +Signed-off-by: Ray Strode + +https://bugzilla.redhat.com/show_bug.cgi?id=1200901 +--- + drivers/gpu/drm/qxl/qxl_display.c | 98 +++++++++++++++++++++++++++++++++++++++ + drivers/gpu/drm/qxl/qxl_drv.h | 1 + + 2 files changed, 99 insertions(+) + +diff --git a/drivers/gpu/drm/qxl/qxl_display.c b/drivers/gpu/drm/qxl/qxl_display.c +index 3aef127..fcc5f3b 100644 +--- a/drivers/gpu/drm/qxl/qxl_display.c ++++ b/drivers/gpu/drm/qxl/qxl_display.c +@@ -211,6 +211,7 @@ static void qxl_crtc_destroy(struct drm_crtc *crtc) + struct qxl_crtc *qxl_crtc = to_qxl_crtc(crtc); + + drm_crtc_cleanup(crtc); ++ kfree(qxl_crtc->cursor); + kfree(qxl_crtc); + } + +@@ -296,6 +297,92 @@ qxl_hide_cursor(struct qxl_device *qdev) + return 0; + } + ++static int qxl_crtc_stash_cursor(struct drm_crtc *crtc, ++ struct qxl_cursor *cursor) ++{ ++ struct qxl_crtc *qcrtc = to_qxl_crtc(crtc); ++ size_t cursor_size; ++ ++ cursor_size = sizeof(struct qxl_cursor) + cursor->data_size; ++ ++ if (!qcrtc->cursor || qcrtc->cursor->data_size != cursor->data_size) { ++ kfree(qcrtc->cursor); ++ qcrtc->cursor = kmalloc(cursor_size, GFP_KERNEL); ++ ++ if (!qcrtc->cursor) ++ return -ENOMEM; ++ } ++ ++ memcpy(qcrtc->cursor, cursor, cursor_size); ++ ++ 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 *cursor; ++ struct qxl_cursor_cmd *cmd; ++ struct qxl_bo *cursor_bo; ++ struct qxl_release *release; ++ size_t cursor_size; ++ int ret = 0; ++ ++ if (!qcrtc->cursor) ++ return 0; ++ ++ cursor_size = sizeof(*qcrtc->cursor) + qcrtc->cursor->data_size; ++ ++ ret = qxl_alloc_release_reserved(qdev, sizeof(*cmd), ++ QXL_RELEASE_CURSOR_CMD, ++ &release, NULL); ++ if (ret) ++ return ret; ++ ++ ret = qxl_alloc_bo_reserved(qdev, release, 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; ++ ++ memcpy(cursor, qcrtc->cursor, cursor_size); ++ ++ qxl_bo_kunmap(cursor_bo); ++ ++ cmd = (struct qxl_cursor_cmd *)qxl_release_map(qdev, release); ++ cmd->type = QXL_CURSOR_SET; ++ cmd->u.set.position.x = qcrtc->cur_x; ++ cmd->u.set.position.y = qcrtc->cur_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); ++ qxl_bo_unref(&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); ++ return ret; ++} ++ + static int qxl_crtc_cursor_set2(struct drm_crtc *crtc, + struct drm_file *file_priv, + uint32_t handle, +@@ -370,6 +457,12 @@ static int qxl_crtc_cursor_set2(struct drm_crtc *crtc, + + memcpy(cursor->chunk.data, user_ptr, size); + ++ ret = qxl_crtc_stash_cursor(crtc, cursor); ++ if (ret) { ++ DRM_ERROR("cannot save cursor, may be lost on next mode set\n"); ++ ret = 0; ++ } ++ + qxl_bo_kunmap(cursor_bo); + + qxl_bo_kunmap(user_bo); +@@ -655,6 +748,12 @@ 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) { +diff --git a/drivers/gpu/drm/qxl/qxl_drv.h b/drivers/gpu/drm/qxl/qxl_drv.h +index 8e633ca..6b63c54 100644 +--- a/drivers/gpu/drm/qxl/qxl_drv.h ++++ b/drivers/gpu/drm/qxl/qxl_drv.h +@@ -137,6 +137,7 @@ struct qxl_crtc { + int cur_y; + int hot_spot_x; + int hot_spot_y; ++ struct qxl_cursor *cursor; + }; + + struct qxl_output {