From 2802071fa9d421a2998d4971671b5c4275d3d435 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 19 Jul 2012 14:12:59 +1000 Subject: 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 --- configure.ac | 8 +++ src/driver.c | 136 +++++++++++++++++++++++++++++++++++++++++--------- src/drmmode_display.c | 117 ++++++++++++++++++++++++++++++++++++++++++- src/drmmode_display.h | 27 ++++++++++ 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 -- cgit v1.2.3