virtgpu_plane.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608
  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 <drm/drm_gem_atomic_helper.h>
  29. #include <linux/virtio_dma_buf.h>
  30. #include <drm/drm_managed.h>
  31. #include <drm/drm_panic.h>
  32. #include <drm/drm_print.h>
  33. #include "virtgpu_drv.h"
  34. static const uint32_t virtio_gpu_formats[] = {
  35. DRM_FORMAT_HOST_XRGB8888,
  36. };
  37. static const uint32_t virtio_gpu_cursor_formats[] = {
  38. DRM_FORMAT_HOST_ARGB8888,
  39. };
  40. uint32_t virtio_gpu_translate_format(uint32_t drm_fourcc)
  41. {
  42. uint32_t format;
  43. switch (drm_fourcc) {
  44. case DRM_FORMAT_XRGB8888:
  45. format = VIRTIO_GPU_FORMAT_B8G8R8X8_UNORM;
  46. break;
  47. case DRM_FORMAT_ARGB8888:
  48. format = VIRTIO_GPU_FORMAT_B8G8R8A8_UNORM;
  49. break;
  50. case DRM_FORMAT_BGRX8888:
  51. format = VIRTIO_GPU_FORMAT_X8R8G8B8_UNORM;
  52. break;
  53. case DRM_FORMAT_BGRA8888:
  54. format = VIRTIO_GPU_FORMAT_A8R8G8B8_UNORM;
  55. break;
  56. default:
  57. /*
  58. * This should not happen, we handle everything listed
  59. * in virtio_gpu_formats[].
  60. */
  61. format = 0;
  62. break;
  63. }
  64. WARN_ON(format == 0);
  65. return format;
  66. }
  67. static struct
  68. drm_plane_state *virtio_gpu_plane_duplicate_state(struct drm_plane *plane)
  69. {
  70. struct virtio_gpu_plane_state *new;
  71. if (WARN_ON(!plane->state))
  72. return NULL;
  73. new = kzalloc_obj(*new);
  74. if (!new)
  75. return NULL;
  76. __drm_atomic_helper_plane_duplicate_state(plane, &new->base);
  77. return &new->base;
  78. }
  79. static const struct drm_plane_funcs virtio_gpu_plane_funcs = {
  80. .update_plane = drm_atomic_helper_update_plane,
  81. .disable_plane = drm_atomic_helper_disable_plane,
  82. .reset = drm_atomic_helper_plane_reset,
  83. .atomic_duplicate_state = virtio_gpu_plane_duplicate_state,
  84. .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
  85. };
  86. static int virtio_gpu_plane_atomic_check(struct drm_plane *plane,
  87. struct drm_atomic_state *state)
  88. {
  89. struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
  90. plane);
  91. struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(state,
  92. plane);
  93. bool is_cursor = plane->type == DRM_PLANE_TYPE_CURSOR;
  94. struct drm_crtc_state *crtc_state;
  95. int ret;
  96. if (!new_plane_state->fb || WARN_ON(!new_plane_state->crtc))
  97. return 0;
  98. /*
  99. * Ignore damage clips if the framebuffer attached to the plane's state
  100. * has changed since the last plane update (page-flip). In this case, a
  101. * full plane update should happen because uploads are done per-buffer.
  102. */
  103. if (old_plane_state->fb != new_plane_state->fb)
  104. new_plane_state->ignore_damage_clips = true;
  105. crtc_state = drm_atomic_get_crtc_state(state,
  106. new_plane_state->crtc);
  107. if (IS_ERR(crtc_state))
  108. return PTR_ERR(crtc_state);
  109. ret = drm_atomic_helper_check_plane_state(new_plane_state, crtc_state,
  110. DRM_PLANE_NO_SCALING,
  111. DRM_PLANE_NO_SCALING,
  112. is_cursor, true);
  113. return ret;
  114. }
  115. /* For drm panic */
  116. static int virtio_gpu_panic_update_dumb_bo(struct virtio_gpu_device *vgdev,
  117. struct drm_plane_state *state,
  118. struct drm_rect *rect)
  119. {
  120. struct virtio_gpu_object *bo =
  121. gem_to_virtio_gpu_obj(state->fb->obj[0]);
  122. struct virtio_gpu_object_array *objs;
  123. uint32_t w = rect->x2 - rect->x1;
  124. uint32_t h = rect->y2 - rect->y1;
  125. uint32_t x = rect->x1;
  126. uint32_t y = rect->y1;
  127. uint32_t off = x * state->fb->format->cpp[0] +
  128. y * state->fb->pitches[0];
  129. objs = virtio_gpu_panic_array_alloc();
  130. if (!objs)
  131. return -ENOMEM;
  132. virtio_gpu_array_add_obj(objs, &bo->base.base);
  133. return virtio_gpu_panic_cmd_transfer_to_host_2d(vgdev, off, w, h, x, y,
  134. objs);
  135. }
  136. static void virtio_gpu_update_dumb_bo(struct virtio_gpu_device *vgdev,
  137. struct drm_plane_state *state,
  138. struct drm_rect *rect)
  139. {
  140. struct virtio_gpu_object *bo =
  141. gem_to_virtio_gpu_obj(state->fb->obj[0]);
  142. struct virtio_gpu_object_array *objs;
  143. uint32_t w = rect->x2 - rect->x1;
  144. uint32_t h = rect->y2 - rect->y1;
  145. uint32_t x = rect->x1;
  146. uint32_t y = rect->y1;
  147. uint32_t off = x * state->fb->format->cpp[0] +
  148. y * state->fb->pitches[0];
  149. objs = virtio_gpu_array_alloc(1);
  150. if (!objs)
  151. return;
  152. virtio_gpu_array_add_obj(objs, &bo->base.base);
  153. virtio_gpu_cmd_transfer_to_host_2d(vgdev, off, w, h, x, y,
  154. objs, NULL);
  155. }
  156. /* For drm_panic */
  157. static void virtio_gpu_panic_resource_flush(struct drm_plane *plane,
  158. uint32_t x, uint32_t y,
  159. uint32_t width, uint32_t height)
  160. {
  161. struct drm_device *dev = plane->dev;
  162. struct virtio_gpu_device *vgdev = dev->dev_private;
  163. struct virtio_gpu_framebuffer *vgfb;
  164. struct virtio_gpu_object *bo;
  165. vgfb = to_virtio_gpu_framebuffer(plane->state->fb);
  166. bo = gem_to_virtio_gpu_obj(vgfb->base.obj[0]);
  167. virtio_gpu_panic_cmd_resource_flush(vgdev, bo->hw_res_handle, x, y,
  168. width, height);
  169. virtio_gpu_panic_notify(vgdev);
  170. }
  171. static void virtio_gpu_resource_flush(struct drm_plane *plane,
  172. uint32_t x, uint32_t y,
  173. uint32_t width, uint32_t height)
  174. {
  175. struct drm_device *dev = plane->dev;
  176. struct virtio_gpu_device *vgdev = dev->dev_private;
  177. struct virtio_gpu_framebuffer *vgfb;
  178. struct virtio_gpu_plane_state *vgplane_st;
  179. struct virtio_gpu_object *bo;
  180. vgfb = to_virtio_gpu_framebuffer(plane->state->fb);
  181. vgplane_st = to_virtio_gpu_plane_state(plane->state);
  182. bo = gem_to_virtio_gpu_obj(vgfb->base.obj[0]);
  183. if (vgplane_st->fence) {
  184. struct virtio_gpu_object_array *objs;
  185. objs = virtio_gpu_array_alloc(1);
  186. if (!objs)
  187. return;
  188. virtio_gpu_array_add_obj(objs, vgfb->base.obj[0]);
  189. virtio_gpu_array_lock_resv(objs);
  190. virtio_gpu_cmd_resource_flush(vgdev, bo->hw_res_handle, x, y,
  191. width, height, objs,
  192. vgplane_st->fence);
  193. virtio_gpu_notify(vgdev);
  194. dma_fence_wait_timeout(&vgplane_st->fence->f, true,
  195. msecs_to_jiffies(50));
  196. } else {
  197. virtio_gpu_cmd_resource_flush(vgdev, bo->hw_res_handle, x, y,
  198. width, height, NULL, NULL);
  199. virtio_gpu_notify(vgdev);
  200. }
  201. }
  202. static void virtio_gpu_primary_plane_update(struct drm_plane *plane,
  203. struct drm_atomic_state *state)
  204. {
  205. struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state,
  206. plane);
  207. struct drm_device *dev = plane->dev;
  208. struct virtio_gpu_device *vgdev = dev->dev_private;
  209. struct virtio_gpu_output *output = NULL;
  210. struct virtio_gpu_object *bo;
  211. struct drm_rect rect;
  212. if (plane->state->crtc)
  213. output = drm_crtc_to_virtio_gpu_output(plane->state->crtc);
  214. if (old_state->crtc)
  215. output = drm_crtc_to_virtio_gpu_output(old_state->crtc);
  216. if (WARN_ON(!output))
  217. return;
  218. if (!plane->state->fb || !output->crtc.state->active) {
  219. DRM_DEBUG("nofb\n");
  220. virtio_gpu_cmd_set_scanout(vgdev, output->index, 0,
  221. plane->state->src_w >> 16,
  222. plane->state->src_h >> 16,
  223. 0, 0);
  224. virtio_gpu_notify(vgdev);
  225. return;
  226. }
  227. if (!drm_atomic_helper_damage_merged(old_state, plane->state, &rect))
  228. return;
  229. bo = gem_to_virtio_gpu_obj(plane->state->fb->obj[0]);
  230. if (bo->dumb)
  231. virtio_gpu_update_dumb_bo(vgdev, plane->state, &rect);
  232. if (plane->state->fb != old_state->fb ||
  233. plane->state->src_w != old_state->src_w ||
  234. plane->state->src_h != old_state->src_h ||
  235. plane->state->src_x != old_state->src_x ||
  236. plane->state->src_y != old_state->src_y ||
  237. output->needs_modeset) {
  238. output->needs_modeset = false;
  239. DRM_DEBUG("handle 0x%x, crtc %dx%d+%d+%d, src %dx%d+%d+%d\n",
  240. bo->hw_res_handle,
  241. plane->state->crtc_w, plane->state->crtc_h,
  242. plane->state->crtc_x, plane->state->crtc_y,
  243. plane->state->src_w >> 16,
  244. plane->state->src_h >> 16,
  245. plane->state->src_x >> 16,
  246. plane->state->src_y >> 16);
  247. if (bo->host3d_blob || bo->guest_blob) {
  248. virtio_gpu_cmd_set_scanout_blob
  249. (vgdev, output->index, bo,
  250. plane->state->fb,
  251. plane->state->src_w >> 16,
  252. plane->state->src_h >> 16,
  253. plane->state->src_x >> 16,
  254. plane->state->src_y >> 16);
  255. } else {
  256. virtio_gpu_cmd_set_scanout(vgdev, output->index,
  257. bo->hw_res_handle,
  258. plane->state->src_w >> 16,
  259. plane->state->src_h >> 16,
  260. plane->state->src_x >> 16,
  261. plane->state->src_y >> 16);
  262. }
  263. }
  264. virtio_gpu_resource_flush(plane,
  265. rect.x1,
  266. rect.y1,
  267. rect.x2 - rect.x1,
  268. rect.y2 - rect.y1);
  269. }
  270. static int virtio_gpu_prepare_imported_obj(struct drm_plane *plane,
  271. struct drm_plane_state *new_state,
  272. struct drm_gem_object *obj)
  273. {
  274. struct virtio_gpu_device *vgdev = plane->dev->dev_private;
  275. struct virtio_gpu_object *bo = gem_to_virtio_gpu_obj(obj);
  276. struct dma_buf_attachment *attach = obj->import_attach;
  277. struct dma_resv *resv = attach->dmabuf->resv;
  278. struct virtio_gpu_mem_entry *ents = NULL;
  279. unsigned int nents;
  280. int ret;
  281. dma_resv_lock(resv, NULL);
  282. ret = dma_buf_pin(attach);
  283. if (ret) {
  284. dma_resv_unlock(resv);
  285. return ret;
  286. }
  287. if (!bo->sgt) {
  288. ret = virtgpu_dma_buf_import_sgt(&ents, &nents,
  289. bo, attach);
  290. if (ret)
  291. goto err;
  292. virtio_gpu_object_attach(vgdev, bo, ents, nents);
  293. }
  294. dma_resv_unlock(resv);
  295. return 0;
  296. err:
  297. dma_buf_unpin(attach);
  298. dma_resv_unlock(resv);
  299. return ret;
  300. }
  301. static int virtio_gpu_plane_prepare_fb(struct drm_plane *plane,
  302. struct drm_plane_state *new_state)
  303. {
  304. struct drm_device *dev = plane->dev;
  305. struct virtio_gpu_device *vgdev = dev->dev_private;
  306. struct virtio_gpu_framebuffer *vgfb;
  307. struct virtio_gpu_plane_state *vgplane_st;
  308. struct virtio_gpu_object *bo;
  309. struct drm_gem_object *obj;
  310. int ret;
  311. if (!new_state->fb)
  312. return 0;
  313. vgfb = to_virtio_gpu_framebuffer(new_state->fb);
  314. vgplane_st = to_virtio_gpu_plane_state(new_state);
  315. bo = gem_to_virtio_gpu_obj(vgfb->base.obj[0]);
  316. drm_gem_plane_helper_prepare_fb(plane, new_state);
  317. if (!bo || (plane->type == DRM_PLANE_TYPE_PRIMARY && !bo->guest_blob))
  318. return 0;
  319. obj = new_state->fb->obj[0];
  320. if (bo->dumb || drm_gem_is_imported(obj)) {
  321. vgplane_st->fence = virtio_gpu_fence_alloc(vgdev,
  322. vgdev->fence_drv.context,
  323. 0);
  324. if (!vgplane_st->fence)
  325. return -ENOMEM;
  326. }
  327. if (drm_gem_is_imported(obj)) {
  328. ret = virtio_gpu_prepare_imported_obj(plane, new_state, obj);
  329. if (ret)
  330. goto err_fence;
  331. }
  332. return 0;
  333. err_fence:
  334. if (vgplane_st->fence) {
  335. dma_fence_put(&vgplane_st->fence->f);
  336. vgplane_st->fence = NULL;
  337. }
  338. return ret;
  339. }
  340. static void virtio_gpu_cleanup_imported_obj(struct drm_gem_object *obj)
  341. {
  342. struct dma_buf_attachment *attach = obj->import_attach;
  343. struct dma_resv *resv = attach->dmabuf->resv;
  344. dma_resv_lock(resv, NULL);
  345. dma_buf_unpin(attach);
  346. dma_resv_unlock(resv);
  347. }
  348. static void virtio_gpu_plane_cleanup_fb(struct drm_plane *plane,
  349. struct drm_plane_state *state)
  350. {
  351. struct virtio_gpu_plane_state *vgplane_st;
  352. struct drm_gem_object *obj;
  353. if (!state->fb)
  354. return;
  355. vgplane_st = to_virtio_gpu_plane_state(state);
  356. if (vgplane_st->fence) {
  357. dma_fence_put(&vgplane_st->fence->f);
  358. vgplane_st->fence = NULL;
  359. }
  360. obj = state->fb->obj[0];
  361. if (drm_gem_is_imported(obj))
  362. virtio_gpu_cleanup_imported_obj(obj);
  363. }
  364. static void virtio_gpu_cursor_plane_update(struct drm_plane *plane,
  365. struct drm_atomic_state *state)
  366. {
  367. struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state,
  368. plane);
  369. struct drm_device *dev = plane->dev;
  370. struct virtio_gpu_device *vgdev = dev->dev_private;
  371. struct virtio_gpu_output *output = NULL;
  372. struct virtio_gpu_framebuffer *vgfb;
  373. struct virtio_gpu_plane_state *vgplane_st;
  374. struct virtio_gpu_object *bo = NULL;
  375. uint32_t handle;
  376. if (plane->state->crtc)
  377. output = drm_crtc_to_virtio_gpu_output(plane->state->crtc);
  378. if (old_state->crtc)
  379. output = drm_crtc_to_virtio_gpu_output(old_state->crtc);
  380. if (WARN_ON(!output))
  381. return;
  382. if (plane->state->fb) {
  383. vgfb = to_virtio_gpu_framebuffer(plane->state->fb);
  384. vgplane_st = to_virtio_gpu_plane_state(plane->state);
  385. bo = gem_to_virtio_gpu_obj(vgfb->base.obj[0]);
  386. handle = bo->hw_res_handle;
  387. } else {
  388. handle = 0;
  389. }
  390. if (bo && bo->dumb && (plane->state->fb != old_state->fb)) {
  391. /* new cursor -- update & wait */
  392. struct virtio_gpu_object_array *objs;
  393. objs = virtio_gpu_array_alloc(1);
  394. if (!objs)
  395. return;
  396. virtio_gpu_array_add_obj(objs, vgfb->base.obj[0]);
  397. virtio_gpu_array_lock_resv(objs);
  398. virtio_gpu_cmd_transfer_to_host_2d
  399. (vgdev, 0,
  400. plane->state->crtc_w,
  401. plane->state->crtc_h,
  402. 0, 0, objs, vgplane_st->fence);
  403. virtio_gpu_notify(vgdev);
  404. dma_fence_wait(&vgplane_st->fence->f, true);
  405. }
  406. if (plane->state->fb != old_state->fb) {
  407. DRM_DEBUG("update, handle %d, pos +%d+%d, hot %d,%d\n", handle,
  408. plane->state->crtc_x,
  409. plane->state->crtc_y,
  410. plane->state->hotspot_x,
  411. plane->state->hotspot_y);
  412. output->cursor.hdr.type =
  413. cpu_to_le32(VIRTIO_GPU_CMD_UPDATE_CURSOR);
  414. output->cursor.resource_id = cpu_to_le32(handle);
  415. if (plane->state->fb) {
  416. output->cursor.hot_x =
  417. cpu_to_le32(plane->state->hotspot_x);
  418. output->cursor.hot_y =
  419. cpu_to_le32(plane->state->hotspot_y);
  420. } else {
  421. output->cursor.hot_x = cpu_to_le32(0);
  422. output->cursor.hot_y = cpu_to_le32(0);
  423. }
  424. } else {
  425. DRM_DEBUG("move +%d+%d\n",
  426. plane->state->crtc_x,
  427. plane->state->crtc_y);
  428. output->cursor.hdr.type =
  429. cpu_to_le32(VIRTIO_GPU_CMD_MOVE_CURSOR);
  430. }
  431. output->cursor.pos.x = cpu_to_le32(plane->state->crtc_x);
  432. output->cursor.pos.y = cpu_to_le32(plane->state->crtc_y);
  433. virtio_gpu_cursor_ping(vgdev, output);
  434. }
  435. static int virtio_drm_get_scanout_buffer(struct drm_plane *plane,
  436. struct drm_scanout_buffer *sb)
  437. {
  438. struct virtio_gpu_object *bo;
  439. if (!plane->state || !plane->state->fb || !plane->state->visible)
  440. return -ENODEV;
  441. bo = gem_to_virtio_gpu_obj(plane->state->fb->obj[0]);
  442. if (virtio_gpu_is_vram(bo) || drm_gem_is_imported(&bo->base.base))
  443. return -ENODEV;
  444. if (bo->base.vaddr) {
  445. iosys_map_set_vaddr(&sb->map[0], bo->base.vaddr);
  446. } else {
  447. struct drm_gem_shmem_object *shmem = &bo->base;
  448. if (!shmem->pages)
  449. return -ENODEV;
  450. /* map scanout buffer later */
  451. sb->pages = shmem->pages;
  452. }
  453. sb->format = plane->state->fb->format;
  454. sb->height = plane->state->fb->height;
  455. sb->width = plane->state->fb->width;
  456. sb->pitch[0] = plane->state->fb->pitches[0];
  457. return 0;
  458. }
  459. static void virtio_panic_flush(struct drm_plane *plane)
  460. {
  461. struct virtio_gpu_object *bo;
  462. struct drm_device *dev = plane->dev;
  463. struct virtio_gpu_device *vgdev = dev->dev_private;
  464. struct drm_rect rect;
  465. rect.x1 = 0;
  466. rect.y1 = 0;
  467. rect.x2 = plane->state->fb->width;
  468. rect.y2 = plane->state->fb->height;
  469. bo = gem_to_virtio_gpu_obj(plane->state->fb->obj[0]);
  470. if (bo->dumb) {
  471. if (virtio_gpu_panic_update_dumb_bo(vgdev, plane->state,
  472. &rect))
  473. return;
  474. }
  475. virtio_gpu_panic_resource_flush(plane,
  476. plane->state->src_x >> 16,
  477. plane->state->src_y >> 16,
  478. plane->state->src_w >> 16,
  479. plane->state->src_h >> 16);
  480. }
  481. static const struct drm_plane_helper_funcs virtio_gpu_primary_helper_funcs = {
  482. .prepare_fb = virtio_gpu_plane_prepare_fb,
  483. .cleanup_fb = virtio_gpu_plane_cleanup_fb,
  484. .atomic_check = virtio_gpu_plane_atomic_check,
  485. .atomic_update = virtio_gpu_primary_plane_update,
  486. .get_scanout_buffer = virtio_drm_get_scanout_buffer,
  487. .panic_flush = virtio_panic_flush,
  488. };
  489. static const struct drm_plane_helper_funcs virtio_gpu_cursor_helper_funcs = {
  490. .prepare_fb = virtio_gpu_plane_prepare_fb,
  491. .cleanup_fb = virtio_gpu_plane_cleanup_fb,
  492. .atomic_check = virtio_gpu_plane_atomic_check,
  493. .atomic_update = virtio_gpu_cursor_plane_update,
  494. };
  495. struct drm_plane *virtio_gpu_plane_init(struct virtio_gpu_device *vgdev,
  496. enum drm_plane_type type,
  497. int index)
  498. {
  499. struct drm_device *dev = vgdev->ddev;
  500. const struct drm_plane_helper_funcs *funcs;
  501. struct drm_plane *plane;
  502. const uint32_t *formats;
  503. int nformats;
  504. if (type == DRM_PLANE_TYPE_CURSOR) {
  505. formats = virtio_gpu_cursor_formats;
  506. nformats = ARRAY_SIZE(virtio_gpu_cursor_formats);
  507. funcs = &virtio_gpu_cursor_helper_funcs;
  508. } else {
  509. formats = virtio_gpu_formats;
  510. nformats = ARRAY_SIZE(virtio_gpu_formats);
  511. funcs = &virtio_gpu_primary_helper_funcs;
  512. }
  513. plane = drmm_universal_plane_alloc(dev, struct drm_plane, dev,
  514. 1 << index, &virtio_gpu_plane_funcs,
  515. formats, nformats, NULL, type, NULL);
  516. if (IS_ERR(plane))
  517. return plane;
  518. drm_plane_helper_add(plane, funcs);
  519. if (type == DRM_PLANE_TYPE_PRIMARY)
  520. drm_plane_enable_fb_damage_clips(plane);
  521. return plane;
  522. }