From 45473d724006e26c532840b0ed81608b10e3f0ac Mon Sep 17 00:00:00 2001 From: imterah Date: Sun, 22 Jun 2025 17:41:05 -0400 Subject: [PATCH] feature: Add DRM leasing code --- raylib/cgo_linux_drm.go | 9 +- raylib/cgo_linux_drm_leasing.go | 11 + raylib/cgo_linux_drm_leasing_no_keyboard.go | 11 + raylib/cgo_linux_drm_no_keyboard.go | 11 + raylib/config.h | 2 +- raylib/platforms/drm-lease-v1.c | 116 +++ raylib/platforms/drm-lease-v1.h | 743 ++++++++++++++++++++ raylib/platforms/drm-lease-v1.xml | 317 +++++++++ raylib/platforms/rcore_drm.c | 490 ++++++++++--- 9 files changed, 1611 insertions(+), 99 deletions(-) create mode 100644 raylib/cgo_linux_drm_leasing.go create mode 100644 raylib/cgo_linux_drm_leasing_no_keyboard.go create mode 100644 raylib/cgo_linux_drm_no_keyboard.go create mode 100644 raylib/platforms/drm-lease-v1.c create mode 100644 raylib/platforms/drm-lease-v1.h create mode 100644 raylib/platforms/drm-lease-v1.xml diff --git a/raylib/cgo_linux_drm.go b/raylib/cgo_linux_drm.go index c50ce91..66d07e4 100644 --- a/raylib/cgo_linux_drm.go +++ b/raylib/cgo_linux_drm.go @@ -1,10 +1,11 @@ -//go:build linux && drm && !rgfw && !sdl && !sdl3 && !android -// +build linux,drm,!rgfw,!sdl,!sdl3,!android +//go:build linux && drm && !drm_leasing && !drm_disable_input && !rgfw && !sdl && !sdl3 && !android +// +build linux,drm,!drm_leasing,!drm_disable_input,!rgfw,!sdl,!sdl3,!android package rl /* -#cgo linux,drm LDFLAGS: -lGLESv2 -lEGL -ldrm -lgbm -lpthread -lrt -lm -ldl -#cgo linux,drm CFLAGS: -DPLATFORM_DRM -DGRAPHICS_API_OPENGL_ES2 -DEGL_NO_X11 -I/usr/include/libdrm +#cgo pkg-config: libdrm gbm +#cgo linux,drm LDFLAGS: -lGLESv2 -lEGL -lpthread -lrt -lm -ldl +#cgo linux,drm CFLAGS: -DSUPPORT_SSH_KEYBOARD_RPI -DPLATFORM_DRM -DGRAPHICS_API_OPENGL_ES2 -DEGL_NO_X11 */ import "C" diff --git a/raylib/cgo_linux_drm_leasing.go b/raylib/cgo_linux_drm_leasing.go new file mode 100644 index 0000000..b56afc0 --- /dev/null +++ b/raylib/cgo_linux_drm_leasing.go @@ -0,0 +1,11 @@ +//go:build linux && drm && drm_leasing && !drm_disable_input && !rgfw && !sdl && !sdl3 && !android +// +build linux,drm,drm_leasing,!drm_disable_input,!rgfw,!sdl,!sdl3,!android + +package rl + +/* +#cgo pkg-config: libdrm gbm wayland-client +#cgo linux,drm LDFLAGS: -lGLESv2 -lEGL -lpthread -lrt -lm -ldl +#cgo linux,drm CFLAGS: -DSUPPORT_SSH_KEYBOARD_RPI -DPLATFORM_DRM -DENABLE_WAYLAND_DRM_LEASING -DGRAPHICS_API_OPENGL_ES2 -DEGL_NO_X11 +*/ +import "C" diff --git a/raylib/cgo_linux_drm_leasing_no_keyboard.go b/raylib/cgo_linux_drm_leasing_no_keyboard.go new file mode 100644 index 0000000..bd04a7f --- /dev/null +++ b/raylib/cgo_linux_drm_leasing_no_keyboard.go @@ -0,0 +1,11 @@ +//go:build linux && drm && drm_leasing && drm_disable_input && !rgfw && !sdl && !sdl3 && !android +// +build linux,drm,drm_leasing,drm_disable_input,!rgfw,!sdl,!sdl3,!android + +package rl + +/* +#cgo pkg-config: libdrm gbm wayland-client +#cgo linux,drm LDFLAGS: -lGLESv2 -lEGL -lpthread -lrt -lm -ldl +#cgo linux,drm CFLAGS: -DDISABLE_EVDEV_INPUT -DPLATFORM_DRM -DENABLE_WAYLAND_DRM_LEASING -DGRAPHICS_API_OPENGL_ES2 -DEGL_NO_X11 +*/ +import "C" diff --git a/raylib/cgo_linux_drm_no_keyboard.go b/raylib/cgo_linux_drm_no_keyboard.go new file mode 100644 index 0000000..12c329d --- /dev/null +++ b/raylib/cgo_linux_drm_no_keyboard.go @@ -0,0 +1,11 @@ +//go:build linux && drm && drm_disable_input && !drm_leasing && !rgfw && !sdl && !sdl3 && !android +// +build linux,drm,drm_disable_input,!drm_leasing,!rgfw,!sdl,!sdl3,!android + +package rl + +/* +#cgo pkg-config: libdrm gbm +#cgo linux,drm LDFLAGS: -lGLESv2 -lEGL -lpthread -lrt -lm -ldl +#cgo linux,drm CFLAGS: -DDISABLE_EVDEV_INPUT -DPLATFORM_DRM -DGRAPHICS_API_OPENGL_ES2 -DEGL_NO_X11 +*/ +import "C" diff --git a/raylib/config.h b/raylib/config.h index 0b3f5e7..c0d50cd 100644 --- a/raylib/config.h +++ b/raylib/config.h @@ -50,7 +50,7 @@ // Mouse gestures are directly mapped like touches and processed by gestures system #define SUPPORT_MOUSE_GESTURES 1 // Reconfigure standard input to receive key inputs, works with SSH connection. -#define SUPPORT_SSH_KEYBOARD_RPI 1 +//#define SUPPORT_SSH_KEYBOARD_RPI 1 // Setting a higher resolution can improve the accuracy of time-out intervals in wait functions. // However, it can also reduce overall system performance, because the thread scheduler switches tasks more often. #define SUPPORT_WINMM_HIGHRES_TIMER 1 diff --git a/raylib/platforms/drm-lease-v1.c b/raylib/platforms/drm-lease-v1.c new file mode 100644 index 0000000..5f75126 --- /dev/null +++ b/raylib/platforms/drm-lease-v1.c @@ -0,0 +1,116 @@ +/* Generated by wayland-scanner 1.23.1 */ + +/* + * Copyright © 2018 NXP + * Copyright © 2019 Status Research & Development GmbH. + * Copyright © 2021 Xaver Hugl + * + * 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 (including the next + * paragraph) 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 +#include +#include +#include "wayland-util.h" + +#ifndef __has_attribute +# define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */ +#endif + +#if (__has_attribute(visibility) || defined(__GNUC__) && __GNUC__ >= 4) +#define WL_PRIVATE __attribute__ ((visibility("hidden"))) +#else +#define WL_PRIVATE +#endif + +extern const struct wl_interface wp_drm_lease_connector_v1_interface; +extern const struct wl_interface wp_drm_lease_request_v1_interface; +extern const struct wl_interface wp_drm_lease_v1_interface; + +static const struct wl_interface *drm_lease_v1_types[] = { + NULL, + &wp_drm_lease_request_v1_interface, + &wp_drm_lease_connector_v1_interface, + &wp_drm_lease_connector_v1_interface, + &wp_drm_lease_v1_interface, +}; + +static const struct wl_message wp_drm_lease_device_v1_requests[] = { + { "create_lease_request", "n", drm_lease_v1_types + 1 }, + { "release", "", drm_lease_v1_types + 0 }, +}; + +static const struct wl_message wp_drm_lease_device_v1_events[] = { + { "drm_fd", "h", drm_lease_v1_types + 0 }, + { "connector", "n", drm_lease_v1_types + 2 }, + { "done", "", drm_lease_v1_types + 0 }, + { "released", "", drm_lease_v1_types + 0 }, +}; + +WL_PRIVATE const struct wl_interface wp_drm_lease_device_v1_interface = { + "wp_drm_lease_device_v1", 1, + 2, wp_drm_lease_device_v1_requests, + 4, wp_drm_lease_device_v1_events, +}; + +static const struct wl_message wp_drm_lease_connector_v1_requests[] = { + { "destroy", "", drm_lease_v1_types + 0 }, +}; + +static const struct wl_message wp_drm_lease_connector_v1_events[] = { + { "name", "s", drm_lease_v1_types + 0 }, + { "description", "s", drm_lease_v1_types + 0 }, + { "connector_id", "u", drm_lease_v1_types + 0 }, + { "done", "", drm_lease_v1_types + 0 }, + { "withdrawn", "", drm_lease_v1_types + 0 }, +}; + +WL_PRIVATE const struct wl_interface wp_drm_lease_connector_v1_interface = { + "wp_drm_lease_connector_v1", 1, + 1, wp_drm_lease_connector_v1_requests, + 5, wp_drm_lease_connector_v1_events, +}; + +static const struct wl_message wp_drm_lease_request_v1_requests[] = { + { "request_connector", "o", drm_lease_v1_types + 3 }, + { "submit", "n", drm_lease_v1_types + 4 }, +}; + +WL_PRIVATE const struct wl_interface wp_drm_lease_request_v1_interface = { + "wp_drm_lease_request_v1", 1, + 2, wp_drm_lease_request_v1_requests, + 0, NULL, +}; + +static const struct wl_message wp_drm_lease_v1_requests[] = { + { "destroy", "", drm_lease_v1_types + 0 }, +}; + +static const struct wl_message wp_drm_lease_v1_events[] = { + { "lease_fd", "h", drm_lease_v1_types + 0 }, + { "finished", "", drm_lease_v1_types + 0 }, +}; + +WL_PRIVATE const struct wl_interface wp_drm_lease_v1_interface = { + "wp_drm_lease_v1", 1, + 1, wp_drm_lease_v1_requests, + 2, wp_drm_lease_v1_events, +}; + diff --git a/raylib/platforms/drm-lease-v1.h b/raylib/platforms/drm-lease-v1.h new file mode 100644 index 0000000..ef24934 --- /dev/null +++ b/raylib/platforms/drm-lease-v1.h @@ -0,0 +1,743 @@ +/* Generated by wayland-scanner 1.23.1 */ + +#ifndef DRM_LEASE_V1_CLIENT_PROTOCOL_H +#define DRM_LEASE_V1_CLIENT_PROTOCOL_H + +#include +#include +#include "wayland-client.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @page page_drm_lease_v1 The drm_lease_v1 protocol + * @section page_ifaces_drm_lease_v1 Interfaces + * - @subpage page_iface_wp_drm_lease_device_v1 - lease device + * - @subpage page_iface_wp_drm_lease_connector_v1 - a leasable DRM connector + * - @subpage page_iface_wp_drm_lease_request_v1 - DRM lease request + * - @subpage page_iface_wp_drm_lease_v1 - a DRM lease + * @section page_copyright_drm_lease_v1 Copyright + *
+ *
+ * Copyright © 2018 NXP
+ * Copyright © 2019 Status Research & Development GmbH.
+ * Copyright © 2021 Xaver Hugl
+ *
+ * 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 (including the next
+ * paragraph) 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.
+ * 
+ */ +struct wp_drm_lease_connector_v1; +struct wp_drm_lease_device_v1; +struct wp_drm_lease_request_v1; +struct wp_drm_lease_v1; + +#ifndef WP_DRM_LEASE_DEVICE_V1_INTERFACE +#define WP_DRM_LEASE_DEVICE_V1_INTERFACE +/** + * @page page_iface_wp_drm_lease_device_v1 wp_drm_lease_device_v1 + * @section page_iface_wp_drm_lease_device_v1_desc Description + * + * This protocol is used by Wayland compositors which act as Direct + * Rendering Manager (DRM) masters to lease DRM resources to Wayland + * clients. + * + * The compositor will advertise one wp_drm_lease_device_v1 global for each + * DRM node. Some time after a client binds to the wp_drm_lease_device_v1 + * global, the compositor will send a drm_fd event followed by zero, one or + * more connector events. After all currently available connectors have been + * sent, the compositor will send a wp_drm_lease_device_v1.done event. + * + * When the list of connectors available for lease changes the compositor + * will send wp_drm_lease_device_v1.connector events for added connectors and + * wp_drm_lease_connector_v1.withdrawn events for removed connectors, + * followed by a wp_drm_lease_device_v1.done event. + * + * The compositor will indicate when a device is gone by removing the global + * via a wl_registry.global_remove event. Upon receiving this event, the + * client should destroy any matching wp_drm_lease_device_v1 object. + * + * To destroy a wp_drm_lease_device_v1 object, the client must first issue + * a release request. Upon receiving this request, the compositor will + * immediately send a released event and destroy the object. The client must + * continue to process and discard drm_fd and connector events until it + * receives the released event. Upon receiving the released event, the + * client can safely cleanup any client-side resources. + * + * Warning! The protocol described in this file is currently in the testing + * phase. Backward compatible changes may be added together with the + * corresponding interface version bump. Backward incompatible changes can + * only be done by creating a new major version of the extension. + * @section page_iface_wp_drm_lease_device_v1_api API + * See @ref iface_wp_drm_lease_device_v1. + */ +/** + * @defgroup iface_wp_drm_lease_device_v1 The wp_drm_lease_device_v1 interface + * + * This protocol is used by Wayland compositors which act as Direct + * Rendering Manager (DRM) masters to lease DRM resources to Wayland + * clients. + * + * The compositor will advertise one wp_drm_lease_device_v1 global for each + * DRM node. Some time after a client binds to the wp_drm_lease_device_v1 + * global, the compositor will send a drm_fd event followed by zero, one or + * more connector events. After all currently available connectors have been + * sent, the compositor will send a wp_drm_lease_device_v1.done event. + * + * When the list of connectors available for lease changes the compositor + * will send wp_drm_lease_device_v1.connector events for added connectors and + * wp_drm_lease_connector_v1.withdrawn events for removed connectors, + * followed by a wp_drm_lease_device_v1.done event. + * + * The compositor will indicate when a device is gone by removing the global + * via a wl_registry.global_remove event. Upon receiving this event, the + * client should destroy any matching wp_drm_lease_device_v1 object. + * + * To destroy a wp_drm_lease_device_v1 object, the client must first issue + * a release request. Upon receiving this request, the compositor will + * immediately send a released event and destroy the object. The client must + * continue to process and discard drm_fd and connector events until it + * receives the released event. Upon receiving the released event, the + * client can safely cleanup any client-side resources. + * + * Warning! The protocol described in this file is currently in the testing + * phase. Backward compatible changes may be added together with the + * corresponding interface version bump. Backward incompatible changes can + * only be done by creating a new major version of the extension. + */ +extern const struct wl_interface wp_drm_lease_device_v1_interface; +#endif +#ifndef WP_DRM_LEASE_CONNECTOR_V1_INTERFACE +#define WP_DRM_LEASE_CONNECTOR_V1_INTERFACE +/** + * @page page_iface_wp_drm_lease_connector_v1 wp_drm_lease_connector_v1 + * @section page_iface_wp_drm_lease_connector_v1_desc Description + * + * Represents a DRM connector which is available for lease. These objects are + * created via wp_drm_lease_device_v1.connector events, and should be passed + * to lease requests via wp_drm_lease_request_v1.request_connector. + * Immediately after the wp_drm_lease_connector_v1 object is created the + * compositor will send a name, a description, a connector_id and a done + * event. When the description is updated the compositor will send a + * description event followed by a done event. + * @section page_iface_wp_drm_lease_connector_v1_api API + * See @ref iface_wp_drm_lease_connector_v1. + */ +/** + * @defgroup iface_wp_drm_lease_connector_v1 The wp_drm_lease_connector_v1 interface + * + * Represents a DRM connector which is available for lease. These objects are + * created via wp_drm_lease_device_v1.connector events, and should be passed + * to lease requests via wp_drm_lease_request_v1.request_connector. + * Immediately after the wp_drm_lease_connector_v1 object is created the + * compositor will send a name, a description, a connector_id and a done + * event. When the description is updated the compositor will send a + * description event followed by a done event. + */ +extern const struct wl_interface wp_drm_lease_connector_v1_interface; +#endif +#ifndef WP_DRM_LEASE_REQUEST_V1_INTERFACE +#define WP_DRM_LEASE_REQUEST_V1_INTERFACE +/** + * @page page_iface_wp_drm_lease_request_v1 wp_drm_lease_request_v1 + * @section page_iface_wp_drm_lease_request_v1_desc Description + * + * A client that wishes to lease DRM resources will attach the list of + * connectors advertised with wp_drm_lease_device_v1.connector that they + * wish to lease, then use wp_drm_lease_request_v1.submit to submit the + * request. + * @section page_iface_wp_drm_lease_request_v1_api API + * See @ref iface_wp_drm_lease_request_v1. + */ +/** + * @defgroup iface_wp_drm_lease_request_v1 The wp_drm_lease_request_v1 interface + * + * A client that wishes to lease DRM resources will attach the list of + * connectors advertised with wp_drm_lease_device_v1.connector that they + * wish to lease, then use wp_drm_lease_request_v1.submit to submit the + * request. + */ +extern const struct wl_interface wp_drm_lease_request_v1_interface; +#endif +#ifndef WP_DRM_LEASE_V1_INTERFACE +#define WP_DRM_LEASE_V1_INTERFACE +/** + * @page page_iface_wp_drm_lease_v1 wp_drm_lease_v1 + * @section page_iface_wp_drm_lease_v1_desc Description + * + * A DRM lease object is used to transfer the DRM file descriptor to the + * client and manage the lifetime of the lease. + * + * Some time after the wp_drm_lease_v1 object is created, the compositor + * will reply with the lease request's result. If the lease request is + * granted, the compositor will send a lease_fd event. If the lease request + * is denied, the compositor will send a finished event without a lease_fd + * event. + * @section page_iface_wp_drm_lease_v1_api API + * See @ref iface_wp_drm_lease_v1. + */ +/** + * @defgroup iface_wp_drm_lease_v1 The wp_drm_lease_v1 interface + * + * A DRM lease object is used to transfer the DRM file descriptor to the + * client and manage the lifetime of the lease. + * + * Some time after the wp_drm_lease_v1 object is created, the compositor + * will reply with the lease request's result. If the lease request is + * granted, the compositor will send a lease_fd event. If the lease request + * is denied, the compositor will send a finished event without a lease_fd + * event. + */ +extern const struct wl_interface wp_drm_lease_v1_interface; +#endif + +/** + * @ingroup iface_wp_drm_lease_device_v1 + * @struct wp_drm_lease_device_v1_listener + */ +struct wp_drm_lease_device_v1_listener { + /** + * open a non-master fd for this DRM node + * + * The compositor will send this event when the + * wp_drm_lease_device_v1 global is bound, although there are no + * guarantees as to how long this takes - the compositor might need + * to wait until regaining DRM master. The included fd is a + * non-master DRM file descriptor opened for this device and the + * compositor must not authenticate it. The purpose of this event + * is to give the client the ability to query DRM and discover + * information which may help them pick the appropriate DRM device + * or select the appropriate connectors therein. + * @param fd DRM file descriptor + */ + void (*drm_fd)(void *data, + struct wp_drm_lease_device_v1 *wp_drm_lease_device_v1, + int32_t fd); + /** + * advertise connectors available for leases + * + * The compositor will use this event to advertise connectors + * available for lease by clients. This object may be passed into a + * lease request to indicate the client would like to lease that + * connector, see wp_drm_lease_request_v1.request_connector for + * details. While the compositor will make a best effort to not + * send disconnected connectors, no guarantees can be made. + * + * The compositor must send the drm_fd event before sending + * connectors. After the drm_fd event it will send all available + * connectors but may send additional connectors at any time. + */ + void (*connector)(void *data, + struct wp_drm_lease_device_v1 *wp_drm_lease_device_v1, + struct wp_drm_lease_connector_v1 *id); + /** + * signals grouping of connectors + * + * The compositor will send this event to indicate that it has + * sent all currently available connectors after the client binds + * to the global or when it updates the connector list, for example + * on hotplug, drm master change or when a leased connector becomes + * available again. It will similarly send this event to group + * wp_drm_lease_connector_v1.withdrawn events of connectors of this + * device. + */ + void (*done)(void *data, + struct wp_drm_lease_device_v1 *wp_drm_lease_device_v1); + /** + * the compositor has finished using the device + * + * This event is sent in response to the release request and + * indicates that the compositor is done sending connector events. + * The compositor will destroy this object immediately after + * sending the event and it will become invalid. The client should + * release any resources associated with this device after + * receiving this event. + */ + void (*released)(void *data, + struct wp_drm_lease_device_v1 *wp_drm_lease_device_v1); +}; + +/** + * @ingroup iface_wp_drm_lease_device_v1 + */ +static inline int +wp_drm_lease_device_v1_add_listener(struct wp_drm_lease_device_v1 *wp_drm_lease_device_v1, + const struct wp_drm_lease_device_v1_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) wp_drm_lease_device_v1, + (void (**)(void)) listener, data); +} + +#define WP_DRM_LEASE_DEVICE_V1_CREATE_LEASE_REQUEST 0 +#define WP_DRM_LEASE_DEVICE_V1_RELEASE 1 + +/** + * @ingroup iface_wp_drm_lease_device_v1 + */ +#define WP_DRM_LEASE_DEVICE_V1_DRM_FD_SINCE_VERSION 1 +/** + * @ingroup iface_wp_drm_lease_device_v1 + */ +#define WP_DRM_LEASE_DEVICE_V1_CONNECTOR_SINCE_VERSION 1 +/** + * @ingroup iface_wp_drm_lease_device_v1 + */ +#define WP_DRM_LEASE_DEVICE_V1_DONE_SINCE_VERSION 1 +/** + * @ingroup iface_wp_drm_lease_device_v1 + */ +#define WP_DRM_LEASE_DEVICE_V1_RELEASED_SINCE_VERSION 1 + +/** + * @ingroup iface_wp_drm_lease_device_v1 + */ +#define WP_DRM_LEASE_DEVICE_V1_CREATE_LEASE_REQUEST_SINCE_VERSION 1 +/** + * @ingroup iface_wp_drm_lease_device_v1 + */ +#define WP_DRM_LEASE_DEVICE_V1_RELEASE_SINCE_VERSION 1 + +/** @ingroup iface_wp_drm_lease_device_v1 */ +static inline void +wp_drm_lease_device_v1_set_user_data(struct wp_drm_lease_device_v1 *wp_drm_lease_device_v1, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) wp_drm_lease_device_v1, user_data); +} + +/** @ingroup iface_wp_drm_lease_device_v1 */ +static inline void * +wp_drm_lease_device_v1_get_user_data(struct wp_drm_lease_device_v1 *wp_drm_lease_device_v1) +{ + return wl_proxy_get_user_data((struct wl_proxy *) wp_drm_lease_device_v1); +} + +static inline uint32_t +wp_drm_lease_device_v1_get_version(struct wp_drm_lease_device_v1 *wp_drm_lease_device_v1) +{ + return wl_proxy_get_version((struct wl_proxy *) wp_drm_lease_device_v1); +} + +/** @ingroup iface_wp_drm_lease_device_v1 */ +static inline void +wp_drm_lease_device_v1_destroy(struct wp_drm_lease_device_v1 *wp_drm_lease_device_v1) +{ + wl_proxy_destroy((struct wl_proxy *) wp_drm_lease_device_v1); +} + +/** + * @ingroup iface_wp_drm_lease_device_v1 + * + * Creates a lease request object. + * + * See the documentation for wp_drm_lease_request_v1 for details. + */ +static inline struct wp_drm_lease_request_v1 * +wp_drm_lease_device_v1_create_lease_request(struct wp_drm_lease_device_v1 *wp_drm_lease_device_v1) +{ + struct wl_proxy *id; + + id = wl_proxy_marshal_flags((struct wl_proxy *) wp_drm_lease_device_v1, + WP_DRM_LEASE_DEVICE_V1_CREATE_LEASE_REQUEST, &wp_drm_lease_request_v1_interface, wl_proxy_get_version((struct wl_proxy *) wp_drm_lease_device_v1), 0, NULL); + + return (struct wp_drm_lease_request_v1 *) id; +} + +/** + * @ingroup iface_wp_drm_lease_device_v1 + * + * Indicates the client no longer wishes to use this object. In response + * the compositor will immediately send the released event and destroy + * this object. It can however not guarantee that the client won't receive + * connector events before the released event. The client must not send any + * requests after this one, doing so will raise a wl_display error. + * Existing connectors, lease request and leases will not be affected. + */ +static inline void +wp_drm_lease_device_v1_release(struct wp_drm_lease_device_v1 *wp_drm_lease_device_v1) +{ + wl_proxy_marshal_flags((struct wl_proxy *) wp_drm_lease_device_v1, + WP_DRM_LEASE_DEVICE_V1_RELEASE, NULL, wl_proxy_get_version((struct wl_proxy *) wp_drm_lease_device_v1), 0); +} + +/** + * @ingroup iface_wp_drm_lease_connector_v1 + * @struct wp_drm_lease_connector_v1_listener + */ +struct wp_drm_lease_connector_v1_listener { + /** + * name + * + * The compositor sends this event once the connector is created + * to indicate the name of this connector. This will not change for + * the duration of the Wayland session, but is not guaranteed to be + * consistent between sessions. + * + * If the compositor supports wl_output version 4 and this + * connector corresponds to a wl_output, the compositor should use + * the same name as for the wl_output. + * @param name connector name + */ + void (*name)(void *data, + struct wp_drm_lease_connector_v1 *wp_drm_lease_connector_v1, + const char *name); + /** + * description + * + * The compositor sends this event once the connector is created + * to provide a human-readable description for this connector, + * which may be presented to the user. The compositor may send this + * event multiple times over the lifetime of this object to reflect + * changes in the description. + * @param description connector description + */ + void (*description)(void *data, + struct wp_drm_lease_connector_v1 *wp_drm_lease_connector_v1, + const char *description); + /** + * connector_id + * + * The compositor sends this event once the connector is created + * to indicate the DRM object ID which represents the underlying + * connector that is being offered. Note that the final lease may + * include additional object IDs, such as CRTCs and planes. + * @param connector_id DRM connector ID + */ + void (*connector_id)(void *data, + struct wp_drm_lease_connector_v1 *wp_drm_lease_connector_v1, + uint32_t connector_id); + /** + * all properties have been sent + * + * This event is sent after all properties of a connector have + * been sent. This allows changes to the properties to be seen as + * atomic even if they happen via multiple events. + */ + void (*done)(void *data, + struct wp_drm_lease_connector_v1 *wp_drm_lease_connector_v1); + /** + * lease offer withdrawn + * + * Sent to indicate that the compositor will no longer honor + * requests for DRM leases which include this connector. The client + * may still issue a lease request including this connector, but + * the compositor will send wp_drm_lease_v1.finished without + * issuing a lease fd. Compositors are encouraged to send this + * event when they lose access to connector, for example when the + * connector is hot-unplugged, when the connector gets leased to a + * client or when the compositor loses DRM master. + * + * If a client holds a lease for the connector, the status of the + * lease remains the same. The client should destroy the object + * after receiving this event. + */ + void (*withdrawn)(void *data, + struct wp_drm_lease_connector_v1 *wp_drm_lease_connector_v1); +}; + +/** + * @ingroup iface_wp_drm_lease_connector_v1 + */ +static inline int +wp_drm_lease_connector_v1_add_listener(struct wp_drm_lease_connector_v1 *wp_drm_lease_connector_v1, + const struct wp_drm_lease_connector_v1_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) wp_drm_lease_connector_v1, + (void (**)(void)) listener, data); +} + +#define WP_DRM_LEASE_CONNECTOR_V1_DESTROY 0 + +/** + * @ingroup iface_wp_drm_lease_connector_v1 + */ +#define WP_DRM_LEASE_CONNECTOR_V1_NAME_SINCE_VERSION 1 +/** + * @ingroup iface_wp_drm_lease_connector_v1 + */ +#define WP_DRM_LEASE_CONNECTOR_V1_DESCRIPTION_SINCE_VERSION 1 +/** + * @ingroup iface_wp_drm_lease_connector_v1 + */ +#define WP_DRM_LEASE_CONNECTOR_V1_CONNECTOR_ID_SINCE_VERSION 1 +/** + * @ingroup iface_wp_drm_lease_connector_v1 + */ +#define WP_DRM_LEASE_CONNECTOR_V1_DONE_SINCE_VERSION 1 +/** + * @ingroup iface_wp_drm_lease_connector_v1 + */ +#define WP_DRM_LEASE_CONNECTOR_V1_WITHDRAWN_SINCE_VERSION 1 + +/** + * @ingroup iface_wp_drm_lease_connector_v1 + */ +#define WP_DRM_LEASE_CONNECTOR_V1_DESTROY_SINCE_VERSION 1 + +/** @ingroup iface_wp_drm_lease_connector_v1 */ +static inline void +wp_drm_lease_connector_v1_set_user_data(struct wp_drm_lease_connector_v1 *wp_drm_lease_connector_v1, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) wp_drm_lease_connector_v1, user_data); +} + +/** @ingroup iface_wp_drm_lease_connector_v1 */ +static inline void * +wp_drm_lease_connector_v1_get_user_data(struct wp_drm_lease_connector_v1 *wp_drm_lease_connector_v1) +{ + return wl_proxy_get_user_data((struct wl_proxy *) wp_drm_lease_connector_v1); +} + +static inline uint32_t +wp_drm_lease_connector_v1_get_version(struct wp_drm_lease_connector_v1 *wp_drm_lease_connector_v1) +{ + return wl_proxy_get_version((struct wl_proxy *) wp_drm_lease_connector_v1); +} + +/** + * @ingroup iface_wp_drm_lease_connector_v1 + * + * The client may send this request to indicate that it will not use this + * connector. Clients are encouraged to send this after receiving the + * "withdrawn" event so that the server can release the resources + * associated with this connector offer. Neither existing lease requests + * nor leases will be affected. + */ +static inline void +wp_drm_lease_connector_v1_destroy(struct wp_drm_lease_connector_v1 *wp_drm_lease_connector_v1) +{ + wl_proxy_marshal_flags((struct wl_proxy *) wp_drm_lease_connector_v1, + WP_DRM_LEASE_CONNECTOR_V1_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) wp_drm_lease_connector_v1), WL_MARSHAL_FLAG_DESTROY); +} + +#ifndef WP_DRM_LEASE_REQUEST_V1_ERROR_ENUM +#define WP_DRM_LEASE_REQUEST_V1_ERROR_ENUM +enum wp_drm_lease_request_v1_error { + /** + * requested a connector from a different lease device + */ + WP_DRM_LEASE_REQUEST_V1_ERROR_WRONG_DEVICE = 0, + /** + * requested a connector twice + */ + WP_DRM_LEASE_REQUEST_V1_ERROR_DUPLICATE_CONNECTOR = 1, + /** + * requested a lease without requesting a connector + */ + WP_DRM_LEASE_REQUEST_V1_ERROR_EMPTY_LEASE = 2, +}; +#endif /* WP_DRM_LEASE_REQUEST_V1_ERROR_ENUM */ + +#define WP_DRM_LEASE_REQUEST_V1_REQUEST_CONNECTOR 0 +#define WP_DRM_LEASE_REQUEST_V1_SUBMIT 1 + + +/** + * @ingroup iface_wp_drm_lease_request_v1 + */ +#define WP_DRM_LEASE_REQUEST_V1_REQUEST_CONNECTOR_SINCE_VERSION 1 +/** + * @ingroup iface_wp_drm_lease_request_v1 + */ +#define WP_DRM_LEASE_REQUEST_V1_SUBMIT_SINCE_VERSION 1 + +/** @ingroup iface_wp_drm_lease_request_v1 */ +static inline void +wp_drm_lease_request_v1_set_user_data(struct wp_drm_lease_request_v1 *wp_drm_lease_request_v1, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) wp_drm_lease_request_v1, user_data); +} + +/** @ingroup iface_wp_drm_lease_request_v1 */ +static inline void * +wp_drm_lease_request_v1_get_user_data(struct wp_drm_lease_request_v1 *wp_drm_lease_request_v1) +{ + return wl_proxy_get_user_data((struct wl_proxy *) wp_drm_lease_request_v1); +} + +static inline uint32_t +wp_drm_lease_request_v1_get_version(struct wp_drm_lease_request_v1 *wp_drm_lease_request_v1) +{ + return wl_proxy_get_version((struct wl_proxy *) wp_drm_lease_request_v1); +} + +/** @ingroup iface_wp_drm_lease_request_v1 */ +static inline void +wp_drm_lease_request_v1_destroy(struct wp_drm_lease_request_v1 *wp_drm_lease_request_v1) +{ + wl_proxy_destroy((struct wl_proxy *) wp_drm_lease_request_v1); +} + +/** + * @ingroup iface_wp_drm_lease_request_v1 + * + * Indicates that the client would like to lease the given connector. + * This is only used as a suggestion, the compositor may choose to + * include any resources in the lease it issues, or change the set of + * leased resources at any time. Compositors are however encouraged to + * include the requested connector and other resources necessary + * to drive the connected output in the lease. + * + * Requesting a connector that was created from a different lease device + * than this lease request raises the wrong_device error. Requesting a + * connector twice will raise the duplicate_connector error. + */ +static inline void +wp_drm_lease_request_v1_request_connector(struct wp_drm_lease_request_v1 *wp_drm_lease_request_v1, struct wp_drm_lease_connector_v1 *connector) +{ + wl_proxy_marshal_flags((struct wl_proxy *) wp_drm_lease_request_v1, + WP_DRM_LEASE_REQUEST_V1_REQUEST_CONNECTOR, NULL, wl_proxy_get_version((struct wl_proxy *) wp_drm_lease_request_v1), 0, connector); +} + +/** + * @ingroup iface_wp_drm_lease_request_v1 + * + * Submits the lease request and creates a new wp_drm_lease_v1 object. + * After calling submit the compositor will immediately destroy this + * object, issuing any more requests will cause a wl_display error. + * The compositor doesn't make any guarantees about the events of the + * lease object, clients cannot expect an immediate response. + * Not requesting any connectors before submitting the lease request + * will raise the empty_lease error. + */ +static inline struct wp_drm_lease_v1 * +wp_drm_lease_request_v1_submit(struct wp_drm_lease_request_v1 *wp_drm_lease_request_v1) +{ + struct wl_proxy *id; + + id = wl_proxy_marshal_flags((struct wl_proxy *) wp_drm_lease_request_v1, + WP_DRM_LEASE_REQUEST_V1_SUBMIT, &wp_drm_lease_v1_interface, wl_proxy_get_version((struct wl_proxy *) wp_drm_lease_request_v1), WL_MARSHAL_FLAG_DESTROY, NULL); + + return (struct wp_drm_lease_v1 *) id; +} + +/** + * @ingroup iface_wp_drm_lease_v1 + * @struct wp_drm_lease_v1_listener + */ +struct wp_drm_lease_v1_listener { + /** + * shares the DRM file descriptor + * + * This event returns a file descriptor suitable for use with + * DRM-related ioctls. The client should use drmModeGetLease to + * enumerate the DRM objects which have been leased to them. The + * compositor guarantees it will not use the leased DRM objects + * itself until it sends the finished event. If the compositor + * cannot or will not grant a lease for the requested connectors, + * it will not send this event, instead sending the finished event. + * + * The compositor will send this event at most once during this + * objects lifetime. + * @param leased_fd leased DRM file descriptor + */ + void (*lease_fd)(void *data, + struct wp_drm_lease_v1 *wp_drm_lease_v1, + int32_t leased_fd); + /** + * sent when the lease has been revoked + * + * The compositor uses this event to either reject a lease + * request, or if it previously sent a lease_fd, to notify the + * client that the lease has been revoked. If the client requires a + * new lease, they should destroy this object and submit a new + * lease request. The compositor will send no further events for + * this object after sending the finish event. Compositors should + * revoke the lease when any of the leased resources become + * unavailable, namely when a hot-unplug occurs or when the + * compositor loses DRM master. Compositors may advertise the + * connector for leasing again, if the resource is available, by + * sending the connector event through the wp_drm_lease_device_v1 + * interface. + */ + void (*finished)(void *data, + struct wp_drm_lease_v1 *wp_drm_lease_v1); +}; + +/** + * @ingroup iface_wp_drm_lease_v1 + */ +static inline int +wp_drm_lease_v1_add_listener(struct wp_drm_lease_v1 *wp_drm_lease_v1, + const struct wp_drm_lease_v1_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) wp_drm_lease_v1, + (void (**)(void)) listener, data); +} + +#define WP_DRM_LEASE_V1_DESTROY 0 + +/** + * @ingroup iface_wp_drm_lease_v1 + */ +#define WP_DRM_LEASE_V1_LEASE_FD_SINCE_VERSION 1 +/** + * @ingroup iface_wp_drm_lease_v1 + */ +#define WP_DRM_LEASE_V1_FINISHED_SINCE_VERSION 1 + +/** + * @ingroup iface_wp_drm_lease_v1 + */ +#define WP_DRM_LEASE_V1_DESTROY_SINCE_VERSION 1 + +/** @ingroup iface_wp_drm_lease_v1 */ +static inline void +wp_drm_lease_v1_set_user_data(struct wp_drm_lease_v1 *wp_drm_lease_v1, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) wp_drm_lease_v1, user_data); +} + +/** @ingroup iface_wp_drm_lease_v1 */ +static inline void * +wp_drm_lease_v1_get_user_data(struct wp_drm_lease_v1 *wp_drm_lease_v1) +{ + return wl_proxy_get_user_data((struct wl_proxy *) wp_drm_lease_v1); +} + +static inline uint32_t +wp_drm_lease_v1_get_version(struct wp_drm_lease_v1 *wp_drm_lease_v1) +{ + return wl_proxy_get_version((struct wl_proxy *) wp_drm_lease_v1); +} + +/** + * @ingroup iface_wp_drm_lease_v1 + * + * The client should send this to indicate that it no longer wishes to use + * this lease. The compositor should use drmModeRevokeLease on the + * appropriate file descriptor, if necessary. + * + * Upon destruction, the compositor should advertise the connector for + * leasing again by sending the connector event through the + * wp_drm_lease_device_v1 interface. + */ +static inline void +wp_drm_lease_v1_destroy(struct wp_drm_lease_v1 *wp_drm_lease_v1) +{ + wl_proxy_marshal_flags((struct wl_proxy *) wp_drm_lease_v1, + WP_DRM_LEASE_V1_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) wp_drm_lease_v1), WL_MARSHAL_FLAG_DESTROY); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/raylib/platforms/drm-lease-v1.xml b/raylib/platforms/drm-lease-v1.xml new file mode 100644 index 0000000..1fca538 --- /dev/null +++ b/raylib/platforms/drm-lease-v1.xml @@ -0,0 +1,317 @@ + + + + Copyright © 2018 NXP + Copyright © 2019 Status Research & Development GmbH. + Copyright © 2021 Xaver Hugl + + 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 (including the next + paragraph) 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. + + + + + This protocol is used by Wayland compositors which act as Direct + Rendering Manager (DRM) masters to lease DRM resources to Wayland + clients. + + The compositor will advertise one wp_drm_lease_device_v1 global for each + DRM node. Some time after a client binds to the wp_drm_lease_device_v1 + global, the compositor will send a drm_fd event followed by zero, one or + more connector events. After all currently available connectors have been + sent, the compositor will send a wp_drm_lease_device_v1.done event. + + When the list of connectors available for lease changes the compositor + will send wp_drm_lease_device_v1.connector events for added connectors and + wp_drm_lease_connector_v1.withdrawn events for removed connectors, + followed by a wp_drm_lease_device_v1.done event. + + The compositor will indicate when a device is gone by removing the global + via a wl_registry.global_remove event. Upon receiving this event, the + client should destroy any matching wp_drm_lease_device_v1 object. + + To destroy a wp_drm_lease_device_v1 object, the client must first issue + a release request. Upon receiving this request, the compositor will + immediately send a released event and destroy the object. The client must + continue to process and discard drm_fd and connector events until it + receives the released event. Upon receiving the released event, the + client can safely cleanup any client-side resources. + + Warning! The protocol described in this file is currently in the testing + phase. Backward compatible changes may be added together with the + corresponding interface version bump. Backward incompatible changes can + only be done by creating a new major version of the extension. + + + + + Creates a lease request object. + + See the documentation for wp_drm_lease_request_v1 for details. + + + + + + + Indicates the client no longer wishes to use this object. In response + the compositor will immediately send the released event and destroy + this object. It can however not guarantee that the client won't receive + connector events before the released event. The client must not send any + requests after this one, doing so will raise a wl_display error. + Existing connectors, lease request and leases will not be affected. + + + + + + The compositor will send this event when the wp_drm_lease_device_v1 + global is bound, although there are no guarantees as to how long this + takes - the compositor might need to wait until regaining DRM master. + The included fd is a non-master DRM file descriptor opened for this + device and the compositor must not authenticate it. + The purpose of this event is to give the client the ability to + query DRM and discover information which may help them pick the + appropriate DRM device or select the appropriate connectors therein. + + + + + + + The compositor will use this event to advertise connectors available for + lease by clients. This object may be passed into a lease request to + indicate the client would like to lease that connector, see + wp_drm_lease_request_v1.request_connector for details. While the + compositor will make a best effort to not send disconnected connectors, + no guarantees can be made. + + The compositor must send the drm_fd event before sending connectors. + After the drm_fd event it will send all available connectors but may + send additional connectors at any time. + + + + + + + The compositor will send this event to indicate that it has sent all + currently available connectors after the client binds to the global or + when it updates the connector list, for example on hotplug, drm master + change or when a leased connector becomes available again. It will + similarly send this event to group wp_drm_lease_connector_v1.withdrawn + events of connectors of this device. + + + + + + This event is sent in response to the release request and indicates + that the compositor is done sending connector events. + The compositor will destroy this object immediately after sending the + event and it will become invalid. The client should release any + resources associated with this device after receiving this event. + + + + + + + Represents a DRM connector which is available for lease. These objects are + created via wp_drm_lease_device_v1.connector events, and should be passed + to lease requests via wp_drm_lease_request_v1.request_connector. + Immediately after the wp_drm_lease_connector_v1 object is created the + compositor will send a name, a description, a connector_id and a done + event. When the description is updated the compositor will send a + description event followed by a done event. + + + + + The compositor sends this event once the connector is created to + indicate the name of this connector. This will not change for the + duration of the Wayland session, but is not guaranteed to be consistent + between sessions. + + If the compositor supports wl_output version 4 and this connector + corresponds to a wl_output, the compositor should use the same name as + for the wl_output. + + + + + + + The compositor sends this event once the connector is created to provide + a human-readable description for this connector, which may be presented + to the user. The compositor may send this event multiple times over the + lifetime of this object to reflect changes in the description. + + + + + + + The compositor sends this event once the connector is created to + indicate the DRM object ID which represents the underlying connector + that is being offered. Note that the final lease may include additional + object IDs, such as CRTCs and planes. + + + + + + + This event is sent after all properties of a connector have been sent. + This allows changes to the properties to be seen as atomic even if they + happen via multiple events. + + + + + + Sent to indicate that the compositor will no longer honor requests for + DRM leases which include this connector. The client may still issue a + lease request including this connector, but the compositor will send + wp_drm_lease_v1.finished without issuing a lease fd. Compositors are + encouraged to send this event when they lose access to connector, for + example when the connector is hot-unplugged, when the connector gets + leased to a client or when the compositor loses DRM master. + + If a client holds a lease for the connector, the status of the lease + remains the same. The client should destroy the object after receiving + this event. + + + + + + The client may send this request to indicate that it will not use this + connector. Clients are encouraged to send this after receiving the + "withdrawn" event so that the server can release the resources + associated with this connector offer. Neither existing lease requests + nor leases will be affected. + + + + + + + A client that wishes to lease DRM resources will attach the list of + connectors advertised with wp_drm_lease_device_v1.connector that they + wish to lease, then use wp_drm_lease_request_v1.submit to submit the + request. + + + + + + + + + + + Indicates that the client would like to lease the given connector. + This is only used as a suggestion, the compositor may choose to + include any resources in the lease it issues, or change the set of + leased resources at any time. Compositors are however encouraged to + include the requested connector and other resources necessary + to drive the connected output in the lease. + + Requesting a connector that was created from a different lease device + than this lease request raises the wrong_device error. Requesting a + connector twice will raise the duplicate_connector error. + + + + + + + Submits the lease request and creates a new wp_drm_lease_v1 object. + After calling submit the compositor will immediately destroy this + object, issuing any more requests will cause a wl_display error. + The compositor doesn't make any guarantees about the events of the + lease object, clients cannot expect an immediate response. + Not requesting any connectors before submitting the lease request + will raise the empty_lease error. + + + + + + + + A DRM lease object is used to transfer the DRM file descriptor to the + client and manage the lifetime of the lease. + + Some time after the wp_drm_lease_v1 object is created, the compositor + will reply with the lease request's result. If the lease request is + granted, the compositor will send a lease_fd event. If the lease request + is denied, the compositor will send a finished event without a lease_fd + event. + + + + + This event returns a file descriptor suitable for use with DRM-related + ioctls. The client should use drmModeGetLease to enumerate the DRM + objects which have been leased to them. The compositor guarantees it + will not use the leased DRM objects itself until it sends the finished + event. If the compositor cannot or will not grant a lease for the + requested connectors, it will not send this event, instead sending the + finished event. + + The compositor will send this event at most once during this objects + lifetime. + + + + + + + The compositor uses this event to either reject a lease request, or if + it previously sent a lease_fd, to notify the client that the lease has + been revoked. If the client requires a new lease, they should destroy + this object and submit a new lease request. The compositor will send + no further events for this object after sending the finish event. + Compositors should revoke the lease when any of the leased resources + become unavailable, namely when a hot-unplug occurs or when the + compositor loses DRM master. Compositors may advertise the connector + for leasing again, if the resource is available, by sending the + connector event through the wp_drm_lease_device_v1 interface. + + + + + + The client should send this to indicate that it no longer wishes to use + this lease. The compositor should use drmModeRevokeLease on the + appropriate file descriptor, if necessary. + + Upon destruction, the compositor should advertise the connector for + leasing again by sending the connector event through the + wp_drm_lease_device_v1 interface. + + + + diff --git a/raylib/platforms/rcore_drm.c b/raylib/platforms/rcore_drm.c index 49cab3b..20d676e 100644 --- a/raylib/platforms/rcore_drm.c +++ b/raylib/platforms/rcore_drm.c @@ -21,10 +21,19 @@ * Reconfigure standard input to receive key inputs, works with SSH connection. * WARNING: Reconfiguring standard input could lead to undesired effects, like breaking other * running processes orblocking the device if not restored properly. Use with care. +* #define ENABLE_WAYLAND_DRM_LEASING +* Instead of acquiring DRM exclusively, this leases a DRM instance from the currently running +* Wayland compositor. This requires the screen to have the non-desktop property, which is set +* through EDIDs. X11 is not supported, but it may be in the future. +* See: +* https://learn.microsoft.com/en-us/windows-hardware/drivers/display/specialized-monitors-edid-extension * * DEPENDENCIES: * - DRM and GLM: System libraries for display initialization and configuration * - gestures: Gestures system for touch-ready devices (or simulated from mouse inputs) +* - wayland-client: Needed for DRM leasing. Only used if ENABLE_WAYLAND_DRM_LEASING is set. +* - drm-lease-v1: Generated Wayland code for the DRM leasing extension. Only used if +* ENABLE_WAYLAND_DRM_LEASING is set. * * * LICENSE: zlib/libpng @@ -71,6 +80,13 @@ #include "EGL/egl.h" // Native platform windowing system interface #include "EGL/eglext.h" // EGL extensions +#if defined(ENABLE_WAYLAND_DRM_LEASING) + #include "wayland-client.h" // Wayland client. Used to do DRM leasing. + // DRM leasing protocol that's used + #include "drm-lease-v1.c" + #include "drm-lease-v1.h" +#endif + #ifndef EGL_OPENGL_ES3_BIT #define EGL_OPENGL_ES3_BIT 0x40 #endif @@ -128,6 +144,10 @@ typedef struct { int gamepadAbsAxisRange[MAX_GAMEPADS][MAX_GAMEPAD_AXES][2]; // [0] = min, [1] = range value of the axes int gamepadAbsAxisMap[MAX_GAMEPADS][ABS_CNT]; // Maps the axes gamepads from the evdev api to a sequential one int gamepadCount; // The number of gamepads registered + + #if defined(ENABLE_WAYLAND_DRM_LEASING) + bool usingDRMLeasing; // True if we are using DRM leasing + #endif } PlatformData; //---------------------------------------------------------------------------------- @@ -717,10 +737,200 @@ void PollInputEvents(void) // Module Internal Functions Definition //---------------------------------------------------------------------------------- +#if defined(ENABLE_WAYLAND_DRM_LEASING) + // Wayland state for DRM leasing + struct wayland_state { + struct wp_drm_lease_device_v1 *lease_device; + struct wp_drm_lease_connector_v1 *lease_connector; + }; + + // Called when we get a potential DRM lease + void lease_handler(void *data, struct wp_drm_lease_v1 *wp_drm_lease_v1, int32_t leased_fd) + { + int *fd = data; + *fd = leased_fd; + } + + void lease_remove_handler(void *data, struct wp_drm_lease_v1 *wp_drm_lease_v1) + { + // Do nothing + } + + static const struct wp_drm_lease_v1_listener lease_listener = { + .lease_fd = lease_handler, + .finished = lease_remove_handler, + }; + + // Called when we get a potential DRM lease + static void lease_device_fd_handler(void *data, struct wp_drm_lease_device_v1 *lease_device, int fd) + { + close(fd); + } + + // Called when we get a lease connector + static void lease_device_connector_handler(void *data, struct wp_drm_lease_device_v1 *lease_device, struct wp_drm_lease_connector_v1 *conn) + { + struct wayland_state *state = data; + + if (!state->lease_connector) { + state->lease_connector = conn; + } + } + + static void lease_device_on_done(void *data, struct wp_drm_lease_device_v1 *lease_device) + { + // Do nothing + } + + static void lease_device_on_release(void *data, struct wp_drm_lease_device_v1 *lease_device) + { + // Do nothing + } + + static const struct wp_drm_lease_device_v1_listener lease_manager_listener = { + .drm_fd = lease_device_fd_handler, + .connector = lease_device_connector_handler, + .done = lease_device_on_done, + .released = lease_device_on_release, + }; + + // Listen for protocol list/dump + static void registry_handler(void *data, struct wl_registry *registry, uint32_t name, const char *interface, uint32_t version) + { + struct wayland_state *state = data; + + if (strcmp(interface, "wp_drm_lease_device_v1") == 0) { + state->lease_device = wl_registry_bind(registry, name, &wp_drm_lease_device_v1_interface, version); + wp_drm_lease_device_v1_add_listener(state->lease_device, &lease_manager_listener, state); + } + } + + // Listen for remove event + static void registry_remove_handler(void *data, struct wl_registry *registry, uint32_t name) + { + // Do nothing + } + + static const struct wl_registry_listener registry_listener = { + .global = registry_handler, + .global_remove = registry_remove_handler, + }; + + // Get the DRM device's file descriptor via DRM leasing. Seperate function due to readability concerns + int GetDRMFDViaWaylandLeasing(void) + { + int fd = -1; + + // Connect to the potentially running Wayland instance + struct wayland_state state = { 0 }; + struct wl_display *display = wl_display_connect(NULL); + + if (!display) + { + TRACELOG(LOG_WARNING, "DISPLAY: Failed to connect to Wayland server for DRM leasing! Is Wayland running? Cannot do DRM leasing"); + return -1; + } + + // Check the Wayland registry to determine if the DRM leasing protocol (wp_drm_lease_device_v1) is supported. If so, get the lease device and connector. + struct wl_registry *registry = wl_display_get_registry(display); + wl_registry_add_listener(registry, ®istry_listener, &state); + wl_display_dispatch(display); + wl_display_roundtrip(display); + + if (!state.lease_device) { + TRACELOG(LOG_WARNING, "DISPLAY: Failed to acquire leasing device"); + return -1; + } + + if (!state.lease_connector) { + TRACELOG(LOG_WARNING, "DISPLAY: No connectors offered for lease"); + return -1; + } + + struct wp_drm_lease_request_v1 *req = wp_drm_lease_device_v1_create_lease_request(state.lease_device); + wp_drm_lease_request_v1_request_connector(req, state.lease_connector); + + struct wp_drm_lease_v1 *lease = wp_drm_lease_request_v1_submit(req); + wp_drm_lease_v1_add_listener(lease, &lease_listener, &fd); + wl_display_dispatch(display); + wl_display_roundtrip(display); + + if (fd < 0) { + TRACELOG(LOG_WARNING, "DISPLAY: DRM file descriptor is not set. Cannot use DRM leased value"); + return -1; + } + + return fd; + } +#endif + +// Get the DRM device's file descriptor +int GetDRMFD(void) +{ + int fd; + + #if defined(ENABLE_WAYLAND_DRM_LEASING) + TRACELOG(LOG_INFO, "DISPLAY: Attempting Wayland DRM leasing"); + fd = GetDRMFDViaWaylandLeasing(); + + if (fd != -1) + { + TRACELOG(LOG_INFO, "DISPLAY: Leased DRM device opened successfully"); + platform.usingDRMLeasing = true; + return fd; + } + #endif + + #if defined(DEFAULT_GRAPHIC_DEVICE_DRM) + fd = open(DEFAULT_GRAPHIC_DEVICE_DRM, O_RDWR); + + if (fd != -1) + { + TRACELOG(LOG_INFO, "DISPLAY: Default graphic device DRM opened successfully"); + return fd; + } + #else + TRACELOG(LOG_WARNING, "DISPLAY: No graphic card set, trying platform-gpu-card"); + fd = open("/dev/dri/by-path/platform-gpu-card", O_RDWR); // VideoCore VI (Raspberry Pi 4) + + if (fd != -1) + { + TRACELOG(LOG_INFO, "DISPLAY: platform-gpu-card opened successfully"); + return fd; + } + + if (drmModeGetResources(fd) == NULL) + { + TRACELOG(LOG_WARNING, "DISPLAY: Failed to open platform-gpu-card, trying card1"); + fd = open("/dev/dri/card1", O_RDWR); // Other Embedded + + if (fd != -1) + { + TRACELOG(LOG_INFO, "DISPLAY: card1 opened successfully"); + return fd; + } + } + + if (drmModeGetResources(fd) == NULL) + { + TRACELOG(LOG_WARNING, "DISPLAY: Failed to open graphic card1, trying card0"); + fd = open("/dev/dri/card0", O_RDWR); // VideoCore IV (Raspberry Pi 1-3) + + if (fd != -1) + { + TRACELOG(LOG_INFO, "DISPLAY: card0 opened successfully"); + return fd; + } + } + #endif + + return fd; +} + // Initialize platform: graphics, inputs and more int InitPlatform(void) { - platform.fd = -1; + platform.fd = GetDRMFD(); platform.connector = NULL; platform.modeIndex = -1; platform.crtc = NULL; @@ -734,29 +944,6 @@ int InitPlatform(void) CORE.Window.fullscreen = true; CORE.Window.flags |= FLAG_FULLSCREEN_MODE; -#if defined(DEFAULT_GRAPHIC_DEVICE_DRM) - platform.fd = open(DEFAULT_GRAPHIC_DEVICE_DRM, O_RDWR); - if (platform.fd != -1) TRACELOG(LOG_INFO, "DISPLAY: Default graphic device DRM opened successfully"); -#else - TRACELOG(LOG_WARNING, "DISPLAY: No graphic card set, trying platform-gpu-card"); - platform.fd = open("/dev/dri/by-path/platform-gpu-card", O_RDWR); // VideoCore VI (Raspberry Pi 4) - if (platform.fd != -1) TRACELOG(LOG_INFO, "DISPLAY: platform-gpu-card opened successfully"); - - if ((platform.fd == -1) || (drmModeGetResources(platform.fd) == NULL)) - { - TRACELOG(LOG_WARNING, "DISPLAY: Failed to open platform-gpu-card, trying card1"); - platform.fd = open("/dev/dri/card1", O_RDWR); // Other Embedded - if (platform.fd != -1) TRACELOG(LOG_INFO, "DISPLAY: card1 opened successfully"); - } - - if ((platform.fd == -1) || (drmModeGetResources(platform.fd) == NULL)) - { - TRACELOG(LOG_WARNING, "DISPLAY: Failed to open graphic card1, trying card0"); - platform.fd = open("/dev/dri/card0", O_RDWR); // VideoCore IV (Raspberry Pi 1-3) - if (platform.fd != -1) TRACELOG(LOG_INFO, "DISPLAY: card0 opened successfully"); - } -#endif - if (platform.fd == -1) { TRACELOG(LOG_WARNING, "DISPLAY: Failed to open graphic card"); @@ -781,17 +968,48 @@ int InitPlatform(void) // In certain cases the status of the conneciton is reported as UKNOWN, but it is still connected. // This might be a hardware or software limitation like on Raspberry Pi Zero with composite output. - if (((con->connection == DRM_MODE_CONNECTED) || (con->connection == DRM_MODE_UNKNOWNCONNECTION)) && (con->encoder_id)) - { - TRACELOG(LOG_TRACE, "DISPLAY: DRM mode connected"); - platform.connector = con; - break; - } - else - { - TRACELOG(LOG_TRACE, "DISPLAY: DRM mode NOT connected (deleting)"); - drmModeFreeConnector(con); - } + #if defined(ENABLE_WAYLAND_DRM_LEASING) + if (platform.usingDRMLeasing) + { + if (((con->connection == DRM_MODE_CONNECTED) || (con->connection == DRM_MODE_UNKNOWNCONNECTION))) + { + TRACELOG(LOG_TRACE, "DISPLAY: DRM mode connected"); + platform.connector = con; + break; + } + else + { + TRACELOG(LOG_TRACE, "DISPLAY: DRM mode NOT connected (deleting)"); + drmModeFreeConnector(con); + } + } + else + { + if (((con->connection == DRM_MODE_CONNECTED) || (con->connection == DRM_MODE_UNKNOWNCONNECTION)) && (con->encoder_id)) + { + TRACELOG(LOG_TRACE, "DISPLAY: DRM mode connected"); + platform.connector = con; + break; + } + else + { + TRACELOG(LOG_TRACE, "DISPLAY: DRM mode NOT connected (deleting)"); + drmModeFreeConnector(con); + } + } + #else + if (((con->connection == DRM_MODE_CONNECTED) || (con->connection == DRM_MODE_UNKNOWNCONNECTION)) && (con->encoder_id)) + { + TRACELOG(LOG_TRACE, "DISPLAY: DRM mode connected"); + platform.connector = con; + break; + } + else + { + TRACELOG(LOG_TRACE, "DISPLAY: DRM mode NOT connected (deleting)"); + drmModeFreeConnector(con); + } + #endif } if (!platform.connector) @@ -801,22 +1019,83 @@ int InitPlatform(void) return -1; } - drmModeEncoder *enc = drmModeGetEncoder(platform.fd, platform.connector->encoder_id); - if (!enc) - { - TRACELOG(LOG_WARNING, "DISPLAY: Failed to get DRM mode encoder"); - drmModeFreeResources(res); - return -1; - } + #if defined(ENABLE_WAYLAND_DRM_LEASING) + drmModeEncoder *enc = NULL; - platform.crtc = drmModeGetCrtc(platform.fd, enc->crtc_id); - if (!platform.crtc) - { - TRACELOG(LOG_WARNING, "DISPLAY: Failed to get DRM mode crtc"); - drmModeFreeEncoder(enc); - drmModeFreeResources(res); - return -1; - } + if (platform.usingDRMLeasing) + { + drmModeResPtr drm_resources = drmModeGetResources(platform.fd); + + if (!drm_resources) + { + TRACELOG(LOG_WARNING, "DISPLAY: Failed to get DRM resources"); + drmModeFreeResources(res); + return -1; + } + + if (res->count_crtcs == 0) + { + TRACELOG(LOG_WARNING, "DISPLAY: No CRTCs found for display"); + } + + for (size_t i = 0; i < res->count_crtcs; ++i) + { + platform.crtc = drmModeGetCrtc(platform.fd, res->crtcs[i]); + + if (!platform.crtc) + { + TRACELOG(LOG_WARNING, "DISPLAY: Failed to get DRM mode crtc"); + drmModeFreeResources(drm_resources); + drmModeFreeResources(res); + return -1; + } + } + + if (!platform.crtc) + { + TRACELOG(LOG_WARNING, "DISPLAY: Failed to get DRM mode crtc"); + drmModeFreeResources(drm_resources); + drmModeFreeResources(res); + return -1; + } + } + else + { + enc = drmModeGetEncoder(platform.fd, platform.connector->encoder_id); + if (!enc) + { + TRACELOG(LOG_WARNING, "DISPLAY: Failed to get DRM mode encoder"); + drmModeFreeResources(res); + return -1; + } + + platform.crtc = drmModeGetCrtc(platform.fd, enc->crtc_id); + if (!platform.crtc) + { + TRACELOG(LOG_WARNING, "DISPLAY: Failed to get DRM mode crtc"); + drmModeFreeEncoder(enc); + drmModeFreeResources(res); + return -1; + } + } + #else + drmModeEncoder *enc = drmModeGetEncoder(platform.fd, platform.connector->encoder_id); + if (!enc) + { + TRACELOG(LOG_WARNING, "DISPLAY: Failed to get DRM mode encoder"); + drmModeFreeResources(res); + return -1; + } + + platform.crtc = drmModeGetCrtc(platform.fd, enc->crtc_id); + if (!platform.crtc) + { + TRACELOG(LOG_WARNING, "DISPLAY: Failed to get DRM mode crtc"); + drmModeFreeEncoder(enc); + drmModeFreeResources(res); + return -1; + } + #endif // If InitWindow should use the current mode find it in the connector's mode list if ((CORE.Window.screen.width <= 0) || (CORE.Window.screen.height <= 0)) @@ -828,7 +1107,11 @@ int InitPlatform(void) if (platform.modeIndex < 0) { TRACELOG(LOG_WARNING, "DISPLAY: No matching DRM connector mode found"); - drmModeFreeEncoder(enc); + #if defined(ENABLE_WAYLAND_DRM_LEASING) + if (!platform.usingDRMLeasing) drmModeFreeEncoder(enc); + #else + drmModeFreeEncoder(enc); + #endif drmModeFreeResources(res); return -1; } @@ -856,7 +1139,11 @@ int InitPlatform(void) if (platform.modeIndex < 0) { TRACELOG(LOG_WARNING, "DISPLAY: Failed to find a suitable DRM connector mode"); - drmModeFreeEncoder(enc); + #if defined(ENABLE_WAYLAND_DRM_LEASING) + if (!platform.usingDRMLeasing) drmModeFreeEncoder(enc); + #else + drmModeFreeEncoder(enc); + #endif drmModeFreeResources(res); return -1; } @@ -873,8 +1160,16 @@ int InitPlatform(void) CORE.Window.render.width = CORE.Window.screen.width; CORE.Window.render.height = CORE.Window.screen.height; - drmModeFreeEncoder(enc); - enc = NULL; + #if defined(ENABLE_WAYLAND_DRM_LEASING) + if (!platform.usingDRMLeasing) + { + drmModeFreeEncoder(enc); + enc = NULL; + } + #else + drmModeFreeEncoder(enc); + enc = NULL; + #endif drmModeFreeResources(res); res = NULL; @@ -903,17 +1198,18 @@ int InitPlatform(void) TRACELOG(LOG_INFO, "DISPLAY: Trying to enable MSAA x4"); } - const EGLint framebufferAttribs[] = { - EGL_RENDERABLE_TYPE, (rlGetVersion() == RL_OPENGL_ES_30)? EGL_OPENGL_ES3_BIT : EGL_OPENGL_ES2_BIT, // Type of context support - EGL_SURFACE_TYPE, EGL_WINDOW_BIT, // Don't use it on Android! + const EGLint framebufferAttribs[] = + { + EGL_RENDERABLE_TYPE, (rlGetVersion() == RL_OPENGL_ES_30)? EGL_OPENGL_ES3_BIT : EGL_OPENGL_ES2_BIT, // Type of context support + EGL_SURFACE_TYPE, EGL_WINDOW_BIT, // Don't use it on Android! EGL_RED_SIZE, 8, // RED color bit depth (alternative: 5) EGL_GREEN_SIZE, 8, // GREEN color bit depth (alternative: 6) EGL_BLUE_SIZE, 8, // BLUE color bit depth (alternative: 5) EGL_ALPHA_SIZE, 8, // ALPHA bit depth (required for transparent framebuffer) //EGL_TRANSPARENT_TYPE, EGL_NONE, // Request transparent framebuffer (EGL_TRANSPARENT_RGB does not work on RPI) - EGL_DEPTH_SIZE, 24, // Depth buffer size (Required to use Depth testing!) + EGL_DEPTH_SIZE, 16, // Depth buffer size (Required to use Depth testing!) //EGL_STENCIL_SIZE, 8, // Stencil buffer size - EGL_SAMPLE_BUFFERS, sampleBuffer, // Activate MSAA + EGL_SAMPLE_BUFFERS, sampleBuffer, // Activate MSAA EGL_SAMPLES, samples, // 4x Antialiasing if activated (Free on MALI GPUs) EGL_NONE }; @@ -1343,46 +1639,52 @@ static void ProcessKeyboard(void) // this means mouse, keyboard or gamepad devices static void InitEvdevInput(void) { - char path[MAX_FILEPATH_LENGTH] = { 0 }; - DIR *directory = NULL; - struct dirent *entity = NULL; + #if !defined(DISABLE_EVDEV_INPUT) + char path[MAX_FILEPATH_LENGTH] = { 0 }; + DIR *directory = NULL; + struct dirent *entity = NULL; - // Initialise keyboard file descriptor - platform.keyboardFd = -1; - platform.mouseFd = -1; + // Initialise keyboard file descriptor + platform.keyboardFd = -1; + platform.mouseFd = -1; - // Reset variables - for (int i = 0; i < MAX_TOUCH_POINTS; ++i) - { - CORE.Input.Touch.position[i].x = -1; - CORE.Input.Touch.position[i].y = -1; - } - - // Reset keyboard key state - for (int i = 0; i < MAX_KEYBOARD_KEYS; i++) - { - CORE.Input.Keyboard.currentKeyState[i] = 0; - CORE.Input.Keyboard.keyRepeatInFrame[i] = 0; - } - - // Open the linux directory of "/dev/input" - directory = opendir(DEFAULT_EVDEV_PATH); - - if (directory) - { - while ((entity = readdir(directory)) != NULL) + // Reset variables + for (int i = 0; i < MAX_TOUCH_POINTS; ++i) { - if ((strncmp("event", entity->d_name, strlen("event")) == 0) || // Search for devices named "event*" - (strncmp("mouse", entity->d_name, strlen("mouse")) == 0)) // Search for devices named "mouse*" - { - snprintf(path, MAX_FILEPATH_LENGTH, "%s%s", DEFAULT_EVDEV_PATH, entity->d_name); - ConfigureEvdevDevice(path); // Configure the device if appropriate - } + CORE.Input.Touch.position[i].x = -1; + CORE.Input.Touch.position[i].y = -1; } - closedir(directory); - } - else TRACELOG(LOG_WARNING, "INPUT: Failed to open linux event directory: %s", DEFAULT_EVDEV_PATH); + // Reset keyboard key state + for (int i = 0; i < MAX_KEYBOARD_KEYS; i++) + { + CORE.Input.Keyboard.currentKeyState[i] = 0; + CORE.Input.Keyboard.keyRepeatInFrame[i] = 0; + } + + // Open the linux directory of "/dev/input" + directory = opendir(DEFAULT_EVDEV_PATH); + + if (directory) + { + while ((entity = readdir(directory)) != NULL) + { + if ((strncmp("event", entity->d_name, strlen("event")) == 0) || // Search for devices named "event*" + (strncmp("mouse", entity->d_name, strlen("mouse")) == 0)) // Search for devices named "mouse*" + { + sprintf(path, "%s%s", DEFAULT_EVDEV_PATH, entity->d_name); + ConfigureEvdevDevice(path); // Configure the device if appropriate + } + } + + closedir(directory); + } + else TRACELOG(LOG_WARNING, "INPUT: Failed to open linux event directory: %s", DEFAULT_EVDEV_PATH); + #else + TRACELOG(LOG_INFO, "INPUT: Not doing evdev input configuration as it's disabled"); + platform.keyboardFd = -1; + platform.mouseFd = -1; + #endif } // Identifies a input device and configures it for use if appropriate