summaryrefslogtreecommitdiff
path: root/libweston
diff options
context:
space:
mode:
authorDaniel Stone <daniels@collabora.com>2021-11-18 16:01:03 +0000
committerDaniel Stone <daniels@collabora.com>2021-12-08 13:38:18 +0000
commit7d27df4c4c6a6cf04195480d11764c6224ce0c32 (patch)
tree0301c42dbeb66d4fe6d75d9ac379fb3802238e3a /libweston
parent2ecc38b04296e5cbbb0add0d3ea5b6e9d69e05f7 (diff)
backend-drm: Cache drm_fb for each weston_buffer
When we first create a drm_fb from a weston_buffer, cache it and keep it alive as long as the buffer lives. This allows us to reuse the gbm_bo and kernel-side DRM framebuffer, rather than constantly creating and destroying them at every repaint. The overhead of doing so (e.g. MMU updates) can be significant on some platforms. Signed-off-by: Daniel Stone <daniels@collabora.com>
Diffstat (limited to 'libweston')
-rw-r--r--libweston/backend-drm/drm-internal.h6
-rw-r--r--libweston/backend-drm/fb.c47
2 files changed, 47 insertions, 6 deletions
diff --git a/libweston/backend-drm/drm-internal.h b/libweston/backend-drm/drm-internal.h
index 9cd80d66..73859f24 100644
--- a/libweston/backend-drm/drm-internal.h
+++ b/libweston/backend-drm/drm-internal.h
@@ -349,6 +349,12 @@ struct drm_fb {
void *map;
};
+struct drm_buffer_fb {
+ struct drm_fb *fb;
+ enum try_view_on_plane_failure_reasons failure_reasons;
+ struct wl_listener buffer_destroy_listener;
+};
+
struct drm_edid {
char eisa_id[13];
char monitor_name[13];
diff --git a/libweston/backend-drm/fb.c b/libweston/backend-drm/fb.c
index dd1cfb06..cc994929 100644
--- a/libweston/backend-drm/fb.c
+++ b/libweston/backend-drm/fb.c
@@ -461,6 +461,21 @@ drm_can_scanout_dmabuf(struct weston_compositor *ec,
return ret;
}
+static void
+drm_fb_handle_buffer_destroy(struct wl_listener *listener, void *data)
+{
+ struct drm_buffer_fb *buf_fb =
+ container_of(listener, struct drm_buffer_fb, buffer_destroy_listener);
+
+ if (buf_fb->fb) {
+ assert(buf_fb->fb->type == BUFFER_CLIENT ||
+ buf_fb->fb->type == BUFFER_DMABUF);
+ drm_fb_unref(buf_fb->fb);
+ }
+
+ free(buf_fb);
+}
+
struct drm_fb *
drm_fb_get_from_view(struct drm_output_state *state, struct weston_view *ev,
uint32_t *try_view_on_plane_failure_reasons)
@@ -468,6 +483,7 @@ drm_fb_get_from_view(struct drm_output_state *state, struct weston_view *ev,
struct drm_output *output = state->output;
struct drm_backend *b = to_drm_backend(output->base.compositor);
struct weston_buffer *buffer = ev->surface->buffer_ref.buffer;
+ struct drm_buffer_fb *buf_fb;
bool is_opaque = weston_view_is_opaque(ev, &ev->transform.boundingbox);
struct linux_dmabuf_buffer *dmabuf;
struct drm_fb *fb;
@@ -485,36 +501,55 @@ drm_fb_get_from_view(struct drm_output_state *state, struct weston_view *ev,
if (!buffer)
return NULL;
+ if (buffer->backend_private) {
+ buf_fb = buffer->backend_private;
+ *try_view_on_plane_failure_reasons |= buf_fb->failure_reasons;
+ return buf_fb->fb ? drm_fb_ref(buf_fb->fb) : NULL;
+ }
+
+ buf_fb = zalloc(sizeof(*buf_fb));
+ buffer->backend_private = buf_fb;
+ buf_fb->buffer_destroy_listener.notify = drm_fb_handle_buffer_destroy;
+ wl_signal_add(&buffer->destroy_signal, &buf_fb->buffer_destroy_listener);
+
if (wl_shm_buffer_get(buffer->resource))
- return NULL;
+ goto unsuitable;
/* GBM is used for dmabuf import as well as from client wl_buffer. */
if (!b->gbm)
- return NULL;
+ goto unsuitable;
dmabuf = linux_dmabuf_buffer_get(buffer->resource);
if (dmabuf) {
fb = drm_fb_get_from_dmabuf(dmabuf, b, is_opaque,
- try_view_on_plane_failure_reasons);
+ &buf_fb->failure_reasons);
if (!fb)
- return NULL;
+ goto unsuitable;
} else {
struct gbm_bo *bo;
bo = gbm_bo_import(b->gbm, GBM_BO_IMPORT_WL_BUFFER,
buffer->resource, GBM_BO_USE_SCANOUT);
if (!bo)
- return NULL;
+ goto unsuitable;
fb = drm_fb_get_from_bo(bo, b, is_opaque, BUFFER_CLIENT);
if (!fb) {
gbm_bo_destroy(bo);
- return NULL;
+ goto unsuitable;
}
}
+ /* The caller holds its own ref to the drm_fb, so when creating a new
+ * drm_fb we take an additional ref for the weston_buffer's cache. */
+ buf_fb->fb = drm_fb_ref(fb);
+
drm_debug(b, "\t\t\t[view] view %p format: %s\n",
ev, fb->format->drm_format_name);
return fb;
+
+unsuitable:
+ *try_view_on_plane_failure_reasons |= buf_fb->failure_reasons;
+ return NULL;
}
#endif