Xwayland: implement drm-lease-v1
This commit allows X11 clients running through Xwayland to lease non-desktop connectors from the Wayland compositor by implementing support for drm-lease-v1. In order to not deadlock with the Wayland compositor if its response to a lease request is delayed, the new interface in _rrScrPriv introduced in the last commit is used, which makes it possible to block the X11 client while a response is pending. Leasing normal outputs is not yet supported, all connectors offered for lease will be advertised as non-desktop. Co-authored-by: Xaver Hugl <xaver.hugl@gmail.com> Reviewed-by: Simon Ser <contact@emersion.fr> Acked-by: Olivier Fourdan <ofourdan@redhat.com> Acked-by: Michel Dänzer <mdaenzer@redhat.com>
This commit is contained in:
parent
7759743c63
commit
089e7f98f8
|
@ -4,6 +4,8 @@ srcs = [
|
||||||
'xwayland-input.h',
|
'xwayland-input.h',
|
||||||
'xwayland-cursor.c',
|
'xwayland-cursor.c',
|
||||||
'xwayland-cursor.h',
|
'xwayland-cursor.h',
|
||||||
|
'xwayland-drm-lease.h',
|
||||||
|
'xwayland-drm-lease.c',
|
||||||
'xwayland-glamor.h',
|
'xwayland-glamor.h',
|
||||||
'xwayland-glx.h',
|
'xwayland-glx.h',
|
||||||
'xwayland-pixmap.c',
|
'xwayland-pixmap.c',
|
||||||
|
@ -43,6 +45,7 @@ xdg_output_xml = join_paths(protodir, 'unstable', 'xdg-output', 'xdg-output-unst
|
||||||
dmabuf_xml = join_paths(protodir, 'unstable', 'linux-dmabuf', 'linux-dmabuf-unstable-v1.xml')
|
dmabuf_xml = join_paths(protodir, 'unstable', 'linux-dmabuf', 'linux-dmabuf-unstable-v1.xml')
|
||||||
viewporter_xml = join_paths(protodir, 'stable', 'viewporter', 'viewporter.xml')
|
viewporter_xml = join_paths(protodir, 'stable', 'viewporter', 'viewporter.xml')
|
||||||
xdg_shell_xml = join_paths(protodir, 'stable', 'xdg-shell', 'xdg-shell.xml')
|
xdg_shell_xml = join_paths(protodir, 'stable', 'xdg-shell', 'xdg-shell.xml')
|
||||||
|
drm_lease_xml = join_paths(protodir, 'staging', 'drm-lease', 'drm-lease-v1.xml')
|
||||||
|
|
||||||
client_header = generator(scanner,
|
client_header = generator(scanner,
|
||||||
output : '@BASENAME@-client-protocol.h',
|
output : '@BASENAME@-client-protocol.h',
|
||||||
|
@ -68,6 +71,7 @@ srcs += client_header.process(xdg_output_xml)
|
||||||
srcs += client_header.process(dmabuf_xml)
|
srcs += client_header.process(dmabuf_xml)
|
||||||
srcs += client_header.process(viewporter_xml)
|
srcs += client_header.process(viewporter_xml)
|
||||||
srcs += client_header.process(xdg_shell_xml)
|
srcs += client_header.process(xdg_shell_xml)
|
||||||
|
srcs += client_header.process(drm_lease_xml)
|
||||||
srcs += code.process(relative_xml)
|
srcs += code.process(relative_xml)
|
||||||
srcs += code.process(pointer_xml)
|
srcs += code.process(pointer_xml)
|
||||||
srcs += code.process(gestures_xml)
|
srcs += code.process(gestures_xml)
|
||||||
|
@ -77,6 +81,7 @@ srcs += code.process(xdg_output_xml)
|
||||||
srcs += code.process(dmabuf_xml)
|
srcs += code.process(dmabuf_xml)
|
||||||
srcs += code.process(viewporter_xml)
|
srcs += code.process(viewporter_xml)
|
||||||
srcs += code.process(xdg_shell_xml)
|
srcs += code.process(xdg_shell_xml)
|
||||||
|
srcs += code.process(drm_lease_xml)
|
||||||
|
|
||||||
xwayland_glamor = []
|
xwayland_glamor = []
|
||||||
eglstream_srcs = []
|
eglstream_srcs = []
|
||||||
|
@ -116,6 +121,10 @@ if build_glx
|
||||||
wayland_inc += glx_inc
|
wayland_inc += glx_inc
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
if libdrm_dep.found()
|
||||||
|
xwayland_dep += libdrm_dep
|
||||||
|
endif
|
||||||
|
|
||||||
xwayland_server = executable(
|
xwayland_server = executable(
|
||||||
'Xwayland',
|
'Xwayland',
|
||||||
srcs,
|
srcs,
|
||||||
|
|
|
@ -0,0 +1,439 @@
|
||||||
|
/*
|
||||||
|
* Copyright © 2020 Drew Devault
|
||||||
|
* Copyright © 2021 Xaver Hugl
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, distribute, and sell this software
|
||||||
|
* and its documentation for any purpose is hereby granted without
|
||||||
|
* fee, provided that the above copyright notice appear in all copies
|
||||||
|
* and that both that copyright notice and this permission notice
|
||||||
|
* appear in supporting documentation, and that the name of the
|
||||||
|
* copyright holders not be used in advertising or publicity
|
||||||
|
* pertaining to distribution of the software without specific,
|
||||||
|
* written prior permission. The copyright holders make no
|
||||||
|
* representations about the suitability of this software for any
|
||||||
|
* purpose. It is provided "as is" without express or implied
|
||||||
|
* warranty.
|
||||||
|
*
|
||||||
|
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
|
||||||
|
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||||
|
* FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||||
|
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
|
||||||
|
* AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <xwayland-config.h>
|
||||||
|
|
||||||
|
#ifdef WITH_LIBDRM
|
||||||
|
#include <xf86drm.h>
|
||||||
|
#include <xf86drmMode.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "xwayland-drm-lease.h"
|
||||||
|
#include "xwayland-screen.h"
|
||||||
|
#include "xwayland-output.h"
|
||||||
|
|
||||||
|
static void
|
||||||
|
drm_lease_handle_lease_fd(void *data,
|
||||||
|
struct wp_drm_lease_v1 *wp_drm_lease_v1,
|
||||||
|
int32_t lease_fd)
|
||||||
|
{
|
||||||
|
struct xwl_drm_lease *lease = (struct xwl_drm_lease *)data;
|
||||||
|
|
||||||
|
lease->fd = lease_fd;
|
||||||
|
AttendClient(lease->client);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
drm_lease_handle_finished(void *data,
|
||||||
|
struct wp_drm_lease_v1 *wp_drm_lease_v1)
|
||||||
|
{
|
||||||
|
struct xwl_drm_lease *lease = (struct xwl_drm_lease *)data;
|
||||||
|
struct xwl_output *output;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (lease->fd >= 0) {
|
||||||
|
RRTerminateLease(lease->rrLease);
|
||||||
|
} else {
|
||||||
|
AttendClient(lease->client);
|
||||||
|
for (i = 0; i < lease->rrLease->numOutputs; ++i) {
|
||||||
|
output = lease->rrLease->outputs[i]->devPrivate;
|
||||||
|
output->lease = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct wp_drm_lease_v1_listener drm_lease_listener = {
|
||||||
|
.lease_fd = drm_lease_handle_lease_fd,
|
||||||
|
.finished = drm_lease_handle_finished,
|
||||||
|
};
|
||||||
|
|
||||||
|
void
|
||||||
|
xwl_randr_get_lease(ClientPtr client, ScreenPtr screen, RRLeasePtr *rrLease, int *fd)
|
||||||
|
{
|
||||||
|
struct xwl_screen *xwl_screen;
|
||||||
|
struct xwl_drm_lease *lease;
|
||||||
|
xwl_screen = xwl_screen_get(screen);
|
||||||
|
|
||||||
|
xorg_list_for_each_entry(lease, &xwl_screen->drm_leases, link) {
|
||||||
|
if (lease->client == client) {
|
||||||
|
*rrLease = lease->rrLease;
|
||||||
|
*fd = lease->fd;
|
||||||
|
if (lease->fd < 0)
|
||||||
|
xorg_list_del(&lease->link);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*rrLease = NULL;
|
||||||
|
*fd = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
xwl_randr_request_lease(ClientPtr client, ScreenPtr screen, RRLeasePtr rrLease)
|
||||||
|
{
|
||||||
|
struct xwl_screen *xwl_screen;
|
||||||
|
struct wp_drm_lease_request_v1 *req;
|
||||||
|
struct xwl_drm_lease *lease_private;
|
||||||
|
struct xwl_drm_lease_device *lease_device = NULL;
|
||||||
|
struct xwl_drm_lease_device *device_data;
|
||||||
|
struct xwl_output *output;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
xwl_screen = xwl_screen_get(screen);
|
||||||
|
|
||||||
|
if (xorg_list_is_empty(&xwl_screen->drm_lease_devices)) {
|
||||||
|
ErrorF("Attempted to create DRM lease without wp_drm_lease_device_v1\n");
|
||||||
|
return BadMatch;
|
||||||
|
}
|
||||||
|
|
||||||
|
xorg_list_for_each_entry(device_data, &xwl_screen->drm_lease_devices, link) {
|
||||||
|
Bool connectors_of_device = FALSE;
|
||||||
|
for (i = 0; i < rrLease->numOutputs; ++i) {
|
||||||
|
output = rrLease->outputs[i]->devPrivate;
|
||||||
|
if (output->lease_device == device_data) {
|
||||||
|
connectors_of_device = TRUE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (connectors_of_device) {
|
||||||
|
if (lease_device != NULL) {
|
||||||
|
ErrorF("Attempted to create DRM lease from multiple devices\n");
|
||||||
|
return BadValue;
|
||||||
|
}
|
||||||
|
lease_device = device_data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < rrLease->numOutputs; ++i) {
|
||||||
|
output = rrLease->outputs[i]->devPrivate;
|
||||||
|
if (!output || !output->lease_connector || output->lease) {
|
||||||
|
return BadValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
req = wp_drm_lease_device_v1_create_lease_request(
|
||||||
|
lease_device->drm_lease_device);
|
||||||
|
lease_private = calloc(1, sizeof(struct xwl_drm_lease));
|
||||||
|
for (i = 0; i < rrLease->numOutputs; ++i) {
|
||||||
|
output = rrLease->outputs[i]->devPrivate;
|
||||||
|
output->lease = lease_private;
|
||||||
|
wp_drm_lease_request_v1_request_connector(req, output->lease_connector);
|
||||||
|
}
|
||||||
|
lease_private->fd = -1;
|
||||||
|
lease_private->lease = wp_drm_lease_request_v1_submit(req);
|
||||||
|
lease_private->rrLease = rrLease;
|
||||||
|
lease_private->client = client;
|
||||||
|
rrLease->devPrivate = lease_private;
|
||||||
|
|
||||||
|
wp_drm_lease_v1_add_listener(lease_private->lease,
|
||||||
|
&drm_lease_listener, lease_private);
|
||||||
|
xorg_list_add(&lease_private->link, &xwl_screen->drm_leases);
|
||||||
|
|
||||||
|
ResetCurrentRequest(client);
|
||||||
|
client->sequence--;
|
||||||
|
IgnoreClient(client);
|
||||||
|
|
||||||
|
return Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
xwl_randr_terminate_lease(ScreenPtr screen, RRLeasePtr lease)
|
||||||
|
{
|
||||||
|
struct xwl_drm_lease *lease_private = lease->devPrivate;
|
||||||
|
|
||||||
|
if (lease_private) {
|
||||||
|
xorg_list_del(&lease_private->link);
|
||||||
|
if (lease_private->fd >= 0)
|
||||||
|
close(lease_private->fd);
|
||||||
|
wp_drm_lease_v1_destroy(lease_private->lease);
|
||||||
|
free(lease_private);
|
||||||
|
lease->devPrivate = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
RRLeaseTerminated(lease);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
lease_connector_handle_name(void *data,
|
||||||
|
struct wp_drm_lease_connector_v1 *wp_drm_lease_connector_v1,
|
||||||
|
const char *name)
|
||||||
|
{
|
||||||
|
/* This space is deliberately left blank */
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
lease_connector_handle_description(void *data,
|
||||||
|
struct wp_drm_lease_connector_v1 *wp_drm_lease_connector_v1,
|
||||||
|
const char *description)
|
||||||
|
{
|
||||||
|
/* This space is deliberately left blank */
|
||||||
|
}
|
||||||
|
|
||||||
|
static RRModePtr *
|
||||||
|
xwl_get_rrmodes_from_connector_id(int drm, int32_t connector_id, int *nmode, int *npref)
|
||||||
|
{
|
||||||
|
#ifdef WITH_LIBDRM
|
||||||
|
drmModeConnectorPtr conn;
|
||||||
|
drmModeModeInfoPtr kmode;
|
||||||
|
RRModePtr *rrmodes;
|
||||||
|
int pref, i;
|
||||||
|
|
||||||
|
*nmode = *npref = 0;
|
||||||
|
|
||||||
|
conn = drmModeGetConnectorCurrent(drm, connector_id);
|
||||||
|
if (!conn) {
|
||||||
|
ErrorF("drmModeGetConnector for connector %d failed\n", connector_id);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
rrmodes = xallocarray(conn->count_modes, sizeof(RRModePtr));
|
||||||
|
if (!rrmodes) {
|
||||||
|
ErrorF("Failed to allocate connector modes\n");
|
||||||
|
drmModeFreeConnector(conn);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This spaghetti brought to you courtesey of xf86RandrR12.c
|
||||||
|
* It adds preferred modes first, then non-preferred modes */
|
||||||
|
for (pref = 1; pref >= 0; pref--) {
|
||||||
|
for (i = 0; i < conn->count_modes; ++i) {
|
||||||
|
kmode = &conn->modes[i];
|
||||||
|
if ((pref != 0) == ((kmode->type & DRM_MODE_TYPE_PREFERRED) != 0)) {
|
||||||
|
xRRModeInfo modeInfo;
|
||||||
|
RRModePtr rrmode;
|
||||||
|
|
||||||
|
modeInfo.nameLength = strlen(kmode->name);
|
||||||
|
|
||||||
|
modeInfo.width = kmode->hdisplay;
|
||||||
|
modeInfo.dotClock = kmode->clock * 1000;
|
||||||
|
modeInfo.hSyncStart = kmode->hsync_start;
|
||||||
|
modeInfo.hSyncEnd = kmode->hsync_end;
|
||||||
|
modeInfo.hTotal = kmode->htotal;
|
||||||
|
modeInfo.hSkew = kmode->hskew;
|
||||||
|
|
||||||
|
modeInfo.height = kmode->vdisplay;
|
||||||
|
modeInfo.vSyncStart = kmode->vsync_start;
|
||||||
|
modeInfo.vSyncEnd = kmode->vsync_end;
|
||||||
|
modeInfo.vTotal = kmode->vtotal;
|
||||||
|
modeInfo.modeFlags = kmode->flags;
|
||||||
|
|
||||||
|
rrmode = RRModeGet(&modeInfo, kmode->name);
|
||||||
|
if (rrmode) {
|
||||||
|
rrmodes[*nmode] = rrmode;
|
||||||
|
*nmode = *nmode + 1;
|
||||||
|
*npref = *npref + pref;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* workaround: there could be no preferred mode that got added */
|
||||||
|
if (*nmode > 0 && *npref == 0)
|
||||||
|
*npref = 1;
|
||||||
|
|
||||||
|
drmModeFreeConnector(conn);
|
||||||
|
return rrmodes;
|
||||||
|
#else
|
||||||
|
*nmode = *npref = 0;
|
||||||
|
return NULL;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
lease_connector_handle_connector_id(void *data,
|
||||||
|
struct wp_drm_lease_connector_v1 *wp_drm_lease_connector_v1,
|
||||||
|
uint32_t connector_id)
|
||||||
|
{
|
||||||
|
struct xwl_output *output;
|
||||||
|
Atom name;
|
||||||
|
INT32 value;
|
||||||
|
int err;
|
||||||
|
int nmode, npref;
|
||||||
|
RRModePtr *rrmodes;
|
||||||
|
|
||||||
|
value = connector_id;
|
||||||
|
output = (struct xwl_output *)data;
|
||||||
|
name = MakeAtom("CONNECTOR_ID", 12, TRUE);
|
||||||
|
|
||||||
|
if (name != BAD_RESOURCE) {
|
||||||
|
err = RRConfigureOutputProperty(output->randr_output, name,
|
||||||
|
FALSE, FALSE, TRUE,
|
||||||
|
1, &value);
|
||||||
|
if (err != 0) {
|
||||||
|
ErrorF("RRConfigureOutputProperty error, %d\n", err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
err = RRChangeOutputProperty(output->randr_output, name,
|
||||||
|
XA_INTEGER, 32, PropModeReplace, 1,
|
||||||
|
&value, FALSE, FALSE);
|
||||||
|
if (err != 0) {
|
||||||
|
ErrorF("RRChangeOutputProperty error, %d\n", err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rrmodes = xwl_get_rrmodes_from_connector_id(output->lease_device->drm_read_only_fd,
|
||||||
|
connector_id, &nmode, &npref);
|
||||||
|
|
||||||
|
if (rrmodes != NULL)
|
||||||
|
RROutputSetModes(output->randr_output, rrmodes, nmode, npref);
|
||||||
|
|
||||||
|
free(rrmodes);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
lease_connector_handle_done(void *data,
|
||||||
|
struct wp_drm_lease_connector_v1 *wp_drm_lease_connector_v1)
|
||||||
|
{
|
||||||
|
/* This space is deliberately left blank */
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
lease_connector_handle_withdrawn(void *data,
|
||||||
|
struct wp_drm_lease_connector_v1 *wp_drm_lease_connector_v1)
|
||||||
|
{
|
||||||
|
xwl_output_remove(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct wp_drm_lease_connector_v1_listener lease_connector_listener = {
|
||||||
|
.name = lease_connector_handle_name,
|
||||||
|
.description = lease_connector_handle_description,
|
||||||
|
.connector_id = lease_connector_handle_connector_id,
|
||||||
|
.withdrawn = lease_connector_handle_withdrawn,
|
||||||
|
.done = lease_connector_handle_done,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
drm_lease_device_handle_drm_fd(void *data,
|
||||||
|
struct wp_drm_lease_device_v1 *wp_drm_lease_device_v1,
|
||||||
|
int fd)
|
||||||
|
{
|
||||||
|
((struct xwl_drm_lease_device *)data)->drm_read_only_fd = fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
drm_lease_device_handle_connector(void *data,
|
||||||
|
struct wp_drm_lease_device_v1 *wp_drm_lease_device_v1,
|
||||||
|
struct wp_drm_lease_connector_v1 *connector)
|
||||||
|
{
|
||||||
|
struct xwl_drm_lease_device *lease_device = data;
|
||||||
|
struct xwl_output *xwl_output;
|
||||||
|
char name[256];
|
||||||
|
|
||||||
|
xwl_output = calloc(1, sizeof *xwl_output);
|
||||||
|
if (xwl_output == NULL) {
|
||||||
|
ErrorF("%s ENOMEM\n", __func__);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
snprintf(name, sizeof name, "XWAYLAND%d", xwl_get_next_output_serial());
|
||||||
|
|
||||||
|
xwl_output->lease_device = lease_device;
|
||||||
|
xwl_output->xwl_screen = lease_device->xwl_screen;
|
||||||
|
xwl_output->lease_connector = connector;
|
||||||
|
xwl_output->randr_crtc = RRCrtcCreate(lease_device->xwl_screen->screen, xwl_output);
|
||||||
|
if (!xwl_output->randr_crtc) {
|
||||||
|
ErrorF("Failed creating RandR CRTC\n");
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
RRCrtcSetRotations(xwl_output->randr_crtc, ALL_ROTATIONS);
|
||||||
|
xwl_output->randr_output = RROutputCreate(lease_device->xwl_screen->screen,
|
||||||
|
name, strlen(name), xwl_output);
|
||||||
|
if (!xwl_output->randr_output) {
|
||||||
|
ErrorF("Failed creating RandR Output\n");
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
RRCrtcGammaSetSize(xwl_output->randr_crtc, 256);
|
||||||
|
RROutputSetCrtcs(xwl_output->randr_output, &xwl_output->randr_crtc, 1);
|
||||||
|
RROutputSetConnection(xwl_output->randr_output, RR_Connected);
|
||||||
|
RROutputSetNonDesktop(xwl_output->randr_output, TRUE);
|
||||||
|
xwl_output->randr_output->devPrivate = xwl_output;
|
||||||
|
|
||||||
|
wp_drm_lease_connector_v1_add_listener(connector,
|
||||||
|
&lease_connector_listener,
|
||||||
|
xwl_output);
|
||||||
|
|
||||||
|
xorg_list_append(&xwl_output->link, &lease_device->xwl_screen->output_list);
|
||||||
|
return;
|
||||||
|
|
||||||
|
err:
|
||||||
|
if (xwl_output->randr_crtc)
|
||||||
|
RRCrtcDestroy(xwl_output->randr_crtc);
|
||||||
|
free(xwl_output);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
drm_lease_device_handle_released(void *data,
|
||||||
|
struct wp_drm_lease_device_v1 *wp_drm_lease_device_v1)
|
||||||
|
{
|
||||||
|
xwl_screen_destroy_drm_lease_device(data, wp_drm_lease_device_v1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
drm_lease_device_handle_done(void *data,
|
||||||
|
struct wp_drm_lease_device_v1 *wp_drm_lease_device_v1)
|
||||||
|
{
|
||||||
|
/* This space is deliberately left blank */
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct wp_drm_lease_device_v1_listener drm_lease_device_listener = {
|
||||||
|
.drm_fd = drm_lease_device_handle_drm_fd,
|
||||||
|
.connector = drm_lease_device_handle_connector,
|
||||||
|
.released = drm_lease_device_handle_released,
|
||||||
|
.done = drm_lease_device_handle_done,
|
||||||
|
};
|
||||||
|
|
||||||
|
void
|
||||||
|
xwl_screen_add_drm_lease_device(struct xwl_screen *xwl_screen, uint32_t id)
|
||||||
|
{
|
||||||
|
struct wp_drm_lease_device_v1 *lease_device = wl_registry_bind(
|
||||||
|
xwl_screen->registry, id, &wp_drm_lease_device_v1_interface, 1);
|
||||||
|
struct xwl_drm_lease_device *device_data = malloc(sizeof(struct xwl_drm_lease_device));
|
||||||
|
|
||||||
|
device_data->drm_lease_device = lease_device;
|
||||||
|
device_data->xwl_screen = xwl_screen;
|
||||||
|
device_data->drm_read_only_fd = -1;
|
||||||
|
device_data->id = id;
|
||||||
|
xorg_list_add(&device_data->link, &xwl_screen->drm_lease_devices);
|
||||||
|
wp_drm_lease_device_v1_add_listener(lease_device,
|
||||||
|
&drm_lease_device_listener,
|
||||||
|
device_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
xwl_screen_destroy_drm_lease_device(struct xwl_screen *xwl_screen,
|
||||||
|
struct wp_drm_lease_device_v1 *wp_drm_lease_device_v1)
|
||||||
|
{
|
||||||
|
struct xwl_drm_lease_device *device_data;
|
||||||
|
|
||||||
|
xorg_list_for_each_entry(device_data, &xwl_screen->drm_lease_devices, link) {
|
||||||
|
if (device_data->drm_lease_device == wp_drm_lease_device_v1) {
|
||||||
|
wp_drm_lease_device_v1_destroy(wp_drm_lease_device_v1);
|
||||||
|
xorg_list_del(&device_data->link);
|
||||||
|
if (device_data->drm_read_only_fd >= 0)
|
||||||
|
close(device_data->drm_read_only_fd);
|
||||||
|
free(device_data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,67 @@
|
||||||
|
/*
|
||||||
|
* Copyright © 2020 Drew Devault
|
||||||
|
* Copyright © 2021 Xaver Hugl
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, distribute, and sell this software
|
||||||
|
* and its documentation for any purpose is hereby granted without
|
||||||
|
* fee, provided that the above copyright notice appear in all copies
|
||||||
|
* and that both that copyright notice and this permission notice
|
||||||
|
* appear in supporting documentation, and that the name of the
|
||||||
|
* copyright holders not be used in advertising or publicity
|
||||||
|
* pertaining to distribution of the software without specific,
|
||||||
|
* written prior permission. The copyright holders make no
|
||||||
|
* representations about the suitability of this software for any
|
||||||
|
* purpose. It is provided "as is" without express or implied
|
||||||
|
* warranty.
|
||||||
|
*
|
||||||
|
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
|
||||||
|
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||||
|
* FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||||
|
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
|
||||||
|
* AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef XWAYLAND_DRM_LEASE_H
|
||||||
|
#define XWAYLAND_DRM_LEASE_H
|
||||||
|
|
||||||
|
#include <X11/Xatom.h>
|
||||||
|
#include <randrstr.h>
|
||||||
|
|
||||||
|
#include "xwayland-types.h"
|
||||||
|
#include "list.h"
|
||||||
|
|
||||||
|
#include "drm-lease-v1-client-protocol.h"
|
||||||
|
|
||||||
|
struct xwl_drm_lease_device {
|
||||||
|
struct xorg_list link;
|
||||||
|
struct wp_drm_lease_device_v1 *drm_lease_device;
|
||||||
|
int drm_read_only_fd;
|
||||||
|
struct xwl_screen *xwl_screen;
|
||||||
|
uint32_t id;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct xwl_queued_drm_lease_device {
|
||||||
|
struct xorg_list link;
|
||||||
|
uint32_t id;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct xwl_drm_lease {
|
||||||
|
struct xorg_list link;
|
||||||
|
struct wp_drm_lease_v1 *lease;
|
||||||
|
RRLeasePtr rrLease;
|
||||||
|
ClientPtr client;
|
||||||
|
int fd;
|
||||||
|
};
|
||||||
|
|
||||||
|
int xwl_randr_request_lease(ClientPtr client, ScreenPtr screen, RRLeasePtr rrLease);
|
||||||
|
void xwl_randr_get_lease(ClientPtr client, ScreenPtr screen, RRLeasePtr *rrLease, int *fd);
|
||||||
|
void xwl_randr_terminate_lease(ScreenPtr screen, RRLeasePtr lease);
|
||||||
|
|
||||||
|
void xwl_screen_add_drm_lease_device(struct xwl_screen *xwl_screen, uint32_t id);
|
||||||
|
void xwl_screen_destroy_drm_lease_device(struct xwl_screen *xwl_screen,
|
||||||
|
struct wp_drm_lease_device_v1 *wp_drm_lease_device_v1);
|
||||||
|
|
||||||
|
#endif /* XWAYLAND_DRM_LEASE_H */
|
|
@ -35,13 +35,6 @@
|
||||||
|
|
||||||
#include "xdg-output-unstable-v1-client-protocol.h"
|
#include "xdg-output-unstable-v1-client-protocol.h"
|
||||||
|
|
||||||
#define ALL_ROTATIONS (RR_Rotate_0 | \
|
|
||||||
RR_Rotate_90 | \
|
|
||||||
RR_Rotate_180 | \
|
|
||||||
RR_Rotate_270 | \
|
|
||||||
RR_Reflect_X | \
|
|
||||||
RR_Reflect_Y)
|
|
||||||
|
|
||||||
static void xwl_output_get_xdg_output(struct xwl_output *xwl_output);
|
static void xwl_output_get_xdg_output(struct xwl_output *xwl_output);
|
||||||
|
|
||||||
static Rotation
|
static Rotation
|
||||||
|
@ -731,7 +724,6 @@ struct xwl_output *
|
||||||
xwl_output_create(struct xwl_screen *xwl_screen, uint32_t id)
|
xwl_output_create(struct xwl_screen *xwl_screen, uint32_t id)
|
||||||
{
|
{
|
||||||
struct xwl_output *xwl_output;
|
struct xwl_output *xwl_output;
|
||||||
static int serial;
|
|
||||||
char name[256];
|
char name[256];
|
||||||
|
|
||||||
xwl_output = calloc(1, sizeof *xwl_output);
|
xwl_output = calloc(1, sizeof *xwl_output);
|
||||||
|
@ -750,7 +742,7 @@ xwl_output_create(struct xwl_screen *xwl_screen, uint32_t id)
|
||||||
xwl_output->server_output_id = id;
|
xwl_output->server_output_id = id;
|
||||||
wl_output_add_listener(xwl_output->output, &output_listener, xwl_output);
|
wl_output_add_listener(xwl_output->output, &output_listener, xwl_output);
|
||||||
|
|
||||||
snprintf(name, sizeof name, "XWAYLAND%d", serial++);
|
snprintf(name, sizeof name, "XWAYLAND%d", xwl_get_next_output_serial());
|
||||||
|
|
||||||
xwl_output->xwl_screen = xwl_screen;
|
xwl_output->xwl_screen = xwl_screen;
|
||||||
xwl_output->randr_crtc = RRCrtcCreate(xwl_screen->screen, xwl_output);
|
xwl_output->randr_crtc = RRCrtcCreate(xwl_screen->screen, xwl_output);
|
||||||
|
@ -795,9 +787,12 @@ err:
|
||||||
void
|
void
|
||||||
xwl_output_destroy(struct xwl_output *xwl_output)
|
xwl_output_destroy(struct xwl_output *xwl_output)
|
||||||
{
|
{
|
||||||
|
if (xwl_output->lease_connector)
|
||||||
|
wp_drm_lease_connector_v1_destroy(xwl_output->lease_connector);
|
||||||
if (xwl_output->xdg_output)
|
if (xwl_output->xdg_output)
|
||||||
zxdg_output_v1_destroy(xwl_output->xdg_output);
|
zxdg_output_v1_destroy(xwl_output->xdg_output);
|
||||||
wl_output_destroy(xwl_output->output);
|
if (xwl_output->output)
|
||||||
|
wl_output_destroy(xwl_output->output);
|
||||||
free(xwl_output);
|
free(xwl_output);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -946,6 +941,10 @@ xwl_screen_init_output(struct xwl_screen *xwl_screen)
|
||||||
rp->rrModeDestroy = xwl_randr_mode_destroy;
|
rp->rrModeDestroy = xwl_randr_mode_destroy;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
rp->rrRequestLease = xwl_randr_request_lease;
|
||||||
|
rp->rrGetLease = xwl_randr_get_lease;
|
||||||
|
rp->rrTerminateLease = xwl_randr_terminate_lease;
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -954,6 +953,12 @@ xwl_output_get_xdg_output(struct xwl_output *xwl_output)
|
||||||
{
|
{
|
||||||
struct xwl_screen *xwl_screen = xwl_output->xwl_screen;
|
struct xwl_screen *xwl_screen = xwl_output->xwl_screen;
|
||||||
|
|
||||||
|
if (!xwl_output->output) {
|
||||||
|
/* This can happen when an output is created from a leasable DRM
|
||||||
|
* connector */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
xwl_output->xdg_output =
|
xwl_output->xdg_output =
|
||||||
zxdg_output_manager_v1_get_xdg_output (xwl_screen->xdg_output_manager,
|
zxdg_output_manager_v1_get_xdg_output (xwl_screen->xdg_output_manager,
|
||||||
xwl_output->output);
|
xwl_output->output);
|
||||||
|
@ -973,3 +978,10 @@ xwl_screen_init_xdg_output(struct xwl_screen *xwl_screen)
|
||||||
xorg_list_for_each_entry(it, &xwl_screen->output_list, link)
|
xorg_list_for_each_entry(it, &xwl_screen->output_list, link)
|
||||||
xwl_output_get_xdg_output(it);
|
xwl_output_get_xdg_output(it);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
xwl_get_next_output_serial(void)
|
||||||
|
{
|
||||||
|
static int output_name_serial = 0;
|
||||||
|
return output_name_serial++;
|
||||||
|
}
|
||||||
|
|
|
@ -34,19 +34,34 @@
|
||||||
#include <randrstr.h>
|
#include <randrstr.h>
|
||||||
|
|
||||||
#include "xwayland-types.h"
|
#include "xwayland-types.h"
|
||||||
|
#include "xwayland-drm-lease.h"
|
||||||
|
|
||||||
|
#define ALL_ROTATIONS (RR_Rotate_0 | \
|
||||||
|
RR_Rotate_90 | \
|
||||||
|
RR_Rotate_180 | \
|
||||||
|
RR_Rotate_270 | \
|
||||||
|
RR_Reflect_X | \
|
||||||
|
RR_Reflect_Y)
|
||||||
|
|
||||||
struct xwl_output {
|
struct xwl_output {
|
||||||
struct xorg_list link;
|
struct xorg_list link;
|
||||||
struct wl_output *output;
|
|
||||||
struct zxdg_output_v1 *xdg_output;
|
|
||||||
uint32_t server_output_id;
|
|
||||||
struct xwl_screen *xwl_screen;
|
struct xwl_screen *xwl_screen;
|
||||||
RROutputPtr randr_output;
|
RROutputPtr randr_output;
|
||||||
RRCrtcPtr randr_crtc;
|
RRCrtcPtr randr_crtc;
|
||||||
|
|
||||||
|
/* only for regular outputs */
|
||||||
|
struct wl_output *output;
|
||||||
|
struct zxdg_output_v1 *xdg_output;
|
||||||
|
uint32_t server_output_id;
|
||||||
int32_t x, y, width, height, refresh;
|
int32_t x, y, width, height, refresh;
|
||||||
Rotation rotation;
|
Rotation rotation;
|
||||||
Bool wl_output_done;
|
Bool wl_output_done;
|
||||||
Bool xdg_output_done;
|
Bool xdg_output_done;
|
||||||
|
|
||||||
|
/* only for lease-able DRM connectors */
|
||||||
|
struct wp_drm_lease_connector_v1 *lease_connector;
|
||||||
|
struct xwl_drm_lease *lease;
|
||||||
|
struct xwl_drm_lease_device *lease_device;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Per client per output emulated randr/vidmode resolution info. */
|
/* Per client per output emulated randr/vidmode resolution info. */
|
||||||
|
@ -79,4 +94,6 @@ void xwl_output_set_window_randr_emu_props(struct xwl_screen *xwl_screen,
|
||||||
|
|
||||||
void xwl_screen_init_xdg_output(struct xwl_screen *xwl_screen);
|
void xwl_screen_init_xdg_output(struct xwl_screen *xwl_screen);
|
||||||
|
|
||||||
|
int xwl_get_next_output_serial(void);
|
||||||
|
|
||||||
#endif /* XWAYLAND_OUTPUT_H */
|
#endif /* XWAYLAND_OUTPUT_H */
|
||||||
|
|
|
@ -149,6 +149,24 @@ xwl_property_callback(CallbackListPtr *pcbl, void *closure,
|
||||||
xwl_window_update_property(xwl_window, rec);
|
xwl_window_update_property(xwl_window, rec);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
xwl_root_window_finalized_callback(CallbackListPtr *pcbl,
|
||||||
|
void *closure,
|
||||||
|
void *calldata)
|
||||||
|
{
|
||||||
|
ScreenPtr screen = closure;
|
||||||
|
struct xwl_screen *xwl_screen = xwl_screen_get(screen);
|
||||||
|
struct xwl_queued_drm_lease_device *queued_device, *next;
|
||||||
|
|
||||||
|
xorg_list_for_each_entry_safe(queued_device, next,
|
||||||
|
&xwl_screen->queued_drm_lease_devices, link) {
|
||||||
|
xwl_screen_add_drm_lease_device(xwl_screen, queued_device->id);
|
||||||
|
xorg_list_del(&queued_device->link);
|
||||||
|
free(queued_device);
|
||||||
|
}
|
||||||
|
DeleteCallback(&RootWindowFinalizeCallback, xwl_root_window_finalized_callback, screen);
|
||||||
|
}
|
||||||
|
|
||||||
Bool
|
Bool
|
||||||
xwl_close_screen(ScreenPtr screen)
|
xwl_close_screen(ScreenPtr screen)
|
||||||
{
|
{
|
||||||
|
@ -168,6 +186,12 @@ xwl_close_screen(ScreenPtr screen)
|
||||||
|
|
||||||
xwl_screen_release_tablet_manager(xwl_screen);
|
xwl_screen_release_tablet_manager(xwl_screen);
|
||||||
|
|
||||||
|
struct xwl_drm_lease_device *device_data, *next;
|
||||||
|
xorg_list_for_each_entry_safe(device_data, next,
|
||||||
|
&xwl_screen->drm_lease_devices, link)
|
||||||
|
xwl_screen_destroy_drm_lease_device(xwl_screen,
|
||||||
|
device_data->drm_lease_device);
|
||||||
|
|
||||||
RemoveNotifyFd(xwl_screen->wayland_fd);
|
RemoveNotifyFd(xwl_screen->wayland_fd);
|
||||||
|
|
||||||
wl_display_disconnect(xwl_screen->display);
|
wl_display_disconnect(xwl_screen->display);
|
||||||
|
@ -392,6 +416,15 @@ registry_global(void *data, struct wl_registry *registry, uint32_t id,
|
||||||
wl_registry_bind(registry, id, &zxdg_output_manager_v1_interface, version);
|
wl_registry_bind(registry, id, &zxdg_output_manager_v1_interface, version);
|
||||||
xwl_screen_init_xdg_output(xwl_screen);
|
xwl_screen_init_xdg_output(xwl_screen);
|
||||||
}
|
}
|
||||||
|
else if (strcmp(interface, "wp_drm_lease_device_v1") == 0) {
|
||||||
|
if (xwl_screen->screen->root == NULL) {
|
||||||
|
struct xwl_queued_drm_lease_device *queued = malloc(sizeof(struct xwl_queued_drm_lease_device));
|
||||||
|
queued->id = id;
|
||||||
|
xorg_list_append(&queued->link, &xwl_screen->queued_drm_lease_devices);
|
||||||
|
} else {
|
||||||
|
xwl_screen_add_drm_lease_device(xwl_screen, id);
|
||||||
|
}
|
||||||
|
}
|
||||||
else if (strcmp(interface, "wp_viewporter") == 0) {
|
else if (strcmp(interface, "wp_viewporter") == 0) {
|
||||||
xwl_screen->viewporter = wl_registry_bind(registry, id, &wp_viewporter_interface, 1);
|
xwl_screen->viewporter = wl_registry_bind(registry, id, &wp_viewporter_interface, 1);
|
||||||
}
|
}
|
||||||
|
@ -408,6 +441,7 @@ global_remove(void *data, struct wl_registry *registry, uint32_t name)
|
||||||
{
|
{
|
||||||
struct xwl_screen *xwl_screen = data;
|
struct xwl_screen *xwl_screen = data;
|
||||||
struct xwl_output *xwl_output, *tmp_xwl_output;
|
struct xwl_output *xwl_output, *tmp_xwl_output;
|
||||||
|
struct xwl_drm_lease_device *lease_device, *tmp_lease_device;
|
||||||
|
|
||||||
xorg_list_for_each_entry_safe(xwl_output, tmp_xwl_output,
|
xorg_list_for_each_entry_safe(xwl_output, tmp_xwl_output,
|
||||||
&xwl_screen->output_list, link) {
|
&xwl_screen->output_list, link) {
|
||||||
|
@ -416,6 +450,14 @@ global_remove(void *data, struct wl_registry *registry, uint32_t name)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
xorg_list_for_each_entry_safe(lease_device, tmp_lease_device,
|
||||||
|
&xwl_screen->drm_lease_devices, link) {
|
||||||
|
if (lease_device->id == name) {
|
||||||
|
wp_drm_lease_device_v1_release(lease_device->drm_lease_device);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct wl_registry_listener registry_listener = {
|
static const struct wl_registry_listener registry_listener = {
|
||||||
|
@ -619,6 +661,9 @@ xwl_screen_init(ScreenPtr pScreen, int argc, char **argv)
|
||||||
xorg_list_init(&xwl_screen->seat_list);
|
xorg_list_init(&xwl_screen->seat_list);
|
||||||
xorg_list_init(&xwl_screen->damage_window_list);
|
xorg_list_init(&xwl_screen->damage_window_list);
|
||||||
xorg_list_init(&xwl_screen->window_list);
|
xorg_list_init(&xwl_screen->window_list);
|
||||||
|
xorg_list_init(&xwl_screen->drm_lease_devices);
|
||||||
|
xorg_list_init(&xwl_screen->queued_drm_lease_devices);
|
||||||
|
xorg_list_init(&xwl_screen->drm_leases);
|
||||||
xwl_screen->depth = 24;
|
xwl_screen->depth = 24;
|
||||||
|
|
||||||
if (!monitorResolution)
|
if (!monitorResolution)
|
||||||
|
@ -744,6 +789,7 @@ xwl_screen_init(ScreenPtr pScreen, int argc, char **argv)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
AddCallback(&PropertyStateCallback, xwl_property_callback, pScreen);
|
AddCallback(&PropertyStateCallback, xwl_property_callback, pScreen);
|
||||||
|
AddCallback(&RootWindowFinalizeCallback, xwl_root_window_finalized_callback, pScreen);
|
||||||
|
|
||||||
xwl_screen_roundtrip(xwl_screen);
|
xwl_screen_roundtrip(xwl_screen);
|
||||||
|
|
||||||
|
|
|
@ -36,6 +36,7 @@
|
||||||
#include "xwayland-types.h"
|
#include "xwayland-types.h"
|
||||||
#include "xwayland-output.h"
|
#include "xwayland-output.h"
|
||||||
#include "xwayland-glamor.h"
|
#include "xwayland-glamor.h"
|
||||||
|
#include "xwayland-drm-lease.h"
|
||||||
|
|
||||||
struct xwl_format {
|
struct xwl_format {
|
||||||
uint32_t format;
|
uint32_t format;
|
||||||
|
@ -87,6 +88,9 @@ struct xwl_screen {
|
||||||
struct zwp_linux_dmabuf_v1 *dmabuf;
|
struct zwp_linux_dmabuf_v1 *dmabuf;
|
||||||
struct zxdg_output_manager_v1 *xdg_output_manager;
|
struct zxdg_output_manager_v1 *xdg_output_manager;
|
||||||
struct wp_viewporter *viewporter;
|
struct wp_viewporter *viewporter;
|
||||||
|
struct xorg_list drm_lease_devices;
|
||||||
|
struct xorg_list queued_drm_lease_devices;
|
||||||
|
struct xorg_list drm_leases;
|
||||||
uint32_t serial;
|
uint32_t serial;
|
||||||
|
|
||||||
#define XWL_FORMAT_ARGB8888 (1 << 0)
|
#define XWL_FORMAT_ARGB8888 (1 << 0)
|
||||||
|
|
|
@ -30,5 +30,6 @@ struct xwl_pixmap;
|
||||||
struct xwl_window;
|
struct xwl_window;
|
||||||
struct xwl_screen;
|
struct xwl_screen;
|
||||||
struct xwl_egl_backend;
|
struct xwl_egl_backend;
|
||||||
|
struct xwl_drm_lease;
|
||||||
|
|
||||||
#endif /* XWAYLAND_TYPES_H */
|
#endif /* XWAYLAND_TYPES_H */
|
||||||
|
|
Loading…
Reference in New Issue