diff options
Diffstat (limited to 'drivers/gpu/drm/virtio/virtgpu_plane.c')
-rw-r--r-- | drivers/gpu/drm/virtio/virtgpu_plane.c | 150 |
1 files changed, 127 insertions, 23 deletions
diff --git a/drivers/gpu/drm/virtio/virtgpu_plane.c b/drivers/gpu/drm/virtio/virtgpu_plane.c index 70b44a2345ab..925ca25209df 100644 --- a/drivers/gpu/drm/virtio/virtgpu_plane.c +++ b/drivers/gpu/drm/virtio/virtgpu_plane.c | |||
@@ -38,6 +38,10 @@ static const uint32_t virtio_gpu_formats[] = { | |||
38 | DRM_FORMAT_ABGR8888, | 38 | DRM_FORMAT_ABGR8888, |
39 | }; | 39 | }; |
40 | 40 | ||
41 | static const uint32_t virtio_gpu_cursor_formats[] = { | ||
42 | DRM_FORMAT_ARGB8888, | ||
43 | }; | ||
44 | |||
41 | static void virtio_gpu_plane_destroy(struct drm_plane *plane) | 45 | static void virtio_gpu_plane_destroy(struct drm_plane *plane) |
42 | { | 46 | { |
43 | kfree(plane); | 47 | kfree(plane); |
@@ -58,16 +62,22 @@ static int virtio_gpu_plane_atomic_check(struct drm_plane *plane, | |||
58 | return 0; | 62 | return 0; |
59 | } | 63 | } |
60 | 64 | ||
61 | static void virtio_gpu_plane_atomic_update(struct drm_plane *plane, | 65 | static void virtio_gpu_primary_plane_update(struct drm_plane *plane, |
62 | struct drm_plane_state *old_state) | 66 | struct drm_plane_state *old_state) |
63 | { | 67 | { |
64 | struct drm_device *dev = plane->dev; | 68 | struct drm_device *dev = plane->dev; |
65 | struct virtio_gpu_device *vgdev = dev->dev_private; | 69 | struct virtio_gpu_device *vgdev = dev->dev_private; |
66 | struct virtio_gpu_output *output = drm_crtc_to_virtio_gpu_output(plane->crtc); | 70 | struct virtio_gpu_output *output = NULL; |
67 | struct virtio_gpu_framebuffer *vgfb; | 71 | struct virtio_gpu_framebuffer *vgfb; |
68 | struct virtio_gpu_object *bo; | 72 | struct virtio_gpu_object *bo; |
69 | uint32_t handle; | 73 | uint32_t handle; |
70 | 74 | ||
75 | if (plane->state->crtc) | ||
76 | output = drm_crtc_to_virtio_gpu_output(plane->state->crtc); | ||
77 | if (old_state->crtc) | ||
78 | output = drm_crtc_to_virtio_gpu_output(old_state->crtc); | ||
79 | WARN_ON(!output); | ||
80 | |||
71 | if (plane->state->fb) { | 81 | if (plane->state->fb) { |
72 | vgfb = to_virtio_gpu_framebuffer(plane->state->fb); | 82 | vgfb = to_virtio_gpu_framebuffer(plane->state->fb); |
73 | bo = gem_to_virtio_gpu_obj(vgfb->obj); | 83 | bo = gem_to_virtio_gpu_obj(vgfb->obj); |
@@ -75,55 +85,149 @@ static void virtio_gpu_plane_atomic_update(struct drm_plane *plane, | |||
75 | if (bo->dumb) { | 85 | if (bo->dumb) { |
76 | virtio_gpu_cmd_transfer_to_host_2d | 86 | virtio_gpu_cmd_transfer_to_host_2d |
77 | (vgdev, handle, 0, | 87 | (vgdev, handle, 0, |
78 | cpu_to_le32(plane->state->crtc_w), | 88 | cpu_to_le32(plane->state->src_w >> 16), |
79 | cpu_to_le32(plane->state->crtc_h), | 89 | cpu_to_le32(plane->state->src_h >> 16), |
80 | plane->state->crtc_x, plane->state->crtc_y, NULL); | 90 | plane->state->src_x >> 16, |
91 | plane->state->src_y >> 16, NULL); | ||
81 | } | 92 | } |
82 | } else { | 93 | } else { |
83 | handle = 0; | 94 | handle = 0; |
84 | } | 95 | } |
85 | 96 | ||
86 | DRM_DEBUG("handle 0x%x, crtc %dx%d+%d+%d\n", handle, | 97 | DRM_DEBUG("handle 0x%x, crtc %dx%d+%d+%d, src %dx%d+%d+%d\n", handle, |
87 | plane->state->crtc_w, plane->state->crtc_h, | 98 | plane->state->crtc_w, plane->state->crtc_h, |
88 | plane->state->crtc_x, plane->state->crtc_y); | 99 | plane->state->crtc_x, plane->state->crtc_y, |
100 | plane->state->src_w >> 16, | ||
101 | plane->state->src_h >> 16, | ||
102 | plane->state->src_x >> 16, | ||
103 | plane->state->src_y >> 16); | ||
89 | virtio_gpu_cmd_set_scanout(vgdev, output->index, handle, | 104 | virtio_gpu_cmd_set_scanout(vgdev, output->index, handle, |
90 | plane->state->crtc_w, | 105 | plane->state->src_w >> 16, |
91 | plane->state->crtc_h, | 106 | plane->state->src_h >> 16, |
92 | plane->state->crtc_x, | 107 | plane->state->src_x >> 16, |
93 | plane->state->crtc_y); | 108 | plane->state->src_y >> 16); |
94 | virtio_gpu_cmd_resource_flush(vgdev, handle, | 109 | virtio_gpu_cmd_resource_flush(vgdev, handle, |
95 | plane->state->crtc_x, | 110 | plane->state->src_x >> 16, |
96 | plane->state->crtc_y, | 111 | plane->state->src_y >> 16, |
97 | plane->state->crtc_w, | 112 | plane->state->src_w >> 16, |
98 | plane->state->crtc_h); | 113 | plane->state->src_h >> 16); |
99 | } | 114 | } |
100 | 115 | ||
116 | static void virtio_gpu_cursor_plane_update(struct drm_plane *plane, | ||
117 | struct drm_plane_state *old_state) | ||
118 | { | ||
119 | struct drm_device *dev = plane->dev; | ||
120 | struct virtio_gpu_device *vgdev = dev->dev_private; | ||
121 | struct virtio_gpu_output *output = NULL; | ||
122 | struct virtio_gpu_framebuffer *vgfb; | ||
123 | struct virtio_gpu_fence *fence = NULL; | ||
124 | struct virtio_gpu_object *bo = NULL; | ||
125 | uint32_t handle; | ||
126 | int ret = 0; | ||
101 | 127 | ||
102 | static const struct drm_plane_helper_funcs virtio_gpu_plane_helper_funcs = { | 128 | if (plane->state->crtc) |
129 | output = drm_crtc_to_virtio_gpu_output(plane->state->crtc); | ||
130 | if (old_state->crtc) | ||
131 | output = drm_crtc_to_virtio_gpu_output(old_state->crtc); | ||
132 | WARN_ON(!output); | ||
133 | |||
134 | if (plane->state->fb) { | ||
135 | vgfb = to_virtio_gpu_framebuffer(plane->state->fb); | ||
136 | bo = gem_to_virtio_gpu_obj(vgfb->obj); | ||
137 | handle = bo->hw_res_handle; | ||
138 | } else { | ||
139 | handle = 0; | ||
140 | } | ||
141 | |||
142 | if (bo && bo->dumb && (plane->state->fb != old_state->fb)) { | ||
143 | /* new cursor -- update & wait */ | ||
144 | virtio_gpu_cmd_transfer_to_host_2d | ||
145 | (vgdev, handle, 0, | ||
146 | cpu_to_le32(plane->state->crtc_w), | ||
147 | cpu_to_le32(plane->state->crtc_h), | ||
148 | 0, 0, &fence); | ||
149 | ret = virtio_gpu_object_reserve(bo, false); | ||
150 | if (!ret) { | ||
151 | reservation_object_add_excl_fence(bo->tbo.resv, | ||
152 | &fence->f); | ||
153 | fence_put(&fence->f); | ||
154 | fence = NULL; | ||
155 | virtio_gpu_object_unreserve(bo); | ||
156 | virtio_gpu_object_wait(bo, false); | ||
157 | } | ||
158 | } | ||
159 | |||
160 | if (plane->state->fb != old_state->fb) { | ||
161 | DRM_DEBUG("update, handle %d, pos +%d+%d, hot %d,%d\n", handle, | ||
162 | plane->state->crtc_x, | ||
163 | plane->state->crtc_y, | ||
164 | plane->state->fb ? plane->state->fb->hot_x : 0, | ||
165 | plane->state->fb ? plane->state->fb->hot_y : 0); | ||
166 | output->cursor.hdr.type = | ||
167 | cpu_to_le32(VIRTIO_GPU_CMD_UPDATE_CURSOR); | ||
168 | output->cursor.resource_id = cpu_to_le32(handle); | ||
169 | if (plane->state->fb) { | ||
170 | output->cursor.hot_x = | ||
171 | cpu_to_le32(plane->state->fb->hot_x); | ||
172 | output->cursor.hot_y = | ||
173 | cpu_to_le32(plane->state->fb->hot_y); | ||
174 | } else { | ||
175 | output->cursor.hot_x = cpu_to_le32(0); | ||
176 | output->cursor.hot_y = cpu_to_le32(0); | ||
177 | } | ||
178 | } else { | ||
179 | DRM_DEBUG("move +%d+%d\n", | ||
180 | plane->state->crtc_x, | ||
181 | plane->state->crtc_y); | ||
182 | output->cursor.hdr.type = | ||
183 | cpu_to_le32(VIRTIO_GPU_CMD_MOVE_CURSOR); | ||
184 | } | ||
185 | output->cursor.pos.x = cpu_to_le32(plane->state->crtc_x); | ||
186 | output->cursor.pos.y = cpu_to_le32(plane->state->crtc_y); | ||
187 | virtio_gpu_cursor_ping(vgdev, output); | ||
188 | } | ||
189 | |||
190 | static const struct drm_plane_helper_funcs virtio_gpu_primary_helper_funcs = { | ||
191 | .atomic_check = virtio_gpu_plane_atomic_check, | ||
192 | .atomic_update = virtio_gpu_primary_plane_update, | ||
193 | }; | ||
194 | |||
195 | static const struct drm_plane_helper_funcs virtio_gpu_cursor_helper_funcs = { | ||
103 | .atomic_check = virtio_gpu_plane_atomic_check, | 196 | .atomic_check = virtio_gpu_plane_atomic_check, |
104 | .atomic_update = virtio_gpu_plane_atomic_update, | 197 | .atomic_update = virtio_gpu_cursor_plane_update, |
105 | }; | 198 | }; |
106 | 199 | ||
107 | struct drm_plane *virtio_gpu_plane_init(struct virtio_gpu_device *vgdev, | 200 | struct drm_plane *virtio_gpu_plane_init(struct virtio_gpu_device *vgdev, |
201 | enum drm_plane_type type, | ||
108 | int index) | 202 | int index) |
109 | { | 203 | { |
110 | struct drm_device *dev = vgdev->ddev; | 204 | struct drm_device *dev = vgdev->ddev; |
205 | const struct drm_plane_helper_funcs *funcs; | ||
111 | struct drm_plane *plane; | 206 | struct drm_plane *plane; |
112 | int ret; | 207 | const uint32_t *formats; |
208 | int ret, nformats; | ||
113 | 209 | ||
114 | plane = kzalloc(sizeof(*plane), GFP_KERNEL); | 210 | plane = kzalloc(sizeof(*plane), GFP_KERNEL); |
115 | if (!plane) | 211 | if (!plane) |
116 | return ERR_PTR(-ENOMEM); | 212 | return ERR_PTR(-ENOMEM); |
117 | 213 | ||
214 | if (type == DRM_PLANE_TYPE_CURSOR) { | ||
215 | formats = virtio_gpu_cursor_formats; | ||
216 | nformats = ARRAY_SIZE(virtio_gpu_cursor_formats); | ||
217 | funcs = &virtio_gpu_cursor_helper_funcs; | ||
218 | } else { | ||
219 | formats = virtio_gpu_formats; | ||
220 | nformats = ARRAY_SIZE(virtio_gpu_formats); | ||
221 | funcs = &virtio_gpu_primary_helper_funcs; | ||
222 | } | ||
118 | ret = drm_universal_plane_init(dev, plane, 1 << index, | 223 | ret = drm_universal_plane_init(dev, plane, 1 << index, |
119 | &virtio_gpu_plane_funcs, | 224 | &virtio_gpu_plane_funcs, |
120 | virtio_gpu_formats, | 225 | formats, nformats, |
121 | ARRAY_SIZE(virtio_gpu_formats), | 226 | type, NULL); |
122 | DRM_PLANE_TYPE_PRIMARY, NULL); | ||
123 | if (ret) | 227 | if (ret) |
124 | goto err_plane_init; | 228 | goto err_plane_init; |
125 | 229 | ||
126 | drm_plane_helper_add(plane, &virtio_gpu_plane_helper_funcs); | 230 | drm_plane_helper_add(plane, funcs); |
127 | return plane; | 231 | return plane; |
128 | 232 | ||
129 | err_plane_init: | 233 | err_plane_init: |