summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2012-07-19 14:12:59 +1000
committerDave Airlie <airlied@redhat.com>2012-07-25 16:01:42 +1000
commit2802071fa9d421a2998d4971671b5c4275d3d435 (patch)
tree5a69b0fcc21d8c970e1e6e746dd1dceb26c93481
parent65054df028047137c7e6b1c749611c751041d7a5 (diff)
modesetting: add output slave support.
This allows the driver to operate as an output slave. It adds scan out pixmap, and the capability checks to make sure they available. Signed-off-by: Dave Airlie <airlied@redhat.com>
-rw-r--r--configure.ac8
-rw-r--r--src/driver.c136
-rw-r--r--src/drmmode_display.c117
-rw-r--r--src/drmmode_display.h27
4 files changed, 264 insertions, 24 deletions
diff --git a/configure.ac b/configure.ac
index 45a1b9f..e1b3727 100644
--- a/configure.ac
+++ b/configure.ac
@@ -82,6 +82,14 @@ if test x"$udev" = xyes; then
AC_DEFINE(HAVE_UDEV,1,[Enable udev-based monitor hotplug detection])
fi
+SAVE_CFLAGS=$CFLAGS
+SAVE_LIBS=$LIBS
+CFLAGS=$DRM_CFLAGS
+LIBS=$DRM_LIBS
+AC_CHECK_FUNCS([drmPrimeFDToHandle])
+CFLAGS=$SAVE_CFLAGS
+LIBS=$SAVE_LIBS
+
DRIVER_NAME=modesetting
AC_SUBST([DRIVER_NAME])
AC_SUBST([moduledir])
diff --git a/src/driver.c b/src/driver.c
index 86be277..371c171 100644
--- a/src/driver.c
+++ b/src/driver.c
@@ -401,21 +401,20 @@ GetRec(ScrnInfoPtr pScrn)
return TRUE;
}
-static void dispatch_dirty(ScreenPtr pScreen)
+static int dispatch_dirty_region(ScrnInfoPtr scrn,
+ PixmapPtr pixmap,
+ DamagePtr damage,
+ int fb_id)
{
- ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen);
modesettingPtr ms = modesettingPTR(scrn);
- RegionPtr dirty = DamageRegion(ms->damage);
+ RegionPtr dirty = DamageRegion(damage);
unsigned num_cliprects = REGION_NUM_RECTS(dirty);
if (num_cliprects) {
- drmModeClip *clip = malloc(num_cliprects * sizeof(drmModeClip));
+ drmModeClip *clip = alloca(num_cliprects * sizeof(drmModeClip));
BoxPtr rect = REGION_RECTS(dirty);
int i, ret;
-
- if (!clip)
- return;
-
+
/* XXX no need for copy? */
for (i = 0; i < num_cliprects; i++, rect++) {
clip[i].x1 = rect->x1;
@@ -425,25 +424,71 @@ static void dispatch_dirty(ScreenPtr pScreen)
}
/* TODO query connector property to see if this is needed */
- ret = drmModeDirtyFB(ms->fd, ms->drmmode.fb_id, clip, num_cliprects);
- free(clip);
+ ret = drmModeDirtyFB(ms->fd, fb_id, clip, num_cliprects);
+ DamageEmpty(damage);
if (ret) {
- if (ret == -EINVAL || ret == -ENOSYS) {
- ms->dirty_enabled = FALSE;
- DamageUnregister(&pScreen->GetScreenPixmap(pScreen)->drawable, ms->damage);
- DamageDestroy(ms->damage);
- ms->damage = NULL;
- xf86DrvMsg(scrn->scrnIndex, X_INFO, "Disabling kernel dirty updates, not required.\n");
- return;
- } else
- ErrorF("%s: failed to send dirty (%i, %s)\n",
- __func__, ret, strerror(-ret));
+ if (ret == -EINVAL)
+ return ret;
}
-
- DamageEmpty(ms->damage);
+ }
+ return 0;
+}
+
+static void dispatch_dirty(ScreenPtr pScreen)
+{
+ ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen);
+ modesettingPtr ms = modesettingPTR(scrn);
+ PixmapPtr pixmap = pScreen->GetScreenPixmap(pScreen);
+ int fb_id = ms->drmmode.fb_id;
+ int ret;
+
+ ret = dispatch_dirty_region(scrn, pixmap, ms->damage, fb_id);
+ if (ret == -EINVAL || ret == -ENOSYS) {
+ ms->dirty_enabled = FALSE;
+ DamageUnregister(&pScreen->GetScreenPixmap(pScreen)->drawable, ms->damage);
+ DamageDestroy(ms->damage);
+ ms->damage = NULL;
+ xf86DrvMsg(scrn->scrnIndex, X_INFO, "Disabling kernel dirty updates, not required.\n");
+ return;
+ }
+}
+
+#ifdef MODESETTING_OUTPUT_SLAVE_SUPPORT
+static void dispatch_dirty_crtc(ScrnInfoPtr scrn, xf86CrtcPtr crtc)
+{
+ modesettingPtr ms = modesettingPTR(scrn);
+ PixmapPtr pixmap = crtc->randr_crtc->scanout_pixmap;
+ msPixmapPrivPtr ppriv = msGetPixmapPriv(&ms->drmmode, pixmap);
+ drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
+ DamagePtr damage = drmmode_crtc->slave_damage;
+ int fb_id = ppriv->fb_id;
+ int ret;
+
+ ret = dispatch_dirty_region(scrn, pixmap, damage, fb_id);
+ if (ret) {
+
}
}
+static void dispatch_slave_dirty(ScreenPtr pScreen)
+{
+ ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen);
+ xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
+ int c;
+
+ for (c = 0; c < xf86_config->num_crtc; c++) {
+ xf86CrtcPtr crtc = xf86_config->crtc[c];
+
+ if (!crtc->randr_crtc)
+ continue;
+ if (!crtc->randr_crtc->scanout_pixmap)
+ continue;
+
+ dispatch_dirty_crtc(scrn, crtc);
+ }
+}
+#endif
+
static void msBlockHandler(BLOCKHANDLER_ARGS_DECL)
{
SCREEN_PTR(arg);
@@ -452,8 +497,13 @@ static void msBlockHandler(BLOCKHANDLER_ARGS_DECL)
pScreen->BlockHandler = ms->BlockHandler;
pScreen->BlockHandler(BLOCKHANDLER_ARGS);
pScreen->BlockHandler = msBlockHandler;
+#ifdef MODESETTING_OUTPUT_SLAVE_SUPPORT
+ if (pScreen->isGPU)
+ dispatch_slave_dirty(pScreen);
+ else
+#endif
if (ms->dirty_enabled)
- dispatch_dirty(pScreen);
+ dispatch_dirty(pScreen);
}
static void
@@ -555,6 +605,16 @@ PreInit(ScrnInfoPtr pScrn, int flags)
ms->drmmode.fd = ms->fd;
+#ifdef MODESETTING_OUTPUT_SLAVE_SUPPORT
+ pScrn->capabilities = 0;
+#ifdef DRM_CAP_PRIME
+ ret = drmGetCap(ms->fd, DRM_CAP_PRIME, &value);
+ if (ret == 0) {
+ if (value & DRM_PRIME_CAP_IMPORT)
+ pScrn->capabilities |= RR_Capability_SinkOutput;
+ }
+#endif
+#endif
drmmode_get_default_bpp(pScrn, &ms->drmmode, &defaultdepth, &defaultbpp);
if (defaultdepth == 24 && defaultbpp == 24)
bppflags = Support24bppFb;
@@ -719,6 +779,25 @@ msShadowInit(ScreenPtr pScreen)
return TRUE;
}
+#ifdef MODESETTING_OUTPUT_SLAVE_SUPPORT
+static Bool
+msSetSharedPixmapBacking(PixmapPtr ppix, void *fd_handle)
+{
+ ScreenPtr screen = ppix->drawable.pScreen;
+ ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
+ modesettingPtr ms = modesettingPTR(scrn);
+ Bool ret;
+ int size = ppix->devKind * ppix->drawable.height;
+ int ihandle = (int)(long)fd_handle;
+
+ ret = drmmode_SetSlaveBO(ppix, &ms->drmmode, ihandle, ppix->devKind, size);
+ if (ret == FALSE)
+ return ret;
+
+ return TRUE;
+}
+#endif
+
static Bool
ScreenInit(SCREEN_INIT_ARGS_DECL)
{
@@ -757,6 +836,13 @@ ScreenInit(SCREEN_INIT_ARGS_DECL)
if (!miSetPixmapDepths())
return FALSE;
+#ifdef MODESETTING_OUTPUT_SLAVE_SUPPORT
+ if (!dixRegisterScreenSpecificPrivateKey(pScreen, &ms->drmmode.pixmapPrivateKeyRec,
+ PRIVATE_PIXMAP, sizeof(msPixmapPrivRec))) {
+ return FALSE;
+ }
+#endif
+
pScrn->memPhysBase = 0;
pScrn->fbOffset = 0;
@@ -816,6 +902,10 @@ ScreenInit(SCREEN_INIT_ARGS_DECL)
ms->BlockHandler = pScreen->BlockHandler;
pScreen->BlockHandler = msBlockHandler;
+#ifdef MODESETTING_OUTPUT_SLAVE_SUPPORT
+ pScreen->SetSharedPixmapBacking = msSetSharedPixmapBacking;
+#endif
+
if (!xf86CrtcScreenInit(pScreen))
return FALSE;
diff --git a/src/drmmode_display.c b/src/drmmode_display.c
index 9ee553e..5e38265 100644
--- a/src/drmmode_display.c
+++ b/src/drmmode_display.c
@@ -138,6 +138,43 @@ static int dumb_bo_destroy(int fd, struct dumb_bo *bo)
return 0;
}
+#ifdef MODESETTING_OUTPUT_SLAVE_SUPPORT
+static struct dumb_bo *dumb_get_bo_from_handle(int fd, int handle, int pitch, int size)
+{
+ struct dumb_bo *bo;
+ int ret;
+
+ bo = calloc(1, sizeof(*bo));
+ if (!bo)
+ return NULL;
+
+ ret = drmPrimeFDToHandle(fd, handle, &bo->handle);
+ if (ret) {
+ free(bo);
+ return NULL;
+ }
+ bo->pitch = pitch;
+ bo->size = size;
+ return bo;
+}
+#endif
+
+#ifdef MODESETTING_OUTPUT_SLAVE_SUPPORT
+Bool drmmode_SetSlaveBO(PixmapPtr ppix,
+ drmmode_ptr drmmode,
+ int fd_handle, int pitch, int size)
+{
+ msPixmapPrivPtr ppriv = msGetPixmapPriv(drmmode, ppix);
+
+ ppriv->backing_bo = dumb_get_bo_from_handle(drmmode->fd, fd_handle, pitch, size);
+ if (!ppriv->backing_bo)
+ return FALSE;
+
+ close(fd_handle);
+ return TRUE;
+}
+#endif
+
static void
drmmode_ConvertFromKMode(ScrnInfoPtr scrn,
drmModeModeInfo *kmode,
@@ -274,7 +311,7 @@ drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
int output_count = 0;
Bool ret = TRUE;
int i;
- int fb_id;
+ uint32_t fb_id;
drmModeModeInfo kmode;
int height;
@@ -338,6 +375,13 @@ drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
drmmode_ConvertToKMode(crtc->scrn, &kmode, mode);
fb_id = drmmode->fb_id;
+#ifdef MODESETTING_OUTPUT_SLAVE_SUPPORT
+ if (crtc->randr_crtc->scanout_pixmap) {
+ msPixmapPrivPtr ppriv = msGetPixmapPriv(drmmode, crtc->randr_crtc->scanout_pixmap);
+ fb_id = ppriv->fb_id;
+ x = y = 0;
+ } else
+#endif
if (drmmode_crtc->rotate_fb_id) {
fb_id = drmmode_crtc->rotate_fb_id;
x = y = 0;
@@ -455,6 +499,54 @@ drmmode_crtc_gamma_set(xf86CrtcPtr crtc, uint16_t *red, uint16_t *green,
size, red, green, blue);
}
+#ifdef MODESETTING_OUTPUT_SLAVE_SUPPORT
+static Bool
+drmmode_set_scanout_pixmap(xf86CrtcPtr crtc, PixmapPtr ppix)
+{
+ drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
+ drmmode_ptr drmmode = drmmode_crtc->drmmode;
+ msPixmapPrivPtr ppriv;
+ void *ptr;
+
+ if (!ppix) {
+ if (crtc->randr_crtc->scanout_pixmap) {
+ ppriv = msGetPixmapPriv(drmmode, crtc->randr_crtc->scanout_pixmap);
+ drmModeRmFB(drmmode->fd, ppriv->fb_id);
+ }
+ if (drmmode_crtc->slave_damage) {
+ DamageUnregister(&crtc->randr_crtc->scanout_pixmap->drawable,
+ drmmode_crtc->slave_damage);
+ drmmode_crtc->slave_damage = NULL;
+ }
+ return TRUE;
+ }
+
+ ppriv = msGetPixmapPriv(drmmode, ppix);
+ if (!drmmode_crtc->slave_damage) {
+ drmmode_crtc->slave_damage = DamageCreate(NULL, NULL,
+ DamageReportNone,
+ TRUE,
+ crtc->randr_crtc->pScreen,
+ NULL);
+ }
+ ptr = drmmode_map_slave_bo(drmmode, ppriv);
+ ppix->devPrivate.ptr = ptr;
+ DamageRegister(&ppix->drawable, drmmode_crtc->slave_damage);
+
+ if (ppriv->fb_id == 0) {
+ int r;
+ r = drmModeAddFB(drmmode->fd, ppix->drawable.width,
+ ppix->drawable.height,
+ ppix->drawable.depth,
+ ppix->drawable.bitsPerPixel,
+ ppix->devKind,
+ ppriv->backing_bo->handle,
+ &ppriv->fb_id);
+ }
+ return TRUE;
+}
+#endif
+
static const xf86CrtcFuncsRec drmmode_crtc_funcs = {
.dpms = drmmode_crtc_dpms,
.set_mode_major = drmmode_set_mode_major,
@@ -466,6 +558,9 @@ static const xf86CrtcFuncsRec drmmode_crtc_funcs = {
.gamma_set = drmmode_crtc_gamma_set,
.destroy = NULL, /* XXX */
+#ifdef MODESETTING_OUTPUT_SLAVE_SUPPORT
+ .set_scanout_pixmap = drmmode_set_scanout_pixmap,
+#endif
};
static void
@@ -1065,6 +1160,10 @@ Bool drmmode_pre_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int cpp)
/* workout clones */
drmmode_clones_init(pScrn, drmmode);
+#if XF86_CRTC_VERSION >= 5
+ xf86ProviderSetup(pScrn, NULL, "modesetting");
+#endif
+
xf86InitialConfiguration(pScrn, TRUE);
return TRUE;
@@ -1324,6 +1423,22 @@ void *drmmode_map_front_bo(drmmode_ptr drmmode)
}
+#ifdef MODESETTING_OUTPUT_SLAVE_SUPPORT
+void *drmmode_map_slave_bo(drmmode_ptr drmmode, msPixmapPrivPtr ppriv)
+{
+ int ret;
+
+ if (ppriv->backing_bo->ptr)
+ return ppriv->backing_bo->ptr;
+
+ ret = dumb_bo_map(drmmode->fd, ppriv->backing_bo);
+ if (ret)
+ return NULL;
+
+ return ppriv->backing_bo->ptr;
+}
+#endif
+
Bool drmmode_map_cursor_bos(ScrnInfoPtr pScrn, drmmode_ptr drmmode)
{
xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
diff --git a/src/drmmode_display.h b/src/drmmode_display.h
index fa280bd..24f7960 100644
--- a/src/drmmode_display.h
+++ b/src/drmmode_display.h
@@ -32,6 +32,11 @@
#include "libudev.h"
#endif
+/* the perfect storm */
+#if XF86_CRTC_VERSION >= 5 && defined(HAVE_DRMPRIMEFDTOHANDLE) && HAVE_SCREEN_SPECIFIC_PRIVATE_KEYS
+#define MODESETTING_OUTPUT_SLAVE_SUPPORT 1
+#endif
+
struct dumb_bo {
uint32_t handle;
uint32_t size;
@@ -58,6 +63,9 @@ typedef struct {
Bool shadow_enable;
void *shadow_fb;
+#ifdef HAVE_SCREEN_SPECIFIC_PRIVATE_KEYS
+ DevPrivateKeyRec pixmapPrivateKeyRec;
+#endif
} drmmode_rec, *drmmode_ptr;
typedef struct {
@@ -67,6 +75,7 @@ typedef struct {
struct dumb_bo *cursor_bo;
unsigned rotate_fb_id;
uint16_t lut_r[256], lut_g[256], lut_b[256];
+ DamagePtr slave_damage;
} drmmode_crtc_private_rec, *drmmode_crtc_private_ptr;
typedef struct {
@@ -90,6 +99,23 @@ typedef struct {
int enc_clone_mask;
} drmmode_output_private_rec, *drmmode_output_private_ptr;
+#ifdef MODESETTING_OUTPUT_SLAVE_SUPPORT
+typedef struct _msPixmapPriv {
+ uint32_t fb_id;
+ struct dumb_bo *backing_bo; /* if this pixmap is backed by a dumb bo */
+} msPixmapPrivRec, *msPixmapPrivPtr;
+
+
+extern DevPrivateKeyRec msPixmapPrivateKeyRec;
+#define msPixmapPrivateKey (&msPixmapPrivateKeyRec)
+
+#define msGetPixmapPriv(drmmode, p) ((msPixmapPrivPtr)dixGetPrivateAddr(&(p)->devPrivates, &(drmmode)->pixmapPrivateKeyRec))
+
+void *drmmode_map_slave_bo(drmmode_ptr drmmode, msPixmapPrivPtr ppriv);
+Bool drmmode_SetSlaveBO(PixmapPtr ppix,
+ drmmode_ptr drmmode,
+ int fd_handle, int pitch, int size);
+#endif
extern Bool drmmode_pre_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int cpp);
void drmmode_adjust_frame(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int x, int y, int flags);
@@ -105,6 +131,7 @@ Bool drmmode_map_cursor_bos(ScrnInfoPtr pScrn, drmmode_ptr drmmode);
void drmmode_free_bos(ScrnInfoPtr pScrn, drmmode_ptr drmmode);
void drmmode_get_default_bpp(ScrnInfoPtr pScrn, drmmode_ptr drmmmode, int *depth, int *bpp);
+
#ifndef DRM_CAP_DUMB_PREFERRED_DEPTH
#define DRM_CAP_DUMB_PREFERRED_DEPTH 3
#endif