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>
This commit is contained in:
parent
2ecc38b042
commit
7d27df4c4c
|
@ -1198,6 +1198,7 @@ struct weston_buffer {
|
|||
int32_t width, height;
|
||||
uint32_t busy_count;
|
||||
int y_inverted;
|
||||
void *backend_private;
|
||||
};
|
||||
|
||||
struct weston_buffer_reference {
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue