summaryrefslogtreecommitdiffstats
path: root/qxl-reapply-cursor-after-SetCrtc-calls.patch
blob: 2787cf7d15bccea8c4b8bd99e8e63aa51962494e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
From 99ea1a3c387899424fb5c6b17baa56e8d68a3484 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
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 <rstrode@redhat.com>

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 {