This new IOCTL allows callers to close a framebuffer without disabling planes or CRTCs. This takes inspiration from Rob Clark's unref_fb IOCTL [1] and DRM_MODE_FB_PERSIST [2]. User-space patch for wlroots available at [3]. IGT test available at [4]. v2: add an extra pad field just in case we want to extend this IOCTL in the future (Pekka, Sima). [1]: https://lore.kernel.org/dri-devel/20170509153654.23464-1-robdclark@gmail.com/ [2]: https://lore.kernel.org/dri-devel/20211006151921.312714-1-contact@emersion.fr/ [3]: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/4394 [4]: https://lists.freedesktop.org/archives/igt-dev/2023-October/063294.html
Unified · Split
| @@ -222,6 +222,8 @@ int drm_mode_addfb2_ioctl(struct drm_device *dev, · 221 unmodified lines | |||
| 222 | void *data, struct drm_file *file_priv); | 222 | void *data, struct drm_file *file_priv); |
| 223 | int drm_mode_rmfb_ioctl(struct drm_device *dev, | 223 | int drm_mode_rmfb_ioctl(struct drm_device *dev, |
| 224 | void *data, struct drm_file *file_priv); | 224 | void *data, struct drm_file *file_priv); |
| 225 | int drm_mode_closefb_ioctl(struct drm_device *dev, | ||
| 226 | void *data, struct drm_file *file_priv); | ||
| 225 | int drm_mode_getfb(struct drm_device *dev, | 227 | int drm_mode_getfb(struct drm_device *dev, |
| 226 | void *data, struct drm_file *file_priv); | 228 | void *data, struct drm_file *file_priv); |
| 227 | int drm_mode_getfb2_ioctl(struct drm_device *dev, | 229 | int drm_mode_getfb2_ioctl(struct drm_device *dev, |
| @@ -480,6 +480,28 @@ int drm_mode_rmfb_ioctl(struct drm_device *dev, · 479 unmodified lines | |||
| 480 | return drm_mode_rmfb(dev, *fb_id, file_priv); | 480 | return drm_mode_rmfb(dev, *fb_id, file_priv); |
| 481 | } | 481 | } |
| 482 | 482 | ||
| 483 | int drm_mode_closefb_ioctl(struct drm_device *dev, | ||
| 484 | void *data, struct drm_file *file_priv) | ||
| 485 | { | ||
| 486 | struct drm_mode_closefb *r = data; | ||
| 487 | struct drm_framebuffer *fb; | ||
| 488 | int ret; | ||
| 489 | |||
| 490 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) | ||
| 491 | return -EOPNOTSUPP; | ||
| 492 | |||
| 493 | if (r->pad) | ||
| 494 | return -EINVAL; | ||
| 495 | |||
| 496 | fb = drm_framebuffer_lookup(dev, file_priv, r->fb_id); | ||
| 497 | if (!fb) | ||
| 498 | return -ENOENT; | ||
| 499 | |||
| 500 | ret = drm_mode_closefb(fb, file_priv); | ||
| 501 | drm_framebuffer_put(fb); | ||
| 502 | return ret; | ||
| 503 | } | ||
| 504 | |||
| 483 | /** | 505 | /** |
| 484 | * drm_mode_getfb - get FB info | 506 | * drm_mode_getfb - get FB info |
| 485 | * @dev: drm device for the ioctl | 507 | * @dev: drm device for the ioctl |
| @@ -675,6 +675,7 @@ static const struct drm_ioctl_desc drm_ioctls[] = { · 674 unmodified lines | |||
| 675 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_ADDFB, drm_mode_addfb_ioctl, 0), | 675 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_ADDFB, drm_mode_addfb_ioctl, 0), |
| 676 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_ADDFB2, drm_mode_addfb2_ioctl, 0), | 676 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_ADDFB2, drm_mode_addfb2_ioctl, 0), |
| 677 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_RMFB, drm_mode_rmfb_ioctl, 0), | 677 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_RMFB, drm_mode_rmfb_ioctl, 0), |
| 678 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_CLOSEFB, drm_mode_closefb_ioctl, 0), | ||
| 678 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_PAGE_FLIP, drm_mode_page_flip_ioctl, DRM_MASTER), | 679 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_PAGE_FLIP, drm_mode_page_flip_ioctl, DRM_MASTER), |
| 679 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_DIRTYFB, drm_mode_dirtyfb_ioctl, DRM_MASTER), | 680 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_DIRTYFB, drm_mode_dirtyfb_ioctl, DRM_MASTER), |
| 680 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_CREATE_DUMB, drm_mode_create_dumb_ioctl, 0), | 681 | DRM_IOCTL_DEF(DRM_IOCTL_MODE_CREATE_DUMB, drm_mode_create_dumb_ioctl, 0), |
| @@ -1218,6 +1218,26 @@ extern "C" { · 1217 unmodified lines | |||
| 1218 | 1218 | ||
| 1219 | #define DRM_IOCTL_SYNCOBJ_EVENTFD DRM_IOWR(0xCF, struct drm_syncobj_eventfd) | 1219 | #define DRM_IOCTL_SYNCOBJ_EVENTFD DRM_IOWR(0xCF, struct drm_syncobj_eventfd) |
| 1220 | 1220 | ||
| 1221 | /** | ||
| 1222 | * DRM_IOCTL_MODE_CLOSEFB - Close a framebuffer. | ||
| 1223 | * | ||
| 1224 | * This closes a framebuffer previously added via ADDFB/ADDFB2. The IOCTL | ||
| 1225 | * argument is a framebuffer object ID. | ||
| 1226 | * | ||
| 1227 | * This IOCTL is similar to &DRM_IOCTL_MODE_RMFB, except it doesn't disable | ||
| 1228 | * planes and CRTCs. As long as the framebuffer is used by a plane, it's kept | ||
| 1229 | * alive. When the plane no longer uses the framebuffer (because the | ||
| 1230 | * framebuffer is replaced with another one, or the plane is disabled), the | ||
| 1231 | * framebuffer is cleaned up. | ||
| 1232 | * | ||
| 1233 | * This is useful to implement flicker-free transitions between two processes. | ||
| 1234 | * | ||
| 1235 | * Depending on the threat model, user-space may want to ensure that the | ||
| 1236 | * framebuffer doesn't expose any sensitive user information: closed | ||
| 1237 | * framebuffers attached to a plane can be read back by the next DRM master. | ||
| 1238 | */ | ||
| 1239 | #define DRM_IOCTL_MODE_CLOSEFB DRM_IOWR(0xD0, struct drm_mode_closefb) | ||
| 1240 | |||
| 1221 | /* | 1241 | /* |
| 1222 | * Device specific ioctls should only be in their respective headers | 1242 | * Device specific ioctls should only be in their respective headers |
| 1223 | * The device specific ioctl range is from 0x40 to 0x9f. | 1243 | * The device specific ioctl range is from 0x40 to 0x9f. |
| @@ -1323,6 +1323,16 @@ struct drm_mode_rect { · 1322 unmodified lines | |||
| 1323 | __s32 y2; | 1323 | __s32 y2; |
| 1324 | }; | 1324 | }; |
| 1325 | 1325 | ||
| 1326 | /** | ||
| 1327 | * struct drm_mode_closefb | ||
| 1328 | * @fb_id: Framebuffer ID. | ||
| 1329 | * @pad: Must be zero. | ||
| 1330 | */ | ||
| 1331 | struct drm_mode_closefb { | ||
| 1332 | __u32 fb_id; | ||
| 1333 | __u32 pad; | ||
| 1334 | }; | ||
| 1335 | |||
| 1326 | #if defined(__cplusplus) | 1336 | #if defined(__cplusplus) |
| 1327 | } | 1337 | } |
| 1328 | #endif | 1338 | #endif |