summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--configure.ac18
-rw-r--r--src/drmmode_display.c137
-rw-r--r--src/drmmode_display.h5
3 files changed, 159 insertions, 1 deletions
diff --git a/configure.ac b/configure.ac
index 378b5aa..d56e519 100644
--- a/configure.ac
+++ b/configure.ac
@@ -54,6 +54,14 @@ if test "x$GCC" = "xyes"; then
CPPFLAGS="$CPPFLAGS -Wall"
fi
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+#include <features.h>
+#ifndef __GLIBC__
+#error not glibc
+#endif
+]], [])], [AC_DEFINE(_GNU_SOURCE, 1,
+ [ Enable GNU and other extensions to the C environment for glibc])])
+
AH_TOP([#include "xorg-server.h"])
# Define a configure option for an alternate module directory
@@ -170,6 +178,12 @@ AC_CHECK_DECL(RROutputSetNonDesktop,
[#include <xorg-server.h>
#include <randrstr.h>])
+AC_CHECK_DECL(RRDeliverLeaseEvent,
+ [AC_DEFINE(HAVE_RRLEASE, 1,
+ [Have RandR lease support API])], [],
+ [#include <xorg-server.h>
+ #include <randrstr.h>])
+
AC_CHECK_DECL(fbGlyphs,
[AC_DEFINE(HAVE_FBGLYPHS, 1, [Have fbGlyphs API])], [],
[#include <X11/Xmd.h>
@@ -209,6 +223,8 @@ AC_CHECK_HEADERS([dri3.h], [], [],
CPPFLAGS="$SAVE_CPPFLAGS"
+AC_CHECK_LIB([bsd], [arc4random_buf])
+
# Checks for headers/macros for byte swapping
# Known variants:
# <byteswap.h> bswap_16, bswap_32, bswap_64 (glibc)
@@ -219,6 +235,8 @@ CPPFLAGS="$SAVE_CPPFLAGS"
# if <byteswap.h> is found, assume it's the correct version
AC_CHECK_HEADERS([byteswap.h])
+AC_REPLACE_FUNCS([reallocarray])
+
# if <sys/endian.h> is found, have to check which version
AC_CHECK_HEADER([sys/endian.h], [HAVE_SYS_ENDIAN_H="yes"], [HAVE_SYS_ENDIAN_H="no"])
diff --git a/src/drmmode_display.c b/src/drmmode_display.c
index 914086d..84a355c 100644
--- a/src/drmmode_display.c
+++ b/src/drmmode_display.c
@@ -2934,8 +2934,138 @@ fail:
return FALSE;
}
+#ifdef HAVE_RRLEASE
+
+static void
+drmmode_validate_leases(ScrnInfoPtr scrn)
+{
+ ScreenPtr screen = scrn->pScreen;
+ rrScrPrivPtr scr_priv = rrGetScrPriv(screen);
+ AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn);
+ drmModeLesseeListPtr lessees;
+ RRLeasePtr lease, next;
+ int l;
+
+ /* We can't talk to the kernel about leases when VT switched */
+ if (!scrn->vtSema)
+ return;
+
+ lessees = drmModeListLessees(pAMDGPUEnt->fd);
+ if (!lessees)
+ return;
+
+ xorg_list_for_each_entry_safe(lease, next, &scr_priv->leases, list) {
+ drmmode_lease_private_ptr lease_private = lease->devPrivate;
+
+ for (l = 0; l < lessees->count; l++) {
+ if (lessees->lessees[l] == lease_private->lessee_id)
+ break;
+ }
+
+ /* check to see if the lease has gone away */
+ if (l == lessees->count) {
+ free(lease_private);
+ lease->devPrivate = NULL;
+ xf86CrtcLeaseTerminated(lease);
+ }
+ }
+
+ free(lessees);
+}
+
+static int
+drmmode_create_lease(RRLeasePtr lease, int *fd)
+{
+ ScreenPtr screen = lease->screen;
+ ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
+ AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn);
+ int ncrtc = lease->numCrtcs;
+ int noutput = lease->numOutputs;
+ int nobjects;
+ int c, o;
+ int i;
+ int lease_fd;
+ uint32_t *objects;
+ drmmode_lease_private_ptr lease_private;
+
+ nobjects = ncrtc + noutput;
+
+ if (nobjects == 0)
+ return BadValue;
+
+ lease_private = calloc(1, sizeof (drmmode_lease_private_rec));
+ if (!lease_private)
+ return BadAlloc;
+
+ objects = xallocarray(nobjects, sizeof (uint32_t));
+
+ if (!objects) {
+ free(lease_private);
+ return BadAlloc;
+ }
+
+ i = 0;
+
+ /* Add CRTC ids */
+ for (c = 0; c < ncrtc; c++) {
+ xf86CrtcPtr crtc = lease->crtcs[c]->devPrivate;
+ drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
+
+ objects[i++] = drmmode_crtc->mode_crtc->crtc_id;
+ }
+
+ /* Add connector ids */
+
+ for (o = 0; o < noutput; o++) {
+ xf86OutputPtr output = lease->outputs[o]->devPrivate;
+ drmmode_output_private_ptr drmmode_output = output->driver_private;
+
+ objects[i++] = drmmode_output->mode_output->connector_id;
+ }
+
+ /* call kernel to create lease */
+ assert (i == nobjects);
+
+ lease_fd = drmModeCreateLease(pAMDGPUEnt->fd, objects, nobjects, 0, &lease_private->lessee_id);
+
+ free(objects);
+
+ if (lease_fd < 0) {
+ free(lease_private);
+ return BadMatch;
+ }
+
+ lease->devPrivate = lease_private;
+
+ xf86CrtcLeaseStarted(lease);
+
+ *fd = lease_fd;
+ return Success;
+}
+
+static void
+drmmode_terminate_lease(RRLeasePtr lease)
+{
+ ScreenPtr screen = lease->screen;
+ ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
+ AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn);
+ drmmode_lease_private_ptr lease_private = lease->devPrivate;
+
+ if (drmModeRevokeLease(pAMDGPUEnt->fd, lease_private->lessee_id) == 0) {
+ free(lease_private);
+ lease->devPrivate = NULL;
+ xf86CrtcLeaseTerminated(lease);
+ }
+}
+
+#endif
+
static const xf86CrtcConfigFuncsRec drmmode_xf86crtc_config_funcs = {
- drmmode_xf86crtc_resize
+ .resize = drmmode_xf86crtc_resize,
+#ifdef HAVE_RRLEASE
+ .create_lease = drmmode_create_lease,
+ .terminate_lease = drmmode_terminate_lease
+#endif
};
static void
@@ -3640,6 +3770,11 @@ restart_destroy:
changed = TRUE;
}
+#ifdef HAVE_RRLEASE
+ /* Check to see if a lessee has disappeared */
+ drmmode_validate_leases(scrn);
+#endif
+
if (changed && dixPrivateKeyRegistered(rrPrivKey)) {
#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,14,99,2,0)
RRSetChanged(xf86ScrnToScreen(scrn));
diff --git a/src/drmmode_display.h b/src/drmmode_display.h
index 0f0227c..8b3482f 100644
--- a/src/drmmode_display.h
+++ b/src/drmmode_display.h
@@ -157,6 +157,11 @@ typedef struct {
int tear_free;
} drmmode_output_private_rec, *drmmode_output_private_ptr;
+#ifdef HAVE_RRLEASE
+typedef struct {
+ uint32_t lessee_id;
+} drmmode_lease_private_rec, *drmmode_lease_private_ptr;
+#endif
enum drmmode_flip_sync {
FLIP_VSYNC,