From: Tomohito Esaki <e...@igel.co.jp> Rather than relying on GBM for dmabuf import, perform the import directly through libdrm. This creates a specialised drm_fb type for dmabufs.
This also supports multi-planar dmabuf. [daniels: Rebased on top of recent drm_fb/drm_plane_state/etc.] Signed-off-by: Daniel Stone <dani...@collabora.com> Differential Revision: https://phabricator.freedesktop.org/D1525 --- configure.ac | 3 -- libweston/compositor-drm.c | 131 ++++++++++++++++++++++++++++++++------------- 2 files changed, 95 insertions(+), 39 deletions(-) diff --git a/configure.ac b/configure.ac index 8fe48b6..54c6fcd 100644 --- a/configure.ac +++ b/configure.ac @@ -207,9 +207,6 @@ if test x$enable_drm_compositor = xyes; then PKG_CHECK_MODULES(DRM_COMPOSITOR_ATOMIC, [libdrm >= 2.4.62], [AC_DEFINE([HAVE_DRM_ATOMIC], 1, [libdrm supports atomic API])], [AC_MSG_WARN([libdrm does not support atomic modesetting, will omit that capability])]) - PKG_CHECK_MODULES(DRM_COMPOSITOR_GBM, [gbm >= 10.2], - [AC_DEFINE([HAVE_GBM_FD_IMPORT], 1, [gbm supports dmabuf import])], - [AC_MSG_WARN([gbm does not support dmabuf import, will omit that capability])]) fi diff --git a/libweston/compositor-drm.c b/libweston/compositor-drm.c index a2d4c8c..e6f94af 100644 --- a/libweston/compositor-drm.c +++ b/libweston/compositor-drm.c @@ -233,6 +233,7 @@ struct drm_mode { enum drm_fb_type { BUFFER_INVALID = 0, /**< never used */ BUFFER_CLIENT, /**< directly sourced from client */ + BUFFER_DMABUF, /**< imported from linux_dmabuf client */ BUFFER_PIXMAN_DUMB, /**< internal Pixman rendering */ BUFFER_GBM_SURFACE, /**< internal EGL rendering */ BUFFER_CURSOR, /**< internal cursor buffer */ @@ -986,6 +987,82 @@ drm_fb_ref(struct drm_fb *fb) return fb; } +static void +drm_fb_destroy_dmabuf(struct drm_fb *fb) +{ + unsigned int i; + + /* Unlike GBM buffers, where destroying the BO also closes the GEM + * handle, we fully control the handle lifetime for dmabuf buffers. */ + for (i = 0; i < ARRAY_LENGTH(fb->handles); i++) { + struct drm_gem_close gem_close = { .handle = fb->handles[i] }; + if (!gem_close.handle) + continue; + (void) drmIoctl(fb->fd, DRM_IOCTL_GEM_CLOSE, &gem_close); + } + + drm_fb_destroy(fb); +} + +static struct drm_fb * +drm_fb_get_from_dmabuf(struct linux_dmabuf_buffer *dmabuf, + struct drm_backend *backend, bool is_opaque) +{ + struct drm_fb *fb; + int i, ret; + + fb = zalloc(sizeof *fb); + if (fb == NULL) + return NULL; + + fb->refcnt = 1; + fb->type = BUFFER_DMABUF; + + fb->width = dmabuf->attributes.width; + fb->height = dmabuf->attributes.height; + memcpy(fb->strides, dmabuf->attributes.stride, sizeof(fb->strides)); + memcpy(fb->offsets, dmabuf->attributes.offset, sizeof(fb->offsets)); + fb->format = pixel_format_get_info(dmabuf->attributes.format); + fb->size = 0; + fb->fd = backend->drm.fd; + + if (!fb->format) { + weston_log("couldn't look up format info for 0x%lx\n", + (unsigned long) fb->format); + goto err_free; + } + + if (is_opaque) + fb->format = pixel_format_get_opaque_substitute(fb->format); + + if (backend->min_width > fb->width || + fb->width > backend->max_width || + backend->min_height > fb->height || + fb->height > backend->max_height) { + weston_log("bo geometry out of bounds\n"); + goto err_free; + } + + for (i = 0; i < dmabuf->attributes.n_planes; i++) { + ret = drmPrimeFDToHandle(backend->drm.fd, + dmabuf->attributes.fd[i], + &fb->handles[i]); + if (ret) + goto err_free; + } + + if (drm_fb_addfb(fb) != 0) { + weston_log("failed to create kms fb: %m\n"); + goto err_free; + } + + return fb; + +err_free: + drm_fb_destroy_dmabuf(fb); + return NULL; +} + static struct drm_fb * drm_fb_get_from_bo(struct gbm_bo *bo, struct drm_backend *backend, bool is_opaque, enum drm_fb_type type) @@ -1070,6 +1147,9 @@ drm_fb_unref(struct drm_fb *fb) case BUFFER_GBM_SURFACE: gbm_surface_release_buffer(fb->gbm_surface, fb->bo); break; + case BUFFER_DMABUF: + drm_fb_destroy_dmabuf(fb); + break; default: assert(NULL); break; @@ -1300,9 +1380,9 @@ 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; + bool is_opaque = drm_view_is_opaque(ev); struct linux_dmabuf_buffer *dmabuf; struct drm_fb *fb; - struct gbm_bo *bo; /* Don't import buffers which span multiple outputs. */ if (ev->output_mask != (1u << output->base.id)) @@ -1317,48 +1397,27 @@ drm_fb_get_from_view(struct drm_output_state *state, struct weston_view *ev) if (wl_shm_buffer_get(buffer->resource)) return NULL; - if (!b->gbm) - return NULL; - dmabuf = linux_dmabuf_buffer_get(buffer->resource); if (dmabuf) { -#ifdef HAVE_GBM_FD_IMPORT - /* XXX: TODO: - * - * Use AddFB2 directly, do not go via GBM. - * Add support for multiplanar formats. - * Both require refactoring in the DRM-backend to - * support a mix of gbm_bos and drmfbs. - */ - struct gbm_import_fd_data gbm_dmabuf = { - .fd = dmabuf->attributes.fd[0], - .width = dmabuf->attributes.width, - .height = dmabuf->attributes.height, - .stride = dmabuf->attributes.stride[0], - .format = dmabuf->attributes.format - }; - - if (dmabuf->attributes.n_planes != 1 || - dmabuf->attributes.offset[0]) + fb = drm_fb_get_from_dmabuf(dmabuf, b, is_opaque); + if (!fb) return NULL; - - bo = gbm_bo_import(b->gbm, GBM_BO_IMPORT_FD, &gbm_dmabuf, - GBM_BO_USE_SCANOUT); -#else - return NULL; -#endif } else { + struct gbm_bo *bo; + + if (!b->gbm) + return NULL; + bo = gbm_bo_import(b->gbm, GBM_BO_IMPORT_WL_BUFFER, buffer->resource, GBM_BO_USE_SCANOUT); - } - - if (!bo) - return NULL; + if (!bo) + return NULL; - fb = drm_fb_get_from_bo(bo, b, drm_view_is_opaque(ev), BUFFER_CLIENT); - if (!fb) { - gbm_bo_destroy(bo); - return NULL; + fb = drm_fb_get_from_bo(bo, b, is_opaque, BUFFER_CLIENT); + if (!fb) { + gbm_bo_destroy(bo); + return NULL; + } } drm_fb_set_buffer(fb, buffer); -- 2.9.3 _______________________________________________ wayland-devel mailing list wayland-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/wayland-devel