From: Benjamin Gaignard benjamin.gaignard@linaro.org
Make drm compositor aware of the wl_dmabuf protocol if pixman is used. Add functions to have a wl_dmabuf server inside drm compositor. Change pixman to let it know how use a wl_dmabuf buffer.
Signed-off-by: Benjamin Gaignard benjamin.gaignard@linaro.org --- src/compositor-drm.c | 168 +++++++++++++++++++++++++++++++++++++++++++++++-- src/compositor.c | 4 +- src/compositor.h | 2 + src/pixman-renderer.c | 86 ++++++++++++++++++------- 4 files changed, 230 insertions(+), 30 deletions(-)
diff --git a/src/compositor-drm.c b/src/compositor-drm.c index 4f015d1..dd957cd 100644 --- a/src/compositor-drm.c +++ b/src/compositor-drm.c @@ -49,6 +49,8 @@ #include "udev-seat.h" #include "launcher-util.h" #include "vaapi-recorder.h" +#include "wayland-dmabuf.h" +#include "wayland-dmabuf-server-protocol.h"
#ifndef DRM_CAP_TIMESTAMP_MONOTONIC #define DRM_CAP_TIMESTAMP_MONOTONIC 0x6 @@ -826,7 +828,8 @@ drm_output_prepare_overlay_surface(struct weston_output *output_base, if (es->alpha != 1.0f) return NULL;
- if (wl_shm_buffer_get(es->buffer_ref.buffer->resource)) + if (wl_shm_buffer_get(es->buffer_ref.buffer->resource) + || wl_dmabuf_buffer_get(es->buffer_ref.buffer->resource)) return NULL;
if (!drm_surface_transform_supported(es)) @@ -951,7 +954,8 @@ drm_output_prepare_cursor_surface(struct weston_output *output_base, if (c->cursors_are_broken) return NULL; if (es->buffer_ref.buffer == NULL || - !wl_shm_buffer_get(es->buffer_ref.buffer->resource) || + (!wl_shm_buffer_get(es->buffer_ref.buffer->resource) && + !wl_dmabuf_buffer_get(es->buffer_ref.buffer->resource))|| es->geometry.width > 64 || es->geometry.height > 64) return NULL;
@@ -985,12 +989,25 @@ drm_output_set_cursor(struct drm_output *output) output->current_cursor ^= 1; bo = output->cursor_bo[output->current_cursor]; memset(buf, 0, sizeof buf); - stride = wl_shm_buffer_get_stride(es->buffer_ref.buffer->shm_buffer); - s = wl_shm_buffer_get_data(es->buffer_ref.buffer->shm_buffer); + if (wl_shm_buffer_get(es->buffer_ref.buffer->resource)) { + stride = wl_shm_buffer_get_stride(es->buffer_ref.buffer->shm_buffer); + s = wl_shm_buffer_get_data(es->buffer_ref.buffer->shm_buffer); + } + if (wl_dmabuf_buffer_get(es->buffer_ref.buffer->resource)) { + stride = wl_dmabuf_buffer_get_stride(es->buffer_ref.buffer->dmabuf_buffer, 0); + s = wl_dmabuf_buffer_get_data(es->buffer_ref.buffer->dmabuf_buffer); + if (!s) { + weston_log("failed to get data from dmabuf buffer"); + return; + } + } for (i = 0; i < es->geometry.height; i++) memcpy(buf + i * 64, s + i * stride, es->geometry.width * 4);
+ if (wl_dmabuf_buffer_get(es->buffer_ref.buffer->resource)) + wl_dmabuf_buffer_put_data(es->buffer_ref.buffer->dmabuf_buffer); + if (gbm_bo_write(bo, buf, sizeof buf) < 0) weston_log("failed update cursor: %m\n");
@@ -1044,7 +1061,8 @@ drm_assign_planes(struct weston_output *output) * non-shm, or small enough to be a cursor */ if ((es->buffer_ref.buffer && - !wl_shm_buffer_get(es->buffer_ref.buffer->resource)) || + (!wl_shm_buffer_get(es->buffer_ref.buffer->resource)) + && !wl_dmabuf_buffer_get(es->buffer_ref.buffer->resource)) || (es->geometry.width <= 64 && es->geometry.height <= 64)) es->keep_buffer = 1; else @@ -1268,6 +1286,142 @@ init_drm(struct drm_compositor *ec, struct udev_device *device) return 0; }
+struct dmabuf_driver_buffer { + uint32_t size; + uint32_t handle; + char *data; +}; + +static void +dmabuf_reference_buffer(void *user_data, int prime_fd, struct wl_dmabuf_buffer *buffer) +{ + struct drm_compositor *ec = user_data; + uint32_t handles[4], pitches[4], offsets[4]; + int ret; + uint32_t fd; + struct dmabuf_driver_buffer *driver_buffer; + + if (prime_fd == -1) + return; + + drmPrimeFDToHandle(ec->drm.fd, prime_fd, &handles[0]); + pitches[0] = buffer->stride[0]; + pitches[1] = buffer->stride[1]; + pitches[2] = buffer->stride[2]; + offsets[0] = buffer->offset[0]; + offsets[1] = buffer->offset[1]; + offsets[2] = buffer->offset[2]; + + ret = drmModeAddFB2 (ec->drm.fd, buffer->width, buffer->height, + buffer->format, handles, pitches, offsets, &fd, 0); + if (ret) { + weston_log("addfb2 failed: %m\n"); + return; + } + + driver_buffer = malloc(sizeof *driver_buffer); + if (driver_buffer == NULL) + return; + + driver_buffer->size = buffer->width * buffer->height * 4; + driver_buffer->handle = handles[0]; + driver_buffer->data = NULL; + buffer->driver_buffer = driver_buffer; +} + +static void +dmabuf_unreference_buffer(void *user_data, struct wl_dmabuf_buffer *buffer) +{ + struct dmabuf_driver_buffer *driver_buffer = buffer->driver_buffer; + + if(driver_buffer->data) + munmap(driver_buffer->data, driver_buffer->size); + + free(buffer->driver_buffer); +} + +static void* +dmabuf_get_data(void *user_data, struct wl_dmabuf_buffer *buffer) +{ + struct dmabuf_driver_buffer *driver_buffer = buffer->driver_buffer; + struct drm_compositor *ec = user_data; + + if (!driver_buffer->data) { + int fd; + drmPrimeHandleToFD(ec->drm.fd, driver_buffer->handle, 0, &fd); + driver_buffer->data = mmap (0, driver_buffer->size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + close(fd); + } + return driver_buffer->data; +} + + +static void +dmabuf_put_data(void *user_data, struct wl_dmabuf_buffer *buffer) +{ + struct dmabuf_driver_buffer *driver_buffer = buffer->driver_buffer; + + if (!driver_buffer->data) { + munmap (driver_buffer->data, driver_buffer->size); + driver_buffer->data = NULL; + } +} + +static void dmabuf_send_supported_formats(void *user_data, struct wl_resource *resource) +{ + struct drm_compositor *ec = user_data; + drmModePlaneRes *plane_resources; + unsigned int i, j; + + weston_log("send supported formats\n"); + + plane_resources = drmModeGetPlaneResources(ec->drm.fd); + if (!plane_resources) + return; + + for (i = 0; i < plane_resources->count_planes; i++) { + drmModePlane *ovr = drmModeGetPlane(ec->drm.fd, plane_resources->planes[i]); + + for (j = 0 ; j < ovr->count_formats; j++) { + weston_log("server support format %4.4s\n", (char *)&ovr->formats[j]); + wl_dmabuf_send_format(resource, ovr->formats[j]); + } + drmModeFreePlane(ovr); + } + + drmModeFreePlaneResources(plane_resources); +} + +static void dmabuf_send_device_name(void *user_data, struct wl_resource *resource) +{ + struct drm_compositor *ec = user_data; + weston_log("send device name %s\n", ec->drm.filename); + + wl_dmabuf_send_device(resource, ec->drm.filename); +} + +static void dmabuf_send_server_info(void *user_data, struct wl_resource *resource) +{ + dmabuf_send_supported_formats(user_data, resource); + dmabuf_send_device_name(user_data, resource); +} + +static struct wl_dmabuf_callbacks wl_dmabuf_callbacks = { + dmabuf_reference_buffer, + dmabuf_unreference_buffer, + dmabuf_get_data, + dmabuf_put_data, + dmabuf_send_server_info +}; + +static int +init_dmabuf_protocol(struct drm_compositor *ec) +{ + wl_dmabuf_init(ec->base.wl_display, + &wl_dmabuf_callbacks, ec, 0); + return 0; +} + static int init_egl(struct drm_compositor *ec) { @@ -1955,6 +2109,10 @@ create_output_for_connector(struct drm_compositor *ec, weston_log("Failed to init output pixman state\n"); goto err_output; } + if (init_dmabuf_protocol(ec) < 0) { + weston_log("Failed to init wl_dmabuf server\n"); + goto err_output; + } } else if (drm_output_init_egl(output, ec) < 0) { weston_log("Failed to init output gl state\n"); goto err_output; diff --git a/src/compositor.c b/src/compositor.c index 4cb44e5..037b695 100644 --- a/src/compositor.c +++ b/src/compositor.c @@ -1257,7 +1257,9 @@ surface_accumulate_damage(struct weston_surface *surface, pixman_region32_t *opaque) { if (surface->buffer_ref.buffer && - wl_shm_buffer_get(surface->buffer_ref.buffer->resource)) + (wl_shm_buffer_get(surface->buffer_ref.buffer->resource) + || wl_dmabuf_buffer_get(surface->buffer_ref.buffer->resource)) + ) surface->compositor->renderer->flush_damage(surface);
if (surface->transform.enabled) { diff --git a/src/compositor.h b/src/compositor.h index 0dcb604..537a9b7 100644 --- a/src/compositor.h +++ b/src/compositor.h @@ -33,6 +33,7 @@ extern "C" {
#define WL_HIDE_DEPRECATED #include <wayland-server.h> +#include <wayland-dmabuf.h>
#include "version.h" #include "matrix.h" @@ -626,6 +627,7 @@ struct weston_buffer {
union { struct wl_shm_buffer *shm_buffer; + struct wl_dmabuf_buffer *dmabuf_buffer; void *legacy_buffer; }; int32_t width, height; diff --git a/src/pixman-renderer.c b/src/pixman-renderer.c index 987c539..7802f2d 100644 --- a/src/pixman-renderer.c +++ b/src/pixman-renderer.c @@ -533,6 +533,8 @@ 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 wl_dmabuf_buffer *dmabuf_buffer; + pixman_format_code_t pixman_format;
weston_buffer_reference(&ps->buffer_ref, buffer); @@ -544,40 +546,76 @@ pixman_renderer_attach(struct weston_surface *es, struct weston_buffer *buffer)
if (!buffer) return; - + shm_buffer = wl_shm_buffer_get(buffer->resource); + dmabuf_buffer = wl_dmabuf_buffer_get(buffer->resource);
- if (! shm_buffer) { - weston_log("Pixman renderer supports only SHM buffers\n"); + if (!shm_buffer && !dmabuf_buffer) { + weston_log("Pixman renderer supports only SHM and DMABUF buffers\n"); weston_buffer_reference(&ps->buffer_ref, NULL); return; }
- switch (wl_shm_buffer_get_format(shm_buffer)) { - case WL_SHM_FORMAT_XRGB8888: - pixman_format = PIXMAN_x8r8g8b8; - break; - case WL_SHM_FORMAT_ARGB8888: - pixman_format = PIXMAN_a8r8g8b8; - break; - case WL_SHM_FORMAT_RGB565: - pixman_format = PIXMAN_r5g6b5; + if (shm_buffer) { + switch (wl_shm_buffer_get_format(shm_buffer)) { + case WL_SHM_FORMAT_XRGB8888: + pixman_format = PIXMAN_x8r8g8b8; + break; + case WL_SHM_FORMAT_ARGB8888: + pixman_format = PIXMAN_a8r8g8b8; + break; + case WL_SHM_FORMAT_RGB565: + pixman_format = PIXMAN_r5g6b5; + break; + default: + weston_log("Unsupported SHM buffer format\n"); + weston_buffer_reference(&ps->buffer_ref, NULL); + return; break; - default: - weston_log("Unsupported SHM buffer format\n"); - weston_buffer_reference(&ps->buffer_ref, NULL); - return; - break; + } + + buffer->shm_buffer = shm_buffer; + buffer->width = wl_shm_buffer_get_width(shm_buffer); + buffer->height = wl_shm_buffer_get_height(shm_buffer); + + ps->image = pixman_image_create_bits(pixman_format, + buffer->width, buffer->height, + wl_shm_buffer_get_data(shm_buffer), + wl_shm_buffer_get_stride(shm_buffer)); }
- buffer->shm_buffer = shm_buffer; - buffer->width = wl_shm_buffer_get_width(shm_buffer); - buffer->height = wl_shm_buffer_get_height(shm_buffer); + if (dmabuf_buffer) { + void *data; + switch (wl_dmabuf_buffer_get_format(dmabuf_buffer)) { + case WL_DMABUF_FORMAT_XRGB8888: + pixman_format = PIXMAN_x8r8g8b8; + break; + case WL_DMABUF_FORMAT_ARGB8888: + pixman_format = PIXMAN_a8r8g8b8; + break; + case WL_DMABUF_FORMAT_RGB565: + pixman_format = PIXMAN_r5g6b5; + break; + default: + weston_log("Unsupported DMABUF buffer format\n"); + weston_buffer_reference(&ps->buffer_ref, NULL); + return; + break; + }
- ps->image = pixman_image_create_bits(pixman_format, - buffer->width, buffer->height, - wl_shm_buffer_get_data(shm_buffer), - wl_shm_buffer_get_stride(shm_buffer)); + buffer->dmabuf_buffer = dmabuf_buffer; + buffer->width = wl_dmabuf_buffer_get_width(dmabuf_buffer); + buffer->height = wl_dmabuf_buffer_get_height(dmabuf_buffer); + + data = wl_dmabuf_buffer_get_data(dmabuf_buffer); + if (data) { + ps->image = pixman_image_create_bits(pixman_format, + buffer->width, buffer->height, data, + wl_dmabuf_buffer_get_stride(dmabuf_buffer, 0)); + wl_dmabuf_buffer_put_data(dmabuf_buffer); + } else + weston_log("failed to get data from dmabuf buffer"); + } }
static int