commit 029cdb9d180d628cfbe828135948ab59caa52b8d
parent f0e0669bc3f4cf991674300e298e311472ba3cc8
Author: Michael Forney <mforney@mforney.org>
Date: Wed, 28 Aug 2019 15:00:04 -0700
Implement linux-dmabuf protocol
Diffstat:
6 files changed, 259 insertions(+), 3 deletions(-)
diff --git a/.gitignore b/.gitignore
@@ -8,6 +8,7 @@ protocol/wayland-drm-protocol.c
protocol/wayland-drm-server-protocol.h
protocol/xdg-shell-protocol.c
protocol/xdg-shell-server-protocol.h
+protocol/linux-dmabuf-unstable-v1-server-protocol.h
/.deps/
/swc.pc
diff --git a/libswc/dmabuf.c b/libswc/dmabuf.c
@@ -0,0 +1,214 @@
+/* swc: dmabuf.c
+ *
+ * Copyright (c) 2019 Michael Forney
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "dmabuf.h"
+#include "drm.h"
+#include "internal.h"
+#include "util.h"
+#include "wayland_buffer.h"
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <drm_fourcc.h>
+#include <unistd.h>
+#include <wld/wld.h>
+#include <wld/drm.h>
+#include "linux-dmabuf-unstable-v1-server-protocol.h"
+
+struct params {
+ struct wl_resource *resource;
+ int fd[4];
+ uint32_t offset[4];
+ uint32_t stride[4];
+ uint64_t modifier[4];
+ bool created;
+};
+
+static void
+destroy(struct wl_client *client, struct wl_resource *resource)
+{
+ wl_resource_destroy(resource);
+}
+
+static void
+add(struct wl_client *client, struct wl_resource *resource, int32_t fd, uint32_t i, uint32_t offset, uint32_t stride, uint32_t modifier_hi, uint32_t modifier_lo)
+{
+ struct params *params = wl_resource_get_user_data(resource);
+
+ if (params->created) {
+ wl_resource_post_error(resource, ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_ALREADY_USED, "buffer already created");
+ return;
+ }
+ if (i > ARRAY_LENGTH(params->fd)) {
+ wl_resource_post_error(resource, ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_PLANE_IDX, "plane index too large");
+ return;
+ }
+ if (params->fd[i] != -1) {
+ wl_resource_post_error(resource, ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_PLANE_SET, "buffer plane already set");
+ return;
+ }
+ params->fd[i] = fd;
+ params->offset[i] = offset;
+ params->stride[i] = stride;
+ params->modifier[i] = (uint64_t)modifier_hi << 32 | modifier_lo;
+}
+
+static void
+create_immed(struct wl_client *client, struct wl_resource *resource, uint32_t id,
+ int32_t width, int32_t height, uint32_t format, uint32_t flags)
+{
+ struct params *params = wl_resource_get_user_data(resource);
+ struct wld_buffer *buffer;
+ struct wl_resource *buffer_resource;
+ union wld_object object;
+ int num_planes, i;
+
+ if (params->created) {
+ wl_resource_post_error(resource, ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_ALREADY_USED, "buffer already created");
+ return;
+ }
+ params->created = true;
+ switch (format) {
+ case DRM_FORMAT_XRGB8888:
+ case DRM_FORMAT_ARGB8888:
+ num_planes = 1;
+ break;
+ default:
+ wl_resource_post_error(resource, ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INVALID_FORMAT, "unsupported format %#" PRIx32, format);
+ return;
+ }
+ for (i = 0; i < num_planes; ++i) {
+ if (params->fd[i] == -1)
+ wl_resource_post_error(resource, ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INCOMPLETE, "missing plane %d", i);
+ }
+ for (; i < ARRAY_LENGTH(params->fd); ++i) {
+ if (params->fd[i] != -1)
+ wl_resource_post_error(resource, ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INCOMPLETE, "too many planes");
+ }
+ object.i = params->fd[0];
+ buffer = wld_import_buffer(swc.drm->context, WLD_DRM_OBJECT_PRIME_FD, object, width, height, format, params->stride[0]);
+ for (i = 0; i < num_planes; ++i) {
+ close(params->fd[i]);
+ params->fd[i] = -1;
+ }
+ if (!buffer)
+ zwp_linux_buffer_params_v1_send_failed(resource);
+
+ buffer_resource = wayland_buffer_create_resource(client, 1, id, buffer);
+ if (!buffer_resource) {
+ if (buffer)
+ wld_buffer_unreference(buffer);
+ wl_resource_post_no_memory(resource);
+ return;
+ }
+ if (id == 0 && buffer)
+ zwp_linux_buffer_params_v1_send_created(resource, buffer_resource);
+}
+
+static void
+create(struct wl_client *client, struct wl_resource *resource,
+ int32_t width, int32_t height, uint32_t format, uint32_t flags)
+{
+ create_immed(client, resource, 0, width, height, format, flags);
+}
+
+static const struct zwp_linux_buffer_params_v1_interface params_impl = {
+ .destroy = destroy,
+ .add = add,
+ .create = create,
+ .create_immed = create_immed,
+};
+
+static void
+params_destroy(struct wl_resource *resource)
+{
+ struct params *params = wl_resource_get_user_data(resource);
+ int i;
+
+ for (i = 0; i < ARRAY_LENGTH(params->fd); ++i)
+ close(params->fd[i]);
+}
+
+static void
+create_params(struct wl_client *client, struct wl_resource *resource, uint32_t id)
+{
+ struct params *params;
+ int i;
+
+ params = malloc(sizeof(*params));
+ if (!params)
+ goto error0;
+ params->created = false;
+ params->resource = wl_resource_create(client, &zwp_linux_buffer_params_v1_interface, wl_resource_get_version(resource), id);
+ if (!params->resource)
+ goto error1;
+ for (i = 0; i < ARRAY_LENGTH(params->fd); ++i)
+ params->fd[i] = -1;
+ wl_resource_set_implementation(params->resource, ¶ms_impl, params, params_destroy);
+ return;
+
+error1:
+ free(params);
+error0:
+ wl_resource_post_no_memory(resource);
+}
+
+static const struct zwp_linux_dmabuf_v1_interface dmabuf_impl = {
+ .destroy = destroy,
+ .create_params = create_params,
+};
+
+static void
+bind_dmabuf(struct wl_client *client, void *data, uint32_t version, uint32_t id)
+{
+ static const uint32_t formats[] = {
+ DRM_FORMAT_XRGB8888,
+ DRM_FORMAT_ARGB8888,
+ };
+ uint64_t modifier = DRM_FORMAT_MOD_INVALID;
+ struct wl_resource *resource;
+ size_t i;
+
+ if (version > 3)
+ version = 3;
+ resource = wl_resource_create(client, &zwp_linux_dmabuf_v1_interface, version, id);
+ if (!resource) {
+ wl_client_post_no_memory(client);
+ return;
+ }
+ wl_resource_set_implementation(resource, &dmabuf_impl, NULL, NULL);
+ for (i = 0; i < ARRAY_LENGTH(formats); ++i) {
+ if (version >= 3) {
+ /* TODO: need a way to query DRM modifiers of wld */
+ zwp_linux_dmabuf_v1_send_modifier(resource, formats[i], modifier >> 32, modifier & 0xffffffff);
+ } else {
+ zwp_linux_dmabuf_v1_send_format(resource, formats[i]);
+ }
+ }
+}
+
+struct wl_global *
+swc_dmabuf_create(struct wl_display *display)
+{
+ return wl_global_create(display, &zwp_linux_dmabuf_v1_interface, 3, NULL, &bind_dmabuf);
+}
diff --git a/libswc/dmabuf.h b/libswc/dmabuf.h
@@ -0,0 +1,31 @@
+/* swc: libswc/dmabuf.h
+ *
+ * Copyright (c) 2019 Michael Forney
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef SWC_DMABUF_H
+#define SWC_DMABUF_H
+
+struct wl_display;
+
+struct wl_global *swc_dmabuf_create(struct wl_display *display);
+
+#endif
diff --git a/libswc/drm.c b/libswc/drm.c
@@ -22,6 +22,7 @@
*/
#include "drm.h"
+#include "dmabuf.h"
#include "event.h"
#include "internal.h"
#include "launch.h"
@@ -53,6 +54,7 @@ static struct {
uint32_t taken_ids;
struct wl_global *global;
+ struct wl_global *dmabuf;
struct wl_event_source *event_source;
} drm;
@@ -299,11 +301,15 @@ drm_initialize(void)
if (!wld_drm_is_dumb(swc.drm->context)) {
drm.global = wl_global_create(swc.display, &wl_drm_interface, 2, NULL, &bind_drm);
-
if (!drm.global) {
ERROR("Could not create wl_drm global\n");
goto error4;
}
+
+ drm.dmabuf = swc_dmabuf_create(swc.display);
+ if (!drm.dmabuf) {
+ WARNING("Could not create wp_linux_dmabuf global\n");
+ }
}
return true;
diff --git a/libswc/local.mk b/libswc/local.mk
@@ -28,6 +28,7 @@ SWC_SOURCES = \
libswc/data.c \
libswc/data_device.c \
libswc/data_device_manager.c \
+ libswc/dmabuf.c \
libswc/drm.c \
libswc/input.c \
libswc/keyboard.c \
@@ -55,7 +56,8 @@ SWC_SOURCES = \
libswc/xdg_shell.c \
protocol/swc-protocol.c \
protocol/wayland-drm-protocol.c \
- protocol/xdg-shell-protocol.c
+ protocol/xdg-shell-protocol.c \
+ protocol/linux-dmabuf-unstable-v1-protocol.c
ifeq ($(ENABLE_LIBUDEV),1)
$(dir)_CFLAGS += -DENABLE_LIBUDEV
@@ -68,6 +70,7 @@ SWC_SHARED_OBJECTS = $(SWC_SOURCES:%.c=%.lo)
# Explicitly state dependencies on generated files
objects = $(foreach obj,$(1),$(dir)/$(obj).o $(dir)/$(obj).lo)
$(call objects,compositor panel_manager panel screen): protocol/swc-server-protocol.h
+$(call objects,dmabuf): protocol/linux-dmabuf-unstable-v1-server-protocol.h
$(call objects,drm drm_buffer): protocol/wayland-drm-server-protocol.h
$(call objects,xdg_shell): protocol/xdg-shell-server-protocol.h
$(call objects,pointer): cursor/cursor_data.h
diff --git a/protocol/local.mk b/protocol/local.mk
@@ -6,7 +6,8 @@ wayland_protocols := $(call pkgconfig,wayland-protocols,variable=pkgdatadir,DATA
PROTOCOL_EXTENSIONS = \
$(dir)/swc.xml \
$(dir)/wayland-drm.xml \
- $(wayland_protocols)/stable/xdg-shell/xdg-shell.xml
+ $(wayland_protocols)/stable/xdg-shell/xdg-shell.xml \
+ $(wayland_protocols)/unstable/linux-dmabuf/linux-dmabuf-unstable-v1.xml
$(dir)_PACKAGES := wayland-server