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>
This commit is contained in:
Dave Airlie 2012-07-19 14:12:59 +10:00
parent fa171c5a81
commit 02811f1a9c
3 changed files with 256 additions and 24 deletions

View File

@ -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;

View File

@ -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);

View File

@ -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