From: Benjamin Gaignard <benjamin.gaign...@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.gaign...@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
-- 
1.7.9.5

_______________________________________________
wayland-devel mailing list
wayland-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/wayland-devel

Reply via email to