diff options
author | Simon Ser <contact@emersion.fr> | 2021-11-26 22:46:10 +0100 |
---|---|---|
committer | Simon Zeni <simon@bl4ckb0ne.ca> | 2021-11-29 14:32:29 +0000 |
commit | fbaefd90fc24f1c06be0d24cc3c4a01c71671157 (patch) | |
tree | 74299ce960f71244c908f01e2afdd71e9ce8a99a /backend/drm | |
parent | bff5b2c5597b30b90b201825b6c1c6537bb06d84 (diff) |
backend/drm: poison buffers which cannot be scanned out
Rather than repeatedly trying to import DMA-BUFs which cannot be
scanned out, mark the failed ones with a special "poison" marker.
Inspired from [1].
[1]: https://gitlab.freedesktop.org/wayland/weston/-/merge_requests/731
Diffstat (limited to 'backend/drm')
-rw-r--r-- | backend/drm/renderer.c | 53 |
1 files changed, 45 insertions, 8 deletions
diff --git a/backend/drm/renderer.c b/backend/drm/renderer.c index bfc94a24..815ba981 100644 --- a/backend/drm/renderer.c +++ b/backend/drm/renderer.c @@ -275,18 +275,54 @@ static void close_all_bo_handles(struct wlr_drm_backend *drm, } } -static struct wlr_drm_fb *drm_fb_create(struct wlr_drm_backend *drm, - struct wlr_buffer *buf, const struct wlr_drm_format_set *formats) { - struct wlr_drm_fb *fb = calloc(1, sizeof(*fb)); - if (!fb) { +static void drm_poisoned_fb_handle_destroy(struct wlr_addon *addon) { + wlr_addon_finish(addon); + free(addon); +} + +static const struct wlr_addon_interface poisoned_fb_addon_impl = { + .name = "wlr_drm_poisoned_fb", + .destroy = drm_poisoned_fb_handle_destroy, +}; + +static bool is_buffer_poisoned(struct wlr_drm_backend *drm, + struct wlr_buffer *buf) { + return wlr_addon_find(&buf->addons, drm, &poisoned_fb_addon_impl) != NULL; +} + +/** + * Mark the buffer as "poisoned", ie. it cannot be imported into KMS. This + * allows us to avoid repeatedly trying to import it when it's not + * scanout-capable. + */ +static void poison_buffer(struct wlr_drm_backend *drm, + struct wlr_buffer *buf) { + struct wlr_addon *addon = calloc(1, sizeof(*addon)); + if (addon == NULL) { wlr_log_errno(WLR_ERROR, "Allocation failed"); - return NULL; + return; } + wlr_addon_init(addon, &buf->addons, drm, &poisoned_fb_addon_impl); + wlr_log(WLR_DEBUG, "Poisoning buffer"); +} +static struct wlr_drm_fb *drm_fb_create(struct wlr_drm_backend *drm, + struct wlr_buffer *buf, const struct wlr_drm_format_set *formats) { struct wlr_dmabuf_attributes attribs; if (!wlr_buffer_get_dmabuf(buf, &attribs)) { wlr_log(WLR_DEBUG, "Failed to get DMA-BUF from buffer"); - goto error_get_dmabuf; + return NULL; + } + + if (is_buffer_poisoned(drm, buf)) { + wlr_log(WLR_DEBUG, "Buffer is poisoned"); + return NULL; + } + + struct wlr_drm_fb *fb = calloc(1, sizeof(*fb)); + if (!fb) { + wlr_log_errno(WLR_ERROR, "Allocation failed"); + return NULL; } if (formats && !wlr_drm_format_set_has(formats, attribs.format, @@ -302,7 +338,7 @@ static struct wlr_drm_fb *drm_fb_create(struct wlr_drm_backend *drm, wlr_log(WLR_DEBUG, "Buffer format 0x%"PRIX32" with modifier " "0x%"PRIX64" cannot be scanned out", attribs.format, attribs.modifier); - goto error_get_dmabuf; + goto error_fb; } } @@ -318,6 +354,7 @@ static struct wlr_drm_fb *drm_fb_create(struct wlr_drm_backend *drm, fb->id = get_fb_for_bo(drm, &attribs, handles); if (!fb->id) { wlr_log(WLR_DEBUG, "Failed to import BO in KMS"); + poison_buffer(drm, buf); goto error_bo_handle; } @@ -333,7 +370,7 @@ static struct wlr_drm_fb *drm_fb_create(struct wlr_drm_backend *drm, error_bo_handle: close_all_bo_handles(drm, handles); -error_get_dmabuf: +error_fb: free(fb); return NULL; } |