virtgpu_plane.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428
  1. /*
  2. * Copyright (C) 2015 Red Hat, Inc.
  3. * All Rights Reserved.
  4. *
  5. * Permission is hereby granted, free of charge, to any person obtaining
  6. * a copy of this software and associated documentation files (the
  7. * "Software"), to deal in the Software without restriction, including
  8. * without limitation the rights to use, copy, modify, merge, publish,
  9. * distribute, sublicense, and/or sell copies of the Software, and to
  10. * permit persons to whom the Software is furnished to do so, subject to
  11. * the following conditions:
  12. *
  13. * The above copyright notice and this permission notice (including the
  14. * next paragraph) shall be included in all copies or substantial
  15. * portions of the Software.
  16. *
  17. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  18. * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  19. * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
  20. * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
  21. * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  22. * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  23. * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  24. */
  25. #include <drm/drm_atomic_helper.h>
  26. #include <drm/drm_damage_helper.h>
  27. #include <drm/drm_fourcc.h>
  28. #include "virtgpu_drv.h"
  29. static const uint32_t virtio_gpu_formats[] = {
  30. DRM_FORMAT_HOST_XRGB8888,
  31. };
  32. static const uint32_t virtio_gpu_cursor_formats[] = {
  33. DRM_FORMAT_HOST_ARGB8888,
  34. };
  35. uint32_t virtio_gpu_translate_format(uint32_t drm_fourcc)
  36. {
  37. uint32_t format;
  38. switch (drm_fourcc) {
  39. case DRM_FORMAT_XRGB8888:
  40. format = VIRTIO_GPU_FORMAT_B8G8R8X8_UNORM;
  41. break;
  42. case DRM_FORMAT_ARGB8888:
  43. format = VIRTIO_GPU_FORMAT_B8G8R8A8_UNORM;
  44. break;
  45. case DRM_FORMAT_BGRX8888:
  46. format = VIRTIO_GPU_FORMAT_X8R8G8B8_UNORM;
  47. break;
  48. case DRM_FORMAT_BGRA8888:
  49. format = VIRTIO_GPU_FORMAT_A8R8G8B8_UNORM;
  50. break;
  51. default:
  52. /*
  53. * This should not happen, we handle everything listed
  54. * in virtio_gpu_formats[].
  55. */
  56. format = 0;
  57. break;
  58. }
  59. WARN_ON(format == 0);
  60. return format;
  61. }
  62. static struct
  63. drm_plane_state *virtio_gpu_plane_duplicate_state(struct drm_plane *plane)
  64. {
  65. struct virtio_gpu_plane_state *new;
  66. if (WARN_ON(!plane->state))
  67. return NULL;
  68. new = kzalloc(sizeof(*new), GFP_KERNEL);
  69. if (!new)
  70. return NULL;
  71. __drm_atomic_helper_plane_duplicate_state(plane, &new->base);
  72. return &new->base;
  73. }
  74. static const struct drm_plane_funcs virtio_gpu_plane_funcs = {
  75. .update_plane = drm_atomic_helper_update_plane,
  76. .disable_plane = drm_atomic_helper_disable_plane,
  77. .reset = drm_atomic_helper_plane_reset,
  78. .atomic_duplicate_state = virtio_gpu_plane_duplicate_state,
  79. .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
  80. };
  81. static int virtio_gpu_plane_atomic_check(struct drm_plane *plane,
  82. struct drm_atomic_state *state)
  83. {
  84. struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
  85. plane);
  86. struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(state,
  87. plane);
  88. bool is_cursor = plane->type == DRM_PLANE_TYPE_CURSOR;
  89. struct drm_crtc_state *crtc_state;
  90. int ret;
  91. if (!new_plane_state->fb || WARN_ON(!new_plane_state->crtc))
  92. return 0;
  93. /*
  94. * Ignore damage clips if the framebuffer attached to the plane's state
  95. * has changed since the last plane update (page-flip). In this case, a
  96. * full plane update should happen because uploads are done per-buffer.
  97. */
  98. if (old_plane_state->fb != new_plane_state->fb)
  99. new_plane_state->ignore_damage_clips = true;
  100. crtc_state = drm_atomic_get_crtc_state(state,
  101. new_plane_state->crtc);
  102. if (IS_ERR(crtc_state))
  103. return PTR_ERR(crtc_state);
  104. ret = drm_atomic_helper_check_plane_state(new_plane_state, crtc_state,
  105. DRM_PLANE_NO_SCALING,
  106. DRM_PLANE_NO_SCALING,
  107. is_cursor, true);
  108. return ret;
  109. }
  110. static void virtio_gpu_update_dumb_bo(struct virtio_gpu_device *vgdev,
  111. struct drm_plane_state *state,
  112. struct drm_rect *rect)
  113. {
  114. struct virtio_gpu_object *bo =
  115. gem_to_virtio_gpu_obj(state->fb->obj[0]);
  116. struct virtio_gpu_object_array *objs;
  117. uint32_t w = rect->x2 - rect->x1;
  118. uint32_t h = rect->y2 - rect->y1;
  119. uint32_t x = rect->x1;
  120. uint32_t y = rect->y1;
  121. uint32_t off = x * state->fb->format->cpp[0] +
  122. y * state->fb->pitches[0];
  123. objs = virtio_gpu_array_alloc(1);
  124. if (!objs)
  125. return;
  126. virtio_gpu_array_add_obj(objs, &bo->base.base);
  127. virtio_gpu_cmd_transfer_to_host_2d(vgdev, off, w, h, x, y,
  128. objs, NULL);
  129. }
  130. static void virtio_gpu_resource_flush(struct drm_plane *plane,
  131. uint32_t x, uint32_t y,
  132. uint32_t width, uint32_t height)
  133. {
  134. struct drm_device *dev = plane->dev;
  135. struct virtio_gpu_device *vgdev = dev->dev_private;
  136. struct virtio_gpu_framebuffer *vgfb;
  137. struct virtio_gpu_plane_state *vgplane_st;
  138. struct virtio_gpu_object *bo;
  139. vgfb = to_virtio_gpu_framebuffer(plane->state->fb);
  140. vgplane_st = to_virtio_gpu_plane_state(plane->state);
  141. bo = gem_to_virtio_gpu_obj(vgfb->base.obj[0]);
  142. if (vgplane_st->fence) {
  143. struct virtio_gpu_object_array *objs;
  144. objs = virtio_gpu_array_alloc(1);
  145. if (!objs)
  146. return;
  147. virtio_gpu_array_add_obj(objs, vgfb->base.obj[0]);
  148. virtio_gpu_array_lock_resv(objs);
  149. virtio_gpu_cmd_resource_flush(vgdev, bo->hw_res_handle, x, y,
  150. width, height, objs,
  151. vgplane_st->fence);
  152. virtio_gpu_notify(vgdev);
  153. dma_fence_wait_timeout(&vgplane_st->fence->f, true,
  154. msecs_to_jiffies(50));
  155. } else {
  156. virtio_gpu_cmd_resource_flush(vgdev, bo->hw_res_handle, x, y,
  157. width, height, NULL, NULL);
  158. virtio_gpu_notify(vgdev);
  159. }
  160. }
  161. static void virtio_gpu_primary_plane_update(struct drm_plane *plane,
  162. struct drm_atomic_state *state)
  163. {
  164. struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state,
  165. plane);
  166. struct drm_device *dev = plane->dev;
  167. struct virtio_gpu_device *vgdev = dev->dev_private;
  168. struct virtio_gpu_output *output = NULL;
  169. struct virtio_gpu_object *bo;
  170. struct drm_rect rect;
  171. if (plane->state->crtc)
  172. output = drm_crtc_to_virtio_gpu_output(plane->state->crtc);
  173. if (old_state->crtc)
  174. output = drm_crtc_to_virtio_gpu_output(old_state->crtc);
  175. if (WARN_ON(!output))
  176. return;
  177. if (!plane->state->fb || !output->crtc.state->active) {
  178. DRM_DEBUG("nofb\n");
  179. virtio_gpu_cmd_set_scanout(vgdev, output->index, 0,
  180. plane->state->src_w >> 16,
  181. plane->state->src_h >> 16,
  182. 0, 0);
  183. virtio_gpu_notify(vgdev);
  184. return;
  185. }
  186. if (!drm_atomic_helper_damage_merged(old_state, plane->state, &rect))
  187. return;
  188. bo = gem_to_virtio_gpu_obj(plane->state->fb->obj[0]);
  189. if (bo->dumb)
  190. virtio_gpu_update_dumb_bo(vgdev, plane->state, &rect);
  191. if (plane->state->fb != old_state->fb ||
  192. plane->state->src_w != old_state->src_w ||
  193. plane->state->src_h != old_state->src_h ||
  194. plane->state->src_x != old_state->src_x ||
  195. plane->state->src_y != old_state->src_y ||
  196. output->needs_modeset) {
  197. output->needs_modeset = false;
  198. DRM_DEBUG("handle 0x%x, crtc %dx%d+%d+%d, src %dx%d+%d+%d\n",
  199. bo->hw_res_handle,
  200. plane->state->crtc_w, plane->state->crtc_h,
  201. plane->state->crtc_x, plane->state->crtc_y,
  202. plane->state->src_w >> 16,
  203. plane->state->src_h >> 16,
  204. plane->state->src_x >> 16,
  205. plane->state->src_y >> 16);
  206. if (bo->host3d_blob || bo->guest_blob) {
  207. virtio_gpu_cmd_set_scanout_blob
  208. (vgdev, output->index, bo,
  209. plane->state->fb,
  210. plane->state->src_w >> 16,
  211. plane->state->src_h >> 16,
  212. plane->state->src_x >> 16,
  213. plane->state->src_y >> 16);
  214. } else {
  215. virtio_gpu_cmd_set_scanout(vgdev, output->index,
  216. bo->hw_res_handle,
  217. plane->state->src_w >> 16,
  218. plane->state->src_h >> 16,
  219. plane->state->src_x >> 16,
  220. plane->state->src_y >> 16);
  221. }
  222. }
  223. virtio_gpu_resource_flush(plane,
  224. rect.x1,
  225. rect.y1,
  226. rect.x2 - rect.x1,
  227. rect.y2 - rect.y1);
  228. }
  229. static int virtio_gpu_plane_prepare_fb(struct drm_plane *plane,
  230. struct drm_plane_state *new_state)
  231. {
  232. struct drm_device *dev = plane->dev;
  233. struct virtio_gpu_device *vgdev = dev->dev_private;
  234. struct virtio_gpu_framebuffer *vgfb;
  235. struct virtio_gpu_plane_state *vgplane_st;
  236. struct virtio_gpu_object *bo;
  237. if (!new_state->fb)
  238. return 0;
  239. vgfb = to_virtio_gpu_framebuffer(new_state->fb);
  240. vgplane_st = to_virtio_gpu_plane_state(new_state);
  241. bo = gem_to_virtio_gpu_obj(vgfb->base.obj[0]);
  242. if (!bo || (plane->type == DRM_PLANE_TYPE_PRIMARY && !bo->guest_blob))
  243. return 0;
  244. if (bo->dumb) {
  245. vgplane_st->fence = virtio_gpu_fence_alloc(vgdev,
  246. vgdev->fence_drv.context,
  247. 0);
  248. if (!vgplane_st->fence)
  249. return -ENOMEM;
  250. }
  251. return 0;
  252. }
  253. static void virtio_gpu_plane_cleanup_fb(struct drm_plane *plane,
  254. struct drm_plane_state *state)
  255. {
  256. struct virtio_gpu_plane_state *vgplane_st;
  257. if (!state->fb)
  258. return;
  259. vgplane_st = to_virtio_gpu_plane_state(state);
  260. if (vgplane_st->fence) {
  261. dma_fence_put(&vgplane_st->fence->f);
  262. vgplane_st->fence = NULL;
  263. }
  264. }
  265. static void virtio_gpu_cursor_plane_update(struct drm_plane *plane,
  266. struct drm_atomic_state *state)
  267. {
  268. struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state,
  269. plane);
  270. struct drm_device *dev = plane->dev;
  271. struct virtio_gpu_device *vgdev = dev->dev_private;
  272. struct virtio_gpu_output *output = NULL;
  273. struct virtio_gpu_framebuffer *vgfb;
  274. struct virtio_gpu_plane_state *vgplane_st;
  275. struct virtio_gpu_object *bo = NULL;
  276. uint32_t handle;
  277. if (plane->state->crtc)
  278. output = drm_crtc_to_virtio_gpu_output(plane->state->crtc);
  279. if (old_state->crtc)
  280. output = drm_crtc_to_virtio_gpu_output(old_state->crtc);
  281. if (WARN_ON(!output))
  282. return;
  283. if (plane->state->fb) {
  284. vgfb = to_virtio_gpu_framebuffer(plane->state->fb);
  285. vgplane_st = to_virtio_gpu_plane_state(plane->state);
  286. bo = gem_to_virtio_gpu_obj(vgfb->base.obj[0]);
  287. handle = bo->hw_res_handle;
  288. } else {
  289. handle = 0;
  290. }
  291. if (bo && bo->dumb && (plane->state->fb != old_state->fb)) {
  292. /* new cursor -- update & wait */
  293. struct virtio_gpu_object_array *objs;
  294. objs = virtio_gpu_array_alloc(1);
  295. if (!objs)
  296. return;
  297. virtio_gpu_array_add_obj(objs, vgfb->base.obj[0]);
  298. virtio_gpu_array_lock_resv(objs);
  299. virtio_gpu_cmd_transfer_to_host_2d
  300. (vgdev, 0,
  301. plane->state->crtc_w,
  302. plane->state->crtc_h,
  303. 0, 0, objs, vgplane_st->fence);
  304. virtio_gpu_notify(vgdev);
  305. dma_fence_wait(&vgplane_st->fence->f, true);
  306. }
  307. if (plane->state->fb != old_state->fb) {
  308. DRM_DEBUG("update, handle %d, pos +%d+%d, hot %d,%d\n", handle,
  309. plane->state->crtc_x,
  310. plane->state->crtc_y,
  311. plane->state->hotspot_x,
  312. plane->state->hotspot_y);
  313. output->cursor.hdr.type =
  314. cpu_to_le32(VIRTIO_GPU_CMD_UPDATE_CURSOR);
  315. output->cursor.resource_id = cpu_to_le32(handle);
  316. if (plane->state->fb) {
  317. output->cursor.hot_x =
  318. cpu_to_le32(plane->state->hotspot_x);
  319. output->cursor.hot_y =
  320. cpu_to_le32(plane->state->hotspot_y);
  321. } else {
  322. output->cursor.hot_x = cpu_to_le32(0);
  323. output->cursor.hot_y = cpu_to_le32(0);
  324. }
  325. } else {
  326. DRM_DEBUG("move +%d+%d\n",
  327. plane->state->crtc_x,
  328. plane->state->crtc_y);
  329. output->cursor.hdr.type =
  330. cpu_to_le32(VIRTIO_GPU_CMD_MOVE_CURSOR);
  331. }
  332. output->cursor.pos.x = cpu_to_le32(plane->state->crtc_x);
  333. output->cursor.pos.y = cpu_to_le32(plane->state->crtc_y);
  334. virtio_gpu_cursor_ping(vgdev, output);
  335. }
  336. static const struct drm_plane_helper_funcs virtio_gpu_primary_helper_funcs = {
  337. .prepare_fb = virtio_gpu_plane_prepare_fb,
  338. .cleanup_fb = virtio_gpu_plane_cleanup_fb,
  339. .atomic_check = virtio_gpu_plane_atomic_check,
  340. .atomic_update = virtio_gpu_primary_plane_update,
  341. };
  342. static const struct drm_plane_helper_funcs virtio_gpu_cursor_helper_funcs = {
  343. .prepare_fb = virtio_gpu_plane_prepare_fb,
  344. .cleanup_fb = virtio_gpu_plane_cleanup_fb,
  345. .atomic_check = virtio_gpu_plane_atomic_check,
  346. .atomic_update = virtio_gpu_cursor_plane_update,
  347. };
  348. struct drm_plane *virtio_gpu_plane_init(struct virtio_gpu_device *vgdev,
  349. enum drm_plane_type type,
  350. int index)
  351. {
  352. struct drm_device *dev = vgdev->ddev;
  353. const struct drm_plane_helper_funcs *funcs;
  354. struct drm_plane *plane;
  355. const uint32_t *formats;
  356. int nformats;
  357. if (type == DRM_PLANE_TYPE_CURSOR) {
  358. formats = virtio_gpu_cursor_formats;
  359. nformats = ARRAY_SIZE(virtio_gpu_cursor_formats);
  360. funcs = &virtio_gpu_cursor_helper_funcs;
  361. } else {
  362. formats = virtio_gpu_formats;
  363. nformats = ARRAY_SIZE(virtio_gpu_formats);
  364. funcs = &virtio_gpu_primary_helper_funcs;
  365. }
  366. plane = drmm_universal_plane_alloc(dev, struct drm_plane, dev,
  367. 1 << index, &virtio_gpu_plane_funcs,
  368. formats, nformats, NULL, type, NULL);
  369. if (IS_ERR(plane))
  370. return plane;
  371. drm_plane_helper_add(plane, funcs);
  372. if (type == DRM_PLANE_TYPE_PRIMARY)
  373. drm_plane_enable_fb_damage_clips(plane);
  374. return plane;
  375. }