From d9bbc416a62c2d280e6921da6b25128a1b3a9e22 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 22 Dec 2020 18:42:59 +0100 Subject: [PATCH] backend/drm: re-use FBs Instead of importing buffers to GBM and KMS at each frame, cache them and re-use them while the wlr_buffer is alive. This is the same as [1] and [2] but for the DRM backend. [1]: https://github.com/swaywm/wlroots/pull/2538 [2]: https://github.com/swaywm/wlroots/pull/2539 --- backend/drm/backend.c | 6 ++++ backend/drm/renderer.c | 59 +++++++++++++++++++++++++--------- include/backend/drm/drm.h | 1 + include/backend/drm/renderer.h | 5 +++ 4 files changed, 56 insertions(+), 15 deletions(-) diff --git a/backend/drm/backend.c b/backend/drm/backend.c index 68087f63..bd68c3e2 100644 --- a/backend/drm/backend.c +++ b/backend/drm/backend.c @@ -42,6 +42,11 @@ static void backend_destroy(struct wlr_backend *backend) { wlr_signal_emit_safe(&backend->events.destroy, backend); + struct wlr_drm_fb *fb, *fb_tmp; + wl_list_for_each_safe(fb, fb_tmp, &drm->fbs, link) { + drm_fb_destroy(fb); + } + wl_list_remove(&drm->display_destroy.link); wl_list_remove(&drm->session_destroy.link); wl_list_remove(&drm->session_active.link); @@ -147,6 +152,7 @@ struct wlr_backend *wlr_drm_backend_create(struct wl_display *display, wlr_backend_init(&drm->backend, &backend_impl); drm->session = session; + wl_list_init(&drm->fbs); wl_list_init(&drm->outputs); drm->dev = dev; diff --git a/backend/drm/renderer.c b/backend/drm/renderer.c index 10280660..2997687f 100644 --- a/backend/drm/renderer.c +++ b/backend/drm/renderer.c @@ -297,15 +297,7 @@ void drm_fb_clear(struct wlr_drm_fb **fb_ptr) { } struct wlr_drm_fb *fb = *fb_ptr; - - struct gbm_device *gbm = gbm_bo_get_device(fb->bo); - if (drmModeRmFB(gbm_device_get_fd(gbm), fb->id) != 0) { - wlr_log(WLR_ERROR, "drmModeRmFB failed"); - } - - gbm_bo_destroy(fb->bo); - wlr_buffer_unlock(fb->wlr_buf); - free(fb); + wlr_buffer_unlock(fb->wlr_buf); // may destroy the buffer *fb_ptr = NULL; } @@ -362,6 +354,12 @@ static struct gbm_bo *get_bo_for_dmabuf(struct gbm_device *gbm, } } +static void drm_fb_handle_wlr_buf_destroy(struct wl_listener *listener, + void *data) { + struct wlr_drm_fb *fb = wl_container_of(listener, fb, wlr_buf_destroy); + drm_fb_destroy(fb); +} + 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)); @@ -369,8 +367,6 @@ static struct wlr_drm_fb *drm_fb_create(struct wlr_drm_backend *drm, return NULL; } - fb->wlr_buf = wlr_buffer_lock(buf); - struct wlr_dmabuf_attributes attribs; if (!wlr_buffer_get_dmabuf(buf, &attribs)) { wlr_log(WLR_ERROR, "Failed to get DMA-BUF from buffer"); @@ -403,16 +399,46 @@ static struct wlr_drm_fb *drm_fb_create(struct wlr_drm_backend *drm, goto error_get_fb_for_bo; } + fb->wlr_buf = buf; + + fb->wlr_buf_destroy.notify = drm_fb_handle_wlr_buf_destroy; + wl_signal_add(&buf->events.destroy, &fb->wlr_buf_destroy); + + wl_list_insert(&drm->fbs, &fb->link); + return fb; error_get_fb_for_bo: gbm_bo_destroy(fb->bo); error_get_dmabuf: - wlr_buffer_unlock(fb->wlr_buf); free(fb); return NULL; } +void drm_fb_destroy(struct wlr_drm_fb *fb) { + wl_list_remove(&fb->link); + wl_list_remove(&fb->wlr_buf_destroy.link); + + struct gbm_device *gbm = gbm_bo_get_device(fb->bo); + if (drmModeRmFB(gbm_device_get_fd(gbm), fb->id) != 0) { + wlr_log(WLR_ERROR, "drmModeRmFB failed"); + } + + gbm_bo_destroy(fb->bo); + free(fb); +} + +static struct wlr_drm_fb *drm_fb_get(struct wlr_drm_backend *drm, + struct wlr_buffer *local_buf) { + struct wlr_drm_fb *fb; + wl_list_for_each(fb, &drm->fbs, link) { + if (fb->wlr_buf == local_buf) { + return fb; + } + } + return NULL; +} + bool drm_fb_import(struct wlr_drm_fb **fb_ptr, struct wlr_drm_backend *drm, struct wlr_buffer *buf, struct wlr_drm_surface *mgpu, const struct wlr_drm_format_set *formats) { @@ -428,10 +454,13 @@ bool drm_fb_import(struct wlr_drm_fb **fb_ptr, struct wlr_drm_backend *drm, local_buf = wlr_buffer_lock(buf); } - struct wlr_drm_fb *fb = drm_fb_create(drm, local_buf, formats); - wlr_buffer_unlock(local_buf); + struct wlr_drm_fb *fb = drm_fb_get(drm, local_buf); if (!fb) { - return false; + fb = drm_fb_create(drm, local_buf, formats); + if (!fb) { + wlr_buffer_unlock(local_buf); + return false; + } } drm_fb_move(fb_ptr, &fb); diff --git a/include/backend/drm/drm.h b/include/backend/drm/drm.h index 23b06847..52aacf39 100644 --- a/include/backend/drm/drm.h +++ b/include/backend/drm/drm.h @@ -86,6 +86,7 @@ struct wlr_drm_backend { struct wl_listener session_active; struct wl_listener dev_change; + struct wl_list fbs; // wlr_drm_fb.link struct wl_list outputs; struct wlr_drm_renderer renderer; diff --git a/include/backend/drm/renderer.h b/include/backend/drm/renderer.h index 8316a070..fdc8a75d 100644 --- a/include/backend/drm/renderer.h +++ b/include/backend/drm/renderer.h @@ -31,8 +31,12 @@ struct wlr_drm_surface { struct wlr_drm_fb { struct wlr_buffer *wlr_buf; + struct wl_list link; // wlr_drm_backend.fbs + struct gbm_bo *bo; uint32_t id; + + struct wl_listener wlr_buf_destroy; }; bool init_drm_renderer(struct wlr_drm_backend *drm, @@ -47,6 +51,7 @@ bool drm_fb_lock_surface(struct wlr_drm_fb **fb, struct wlr_drm_backend *drm, bool drm_fb_import(struct wlr_drm_fb **fb, struct wlr_drm_backend *drm, struct wlr_buffer *buf, struct wlr_drm_surface *mgpu, const struct wlr_drm_format_set *formats); +void drm_fb_destroy(struct wlr_drm_fb *fb); void drm_fb_clear(struct wlr_drm_fb **fb); void drm_fb_move(struct wlr_drm_fb **new, struct wlr_drm_fb **old);