aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--backend/drm/backend.c6
-rw-r--r--backend/drm/renderer.c59
-rw-r--r--include/backend/drm/drm.h1
-rw-r--r--include/backend/drm/renderer.h5
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);