diff options
-rw-r--r-- | configure.ac | 18 | ||||
-rw-r--r-- | src/drmmode_display.c | 137 | ||||
-rw-r--r-- | src/drmmode_display.h | 5 |
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, |