commit bd1a974fc2801c104a873b5820d80f695d4228b2
parent 351b43dc6d1583a402434f8f3a6bae432937ae81
Author: Michael Forney <mforney@mforney.org>
Date: Wed, 28 Aug 2019 23:38:54 -0700
Use universal planes for cursor
Diffstat:
9 files changed, 280 insertions(+), 183 deletions(-)
diff --git a/libswc/cursor_plane.c b/libswc/cursor_plane.c
@@ -1,121 +0,0 @@
-/* swc: cursor_plane.c
- *
- * Copyright (c) 2013, 2014 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 "cursor_plane.h"
-#include "drm.h"
-#include "event.h"
-#include "internal.h"
-#include "launch.h"
-#include "screen.h"
-#include "util.h"
-
-#include <errno.h>
-#include <wld/wld.h>
-#include <wld/drm.h>
-#include <xf86drmMode.h>
-
-static bool
-update(struct view *view)
-{
- return true;
-}
-
-static int
-attach(struct view *view, struct wld_buffer *buffer)
-{
- struct cursor_plane *plane = wl_container_of(view, plane, view);
-
- if (buffer) {
- union wld_object object;
-
- if (!wld_export(buffer, WLD_DRM_OBJECT_HANDLE, &object)) {
- ERROR("Could not get export buffer to DRM handle\n");
- /* XXX: Not the best error code, but we don't know better until wld
- * returns an actual error code. */
- return -EINVAL;
- }
-
- if (swc.active && drmModeSetCursor(swc.drm->fd, plane->crtc, object.u32, buffer->width, buffer->height) < 0) {
- ERROR("Could not set cursor: %s\n", strerror(errno));
- return -errno;
- }
- } else if (swc.active && drmModeSetCursor(swc.drm->fd, plane->crtc, 0, 0, 0) < 0) {
- ERROR("Could not unset cursor: %s\n", strerror(errno));
- return -errno;
- }
-
- view_set_size_from_buffer(view, buffer);
- return 0;
-}
-
-static bool
-move(struct view *view, int32_t x, int32_t y)
-{
- struct cursor_plane *plane = wl_container_of(view, plane, view);
-
- if (swc.active && drmModeMoveCursor(swc.drm->fd, plane->crtc, x - plane->origin->x, y - plane->origin->y) != 0) {
- ERROR("Could not move cursor: %s\n", strerror(errno));
- return false;
- }
-
- view_set_position(view, x, y);
-
- return true;
-}
-
-static const struct view_impl view_impl = {
- .update = update,
- .attach = attach,
- .move = move,
-};
-
-static void
-handle_swc_event(struct wl_listener *listener, void *data)
-{
- struct event *event = data;
- struct cursor_plane *plane = wl_container_of(listener, plane, swc_listener);
-
- switch (event->type) {
- case SWC_EVENT_ACTIVATED:
- move(&plane->view, plane->view.geometry.x, plane->view.geometry.y);
- attach(&plane->view, plane->view.buffer);
- break;
- }
-}
-
-bool
-cursor_plane_initialize(struct cursor_plane *plane, uint32_t crtc, const struct swc_rectangle *origin)
-{
- plane->origin = origin;
- plane->crtc = crtc;
- plane->swc_listener.notify = &handle_swc_event;
- wl_signal_add(&swc.event_signal, &plane->swc_listener);
- view_initialize(&plane->view, &view_impl);
-
- return true;
-}
-
-void
-cursor_plane_finalize(struct cursor_plane *plane)
-{
-}
diff --git a/libswc/cursor_plane.h b/libswc/cursor_plane.h
@@ -1,39 +0,0 @@
-/* swc: libswc/cursor_plane.h
- *
- * Copyright (c) 2013, 2014 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_CURSOR_PLANE_H
-#define SWC_CURSOR_PLANE_H
-
-#include "view.h"
-
-struct cursor_plane {
- struct view view;
- const struct swc_rectangle *origin;
- uint32_t crtc;
- struct wl_listener swc_listener;
-};
-
-bool cursor_plane_initialize(struct cursor_plane *plane, uint32_t crtc, const struct swc_rectangle *origin);
-void cursor_plane_finalize(struct cursor_plane *plane);
-
-#endif
diff --git a/libswc/drm.c b/libswc/drm.c
@@ -27,6 +27,7 @@
#include "internal.h"
#include "launch.h"
#include "output.h"
+#include "plane.h"
#include "screen.h"
#include "util.h"
#include "wayland_buffer.h"
@@ -269,6 +270,10 @@ drm_initialize(void)
ERROR("Could not open DRM device at %s\n", primary);
goto error0;
}
+ if (drmSetClientCap(swc.drm->fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1) < 0) {
+ ERROR("Could not enable DRM universal planes\n");
+ goto error1;
+ }
if (drmGetCap(swc.drm->fd, DRM_CAP_CURSOR_WIDTH, &val) < 0)
val = 64;
swc.drm->cursor_w = val;
@@ -341,17 +346,32 @@ drm_finalize(void)
bool
drm_create_screens(struct wl_list *screens)
{
+ drmModePlaneRes *plane_ids;
drmModeRes *resources;
drmModeConnector *connector;
- int i;
+ struct plane *plane, *cursor_plane;
struct output *output;
- uint32_t taken_crtcs = 0;
+ uint32_t i, taken_crtcs = 0;
+ struct wl_list planes;
- if (!(resources = drmModeGetResources(swc.drm->fd))) {
- ERROR("Could not get DRM resources\n");
+ plane_ids = drmModeGetPlaneResources(swc.drm->fd);
+ if (!plane_ids) {
+ ERROR("Could not get DRM plane resources\n");
return false;
}
+ wl_list_init(&planes);
+ for (i = 0; i < plane_ids->count_planes; ++i) {
+ plane = plane_new(plane_ids->planes[i]);
+ if (plane)
+ wl_list_insert(&planes, &plane->link);
+ }
+ drmModeFreePlaneResources(plane_ids);
+ resources = drmModeGetResources(swc.drm->fd);
+ if (!resources) {
+ ERROR("Could not get DRM resources\n");
+ return false;
+ }
for (i = 0; i < resources->count_connectors; ++i, drmModeFreeConnector(connector)) {
connector = drmModeGetConnector(swc.drm->fd, resources->connectors[i]);
@@ -364,6 +384,18 @@ drm_create_screens(struct wl_list *screens)
continue;
}
+ cursor_plane = NULL;
+ wl_list_for_each (plane, &planes, link) {
+ if (plane->type == DRM_PLANE_TYPE_CURSOR && plane->possible_crtcs & 1 << crtc_index) {
+ wl_list_remove(&plane->link);
+ cursor_plane = plane;
+ break;
+ }
+ }
+ if (!cursor_plane) {
+ WARNING("Could not find cursor plane for CRTC %d\n", crtc_index);
+ }
+
if (!find_available_id(&id)) {
WARNING("No more available output IDs\n");
drmModeFreeConnector(connector);
@@ -373,7 +405,7 @@ drm_create_screens(struct wl_list *screens)
if (!(output = output_new(connector)))
continue;
- output->screen = screen_new(resources->crtcs[crtc_index], output);
+ output->screen = screen_new(resources->crtcs[crtc_index], output, cursor_plane);
output->screen->id = id;
taken_crtcs |= 1 << crtc_index;
@@ -382,7 +414,6 @@ drm_create_screens(struct wl_list *screens)
wl_list_insert(screens, &output->screen->link);
}
}
-
drmModeFreeResources(resources);
return true;
@@ -430,6 +461,9 @@ drm_get_framebuffer(struct wld_buffer *buffer)
union wld_object object;
int ret;
+ if (!buffer)
+ return 0;
+
if (wld_export(buffer, WLD_USER_OBJECT_FRAMEBUFFER, &object))
return object.u32;
diff --git a/libswc/local.mk b/libswc/local.mk
@@ -24,7 +24,6 @@ SWC_SOURCES = \
launch/protocol.c \
libswc/bindings.c \
libswc/compositor.c \
- libswc/cursor_plane.c \
libswc/data.c \
libswc/data_device.c \
libswc/data_device_manager.c \
@@ -37,6 +36,7 @@ SWC_SOURCES = \
libswc/output.c \
libswc/panel.c \
libswc/panel_manager.c \
+ libswc/plane.c \
libswc/pointer.c \
libswc/primary_plane.c \
libswc/region.c \
diff --git a/libswc/plane.c b/libswc/plane.c
@@ -0,0 +1,174 @@
+/* swc: libswc/plane.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 "plane.h"
+#include "event.h"
+#include "drm.h"
+#include "internal.h"
+#include "screen.h"
+#include "util.h"
+
+#include <errno.h>
+#include <stdlib.h>
+#include <wld/wld.h>
+#include <wld/drm.h>
+#include <xf86drmMode.h>
+
+enum plane_property {
+ PLANE_TYPE,
+ PLANE_IN_FENCE_FD,
+ PLANE_CRTC_ID,
+ PLANE_CRTC_X,
+ PLANE_CRTC_Y,
+ PLANE_CRTC_W,
+ PLANE_CRTC_H,
+ PLANE_SRC_X,
+ PLANE_SRC_Y,
+ PLANE_SRC_W,
+ PLANE_SRC_H,
+};
+
+static bool
+update(struct view *view)
+{
+ struct plane *plane = wl_container_of(view, plane, view);
+ uint32_t x, y, w, h;
+
+ if (!plane->screen)
+ return false;
+ x = view->geometry.x - plane->screen->base.geometry.x;
+ y = view->geometry.y - plane->screen->base.geometry.y;
+ w = view->geometry.width;
+ h = view->geometry.height;
+ if (swc.active && drmModeSetPlane(swc.drm->fd, plane->id, plane->screen->crtc, plane->fb, 0, x, y, w, h, 0, 0, w << 16, h << 16) < 0) {
+ ERROR("Could not set cursor: %s\n", strerror(errno));
+ return false;
+ }
+
+ return true;
+}
+
+static int
+attach(struct view *view, struct wld_buffer *buffer)
+{
+ struct plane *plane = wl_container_of(view, plane, view);
+
+ plane->fb = drm_get_framebuffer(buffer);
+ view_set_size_from_buffer(view, buffer);
+ return 0;
+}
+
+static bool
+move(struct view *view, int32_t x, int32_t y)
+{
+ view_set_position(view, x, y);
+ return true;
+}
+
+static const struct view_impl view_impl = {
+ .update = update,
+ .attach = attach,
+ .move = move,
+};
+
+static enum plane_property
+find_prop(const char *name)
+{
+ static const char property_names[][16] = {
+ [PLANE_TYPE] = "type",
+ [PLANE_IN_FENCE_FD] = "IN_FENCE_FD",
+ [PLANE_CRTC_ID] = "CRTC_ID",
+ [PLANE_CRTC_X] = "CRTC_X",
+ [PLANE_CRTC_Y] = "CRTC_Y",
+ [PLANE_CRTC_W] = "CRTC_W",
+ [PLANE_CRTC_H] = "CRTC_H",
+ [PLANE_SRC_X] = "SRC_X",
+ [PLANE_SRC_Y] = "SRC_Y",
+ [PLANE_SRC_W] = "SRC_W",
+ [PLANE_SRC_H] = "SRC_H",
+ };
+ size_t i;
+
+ for (i = 0; i < ARRAY_LENGTH(property_names); ++i) {
+ if (strcmp(name, property_names[i]) == 0)
+ return i;
+ }
+ return -1;
+}
+
+static void
+handle_swc_event(struct wl_listener *listener, void *data)
+{
+ struct event *event = data;
+ struct plane *plane = wl_container_of(listener, plane, swc_listener);
+
+ switch (event->type) {
+ case SWC_EVENT_ACTIVATED:
+ update(&plane->view);
+ break;
+ }
+}
+
+struct plane *
+plane_new(uint32_t id)
+{
+ struct plane *plane;
+ uint32_t i;
+ drmModeObjectProperties *props;
+ drmModePropertyRes *prop;
+ drmModePlane *drm_plane;
+
+ plane = malloc(sizeof(*plane));
+ if (!plane)
+ goto error0;
+ drm_plane = drmModeGetPlane(swc.drm->fd, id);
+ if (!drm_plane)
+ goto error1;
+ plane->id = id;
+ plane->fb = 0;
+ plane->screen = NULL;
+ plane->possible_crtcs = drm_plane->possible_crtcs;
+ drmModeFreePlane(drm_plane);
+ plane->type = -1;
+ props = drmModeObjectGetProperties(swc.drm->fd, id, DRM_MODE_OBJECT_PLANE);
+ for (i = 0; i < props->count_props; ++i, drmModeFreeProperty(prop)) {
+ prop = drmModeGetProperty(swc.drm->fd, props->props[i]);
+ if (prop && find_prop(prop->name) == PLANE_TYPE)
+ plane->type = props->prop_values[i];
+ }
+ plane->swc_listener.notify = &handle_swc_event;
+ wl_signal_add(&swc.event_signal, &plane->swc_listener);
+ view_initialize(&plane->view, &view_impl);
+ return plane;
+
+error1:
+ free(plane);
+error0:
+ return NULL;
+}
+
+void
+plane_destroy(struct plane *plane)
+{
+ free(plane);
+}
diff --git a/libswc/plane.h b/libswc/plane.h
@@ -0,0 +1,45 @@
+/* swc: libswc/plane.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_PLANE_H
+#define SWC_PLANE_H
+
+#include "plane.h"
+#include "view.h"
+
+#include <wayland-util.h>
+
+struct plane {
+ struct view view;
+ struct screen *screen;
+ uint32_t id, fb;
+ int type;
+ uint32_t possible_crtcs;
+ struct wl_listener swc_listener;
+ struct wl_list link;
+};
+
+struct plane *plane_new(uint32_t id);
+void plane_destroy(struct plane *plane);
+
+#endif
diff --git a/libswc/pointer.c b/libswc/pointer.c
@@ -25,6 +25,7 @@
#include "compositor.h"
#include "event.h"
#include "internal.h"
+#include "plane.h"
#include "screen.h"
#include "shm.h"
#include "surface.h"
@@ -106,8 +107,10 @@ attach(struct view *view, struct wld_buffer *buffer)
if (view_set_size_from_buffer(view, buffer))
view_update_screens(view);
- wl_list_for_each (screen, &swc.screens, link)
- view_attach(&screen->planes.cursor.view, buffer ? pointer->cursor.buffer : NULL);
+ wl_list_for_each (screen, &swc.screens, link) {
+ view_attach(&screen->planes.cursor->view, buffer ? pointer->cursor.buffer : NULL);
+ view_update(&screen->planes.cursor->view);
+ }
return 0;
}
@@ -120,8 +123,10 @@ move(struct view *view, int32_t x, int32_t y)
if (view_set_position(view, x, y))
view_update_screens(view);
- wl_list_for_each (screen, &swc.screens, link)
- view_move(&screen->planes.cursor.view, view->geometry.x, view->geometry.y);
+ wl_list_for_each (screen, &swc.screens, link) {
+ view_move(&screen->planes.cursor->view, view->geometry.x, view->geometry.y);
+ view_update(&screen->planes.cursor->view);
+ }
return true;
}
@@ -243,7 +248,7 @@ pointer_initialize(struct pointer *pointer)
pointer_set_cursor(pointer, cursor_left_ptr);
wl_list_for_each (screen, &swc.screens, link)
- view_attach(&screen->planes.cursor.view, pointer->cursor.buffer);
+ view_attach(&screen->planes.cursor->view, pointer->cursor.buffer);
input_focus_initialize(&pointer->focus, &pointer->focus_handler);
pixman_region32_init(&pointer->region);
diff --git a/libswc/screen.c b/libswc/screen.c
@@ -27,6 +27,7 @@
#include "internal.h"
#include "mode.h"
#include "output.h"
+#include "plane.h"
#include "pointer.h"
#include "util.h"
@@ -98,7 +99,7 @@ bind_screen(struct wl_client *client, void *data, uint32_t version, uint32_t id)
}
struct screen *
-screen_new(uint32_t crtc, struct output *output)
+screen_new(uint32_t crtc, struct output *output, struct plane *cursor_plane)
{
struct screen *screen;
int32_t x = 0;
@@ -117,15 +118,15 @@ screen_new(uint32_t crtc, struct output *output)
goto error1;
}
+ screen->crtc = crtc;
+
if (!primary_plane_initialize(&screen->planes.primary, crtc, output->preferred_mode, &output->connector, 1)) {
ERROR("Failed to initialize primary plane\n");
goto error2;
}
- if (!cursor_plane_initialize(&screen->planes.cursor, crtc, &screen->base.geometry)) {
- ERROR("Failed to initialize cursor plane\n");
- goto error3;
- }
+ cursor_plane->screen = screen;
+ screen->planes.cursor = cursor_plane;
screen->handler = &null_handler;
wl_signal_init(&screen->destroy_signal);
@@ -142,8 +143,6 @@ screen_new(uint32_t crtc, struct output *output)
return screen;
-error3:
- primary_plane_finalize(&screen->planes.primary);
error2:
wl_global_destroy(screen->global);
error1:
@@ -165,7 +164,7 @@ screen_destroy(struct screen *screen)
wl_list_for_each_safe (output, next, &screen->outputs, link)
output_destroy(output);
primary_plane_finalize(&screen->planes.primary);
- cursor_plane_finalize(&screen->planes.cursor);
+ plane_destroy(screen->planes.cursor);
free(screen);
}
diff --git a/libswc/screen.h b/libswc/screen.h
@@ -25,7 +25,6 @@
#define SWC_SCREEN_H
#include "swc.h"
-#include "cursor_plane.h"
#include "primary_plane.h"
#include <wayland-util.h>
@@ -50,10 +49,11 @@ struct screen {
struct wl_signal destroy_signal;
uint8_t id;
+ uint32_t crtc;
struct {
struct primary_plane primary;
- struct cursor_plane cursor;
+ struct plane *cursor;
} planes;
struct wl_global *global;
@@ -67,7 +67,7 @@ struct screen {
bool screens_initialize(void);
void screens_finalize(void);
-struct screen *screen_new(uint32_t crtc, struct output *output);
+struct screen *screen_new(uint32_t crtc, struct output *output, struct plane *cursor_plane);
void screen_destroy(struct screen *screen);
static inline uint32_t