diff options
Diffstat (limited to 'backend/drm')
-rw-r--r-- | backend/drm/backend.c | 6 | ||||
-rw-r--r-- | backend/drm/renderer.c | 59 |
2 files changed, 50 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); |