From e3010856c00b92ffb8722805101684826c3a7a1f Mon Sep 17 00:00:00 2001 From: Jeffy Chen Date: Fri, 3 Jul 2020 14:43:49 +0800 Subject: [PATCH 18/74] pixman-renderer: Support linux dmabuf NOTE: Only support contig dmabuf. Signed-off-by: Jeffy Chen --- libweston/pixman-renderer.c | 258 +++++++++++++++++++++++++++++++++++- 1 file changed, 253 insertions(+), 5 deletions(-) diff --git a/libweston/pixman-renderer.c b/libweston/pixman-renderer.c index d7182e7..d5c5422 100644 --- a/libweston/pixman-renderer.c +++ b/libweston/pixman-renderer.c @@ -37,8 +37,15 @@ #include "pixel-formats.h" #include "shared/helpers.h" +#include +#include +#include +#include #include +#include "linux-dmabuf.h" +#include "linux-dmabuf-unstable-v1-server-protocol.h" + struct pixman_output_state { void *shadow_buffer; pixman_image_t *shadow_image; @@ -66,6 +73,13 @@ struct pixman_renderer { struct weston_binding *debug_binding; struct wl_signal destroy_signal; + + struct weston_drm_format_array supported_formats; +}; + +struct dmabuf_data { + void *ptr; + size_t size; }; static inline struct pixman_output_state * @@ -353,7 +367,7 @@ repaint_region(struct weston_view *ev, struct weston_output *output, else filter = PIXMAN_FILTER_NEAREST; - if (ps->buffer_ref.buffer) + if (ps->buffer_ref.buffer && ps->buffer_ref.buffer->shm_buffer) wl_shm_buffer_begin_access(ps->buffer_ref.buffer->shm_buffer); if (ev->alpha < 1.0) { @@ -373,7 +387,7 @@ repaint_region(struct weston_view *ev, struct weston_output *output, if (mask_image) pixman_image_unref(mask_image); - if (ps->buffer_ref.buffer) + if (ps->buffer_ref.buffer && ps->buffer_ref.buffer->shm_buffer) wl_shm_buffer_end_access(ps->buffer_ref.buffer->shm_buffer); if (pr->repaint_debug) @@ -622,11 +636,88 @@ buffer_state_handle_buffer_destroy(struct wl_listener *listener, void *data) ps->buffer_destroy_listener.notify = NULL; } +static void +pixman_renderer_attach_dmabuf(struct weston_surface *es, + struct weston_buffer *buffer, + struct linux_dmabuf_buffer *dmabuf) +{ + struct pixman_surface_state *ps = get_surface_state(es); + struct dmabuf_attributes *attributes = &dmabuf->attributes; + struct dmabuf_data *data; + pixman_format_code_t pixman_format; + size_t vstride; + + data = linux_dmabuf_buffer_get_user_data(dmabuf); + if (!data || !data->ptr) { + weston_buffer_reference(&ps->buffer_ref, NULL); + weston_buffer_release_reference(&ps->buffer_release_ref, + NULL); + return; + } + + buffer->width = attributes->width; + buffer->height = attributes->height; + + if (attributes->n_planes == 1) + vstride = attributes->height; + else + vstride = (attributes->offset[1] - attributes->offset[0]) / + attributes->stride[0]; + + switch (attributes->format) { + case DRM_FORMAT_ARGB8888: + pixman_format = PIXMAN_a8r8g8b8; + break; + case DRM_FORMAT_XRGB8888: + pixman_format = PIXMAN_x8r8g8b8; + break; + case DRM_FORMAT_YUYV: + pixman_format = PIXMAN_yuy2; + break; + case DRM_FORMAT_YVU420: + pixman_format = PIXMAN_yv12; + break; +#ifdef HAVE_PIXMAN_I420 + case DRM_FORMAT_YUV420: + pixman_format = PIXMAN_i420; + break; +#endif +#ifdef HAVE_PIXMAN_NV12 + case DRM_FORMAT_NV12: + pixman_format = PIXMAN_nv12; + break; +#endif +#ifdef HAVE_PIXMAN_NV16 + case DRM_FORMAT_NV16: + pixman_format = PIXMAN_nv16; + break; +#endif + default: + weston_log("Unsupported dmabuf format\n"); + weston_buffer_reference(&ps->buffer_ref, NULL); + weston_buffer_release_reference(&ps->buffer_release_ref, + NULL); + return; + break; + } + + ps->image = pixman_image_create_bits(pixman_format, + buffer->width, vstride, + data->ptr + attributes->offset[0], + attributes->stride[0]); + + ps->buffer_destroy_listener.notify = + buffer_state_handle_buffer_destroy; + wl_signal_add(&buffer->destroy_signal, + &ps->buffer_destroy_listener); +} + static void pixman_renderer_attach(struct weston_surface *es, struct weston_buffer *buffer) { struct pixman_surface_state *ps = get_surface_state(es); struct wl_shm_buffer *shm_buffer; + struct linux_dmabuf_buffer *dmabuf; const struct pixel_format_info *pixel_info; weston_buffer_reference(&ps->buffer_ref, buffer); @@ -649,9 +740,17 @@ pixman_renderer_attach(struct weston_surface *es, struct weston_buffer *buffer) shm_buffer = wl_shm_buffer_get(buffer->resource); if (! shm_buffer) { - weston_log("Pixman renderer supports only SHM buffers\n"); - weston_buffer_reference(&ps->buffer_ref, NULL); - weston_buffer_release_reference(&ps->buffer_release_ref, NULL); + if ((dmabuf = linux_dmabuf_buffer_get(buffer->resource))) { + pixman_renderer_attach_dmabuf(es, buffer, dmabuf); + } else { + weston_log("unhandled buffer type!\n"); + weston_buffer_reference(&ps->buffer_ref, NULL); + weston_buffer_release_reference(&ps->buffer_release_ref, + NULL); + weston_buffer_send_server_error(buffer, + "disconnecting due to unhandled buffer type"); + } + return; } @@ -750,6 +849,9 @@ pixman_renderer_create_surface(struct weston_surface *surface) wl_signal_add(&pr->destroy_signal, &ps->renderer_destroy_listener); + if (surface->buffer_ref.buffer) + pixman_renderer_attach(surface, surface->buffer_ref.buffer); + return 0; } @@ -780,6 +882,9 @@ pixman_renderer_destroy(struct weston_compositor *ec) wl_signal_emit(&pr->destroy_signal, pr); weston_binding_destroy(pr->debug_binding); + + weston_drm_format_array_fini(&pr->supported_formats); + free(pr); ec->renderer = NULL; @@ -853,12 +958,141 @@ debug_binding(struct weston_keyboard *keyboard, const struct timespec *time, } } +static void +pixman_renderer_destroy_dmabuf(struct linux_dmabuf_buffer *dmabuf) +{ + struct dmabuf_data *data = dmabuf->user_data; + linux_dmabuf_buffer_set_user_data(dmabuf, NULL, NULL); + + if (data) { + if (data->ptr) + munmap(data->ptr, data->size); + + free(data); + } +} + +static bool +pixman_renderer_import_dmabuf(struct weston_compositor *ec, + struct linux_dmabuf_buffer *dmabuf) +{ + struct dmabuf_attributes *attributes = &dmabuf->attributes; + struct dmabuf_data *data; + size_t total_size, vstride0; + int i; + + for (i = 0; i < attributes->n_planes; i++) { + if (attributes->modifier[i] != DRM_FORMAT_MOD_INVALID) + return false; + } + + /* reject all flags we do not recognize or handle */ + if (attributes->flags & ~ZWP_LINUX_BUFFER_PARAMS_V1_FLAGS_Y_INVERT) + return false; + + if (attributes->n_planes < 0) + return false; + + if (attributes->n_planes == 1) + goto out; + + total_size = lseek(attributes->fd[0], 0, SEEK_END); + vstride0 = (attributes->offset[1] - attributes->offset[0]) / + attributes->stride[0]; + + for (i = 1; i < attributes->n_planes; i++) { + size_t size = attributes->offset[i] - attributes->offset[i - 1]; + size_t vstride = size / attributes->stride[i - 1]; + + /* not contig */ + if (size <= 0 || vstride <= 0 || + attributes->offset[i - 1] + size > total_size) + return false; + + /* stride unmatched */ + if ((vstride != vstride0 && vstride != vstride0 / 2) || + (attributes->stride[i] != attributes->stride[0] && + attributes->stride[i] != attributes->stride[0] / 2)) + return false; + } + +out: + /* Handle contig dma buffer */ + + data = zalloc(sizeof *data); + if (!data) + return false; + + linux_dmabuf_buffer_set_user_data(dmabuf, data, + pixman_renderer_destroy_dmabuf); + + data->size = lseek(attributes->fd[0], 0, SEEK_END); + + data->ptr = mmap(NULL, data->size, PROT_READ, + MAP_SHARED, attributes->fd[0], 0); + return data->ptr != MAP_FAILED; +} + +static const struct weston_drm_format_array * +pixman_renderer_get_supported_formats(struct weston_compositor *ec) +{ + struct pixman_renderer *pr = get_renderer(ec); + + return &pr->supported_formats; +} + +static int +populate_supported_formats(struct weston_compositor *ec, + struct weston_drm_format_array *supported_formats) +{ + struct weston_drm_format *fmt; + int i, ret = 0; + + /* TODO: support more formats */ + static const int formats[] = { + DRM_FORMAT_ARGB8888, + DRM_FORMAT_XRGB8888, + DRM_FORMAT_RGBA8888, + DRM_FORMAT_RGBX8888, + DRM_FORMAT_ABGR8888, + DRM_FORMAT_XBGR8888, + DRM_FORMAT_BGRA8888, + DRM_FORMAT_BGRX8888, + DRM_FORMAT_YUYV, + DRM_FORMAT_YVU420, + DRM_FORMAT_YUV420, + DRM_FORMAT_NV12, + DRM_FORMAT_NV16, + }; + + int num_formats = ARRAY_LENGTH(formats); + + for (i = 0; i < num_formats; i++) { + fmt = weston_drm_format_array_add_format(supported_formats, + formats[i]); + if (!fmt) { + ret = -1; + goto out; + } + + /* Always add DRM_FORMAT_MOD_INVALID, as EGL implementations + * support implicit modifiers. */ + ret = weston_drm_format_add_modifier(fmt, DRM_FORMAT_MOD_INVALID); + if (ret < 0) + goto out; + } + +out: + return ret; +} + WL_EXPORT int pixman_renderer_init(struct weston_compositor *ec) { struct pixman_renderer *renderer; const struct pixel_format_info *pixel_info, *info_argb8888, *info_xrgb8888; unsigned int i, num_formats; + int ret; renderer = zalloc(sizeof *renderer); if (renderer == NULL) @@ -880,6 +1114,15 @@ pixman_renderer_init(struct weston_compositor *ec) ec->capabilities |= WESTON_CAP_ROTATION_ANY; ec->capabilities |= WESTON_CAP_VIEW_CLIP_MASK; + weston_drm_format_array_init(&renderer->supported_formats); + + ret = populate_supported_formats(ec, &renderer->supported_formats); + if (ret < 0) { + weston_drm_format_array_fini(&renderer->supported_formats); + free(renderer); + return -1; + } + renderer->debug_binding = weston_compositor_add_debug_binding(ec, KEY_R, debug_binding, ec); @@ -902,6 +1145,11 @@ pixman_renderer_init(struct weston_compositor *ec) wl_signal_init(&renderer->destroy_signal); + renderer->base.import_dmabuf = pixman_renderer_import_dmabuf; + + renderer->base.get_supported_formats = + pixman_renderer_get_supported_formats; + return 0; } -- 2.20.1