diff --git a/hw/xfree86/drivers/modesetting/driver.c b/hw/xfree86/drivers/modesetting/driver.c index 97a74044e..ab3b0283d 100644 --- a/hw/xfree86/drivers/modesetting/driver.c +++ b/hw/xfree86/drivers/modesetting/driver.c @@ -529,20 +529,14 @@ dispatch_dirty(ScreenPtr pScreen) } static void -dispatch_dirty_crtc(ScrnInfoPtr scrn, xf86CrtcPtr crtc) +dispatch_dirty_pixmap(ScrnInfoPtr scrn, xf86CrtcPtr crtc, PixmapPtr ppix) { modesettingPtr ms = modesettingPTR(scrn); - drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; - PixmapPtr pixmap = drmmode_crtc->prime_pixmap; - DamagePtr damage = drmmode_crtc->slave_damage; - msPixmapPrivPtr ppriv = msGetPixmapPriv(&ms->drmmode, pixmap); + msPixmapPrivPtr ppriv = msGetPixmapPriv(&ms->drmmode, ppix); + DamagePtr damage = ppriv->slave_damage; int fb_id = ppriv->fb_id; - int ret; - ret = dispatch_dirty_region(scrn, pixmap, damage, fb_id); - if (ret) { - - } + dispatch_dirty_region(scrn, ppix, damage, fb_id); } static void @@ -558,10 +552,11 @@ dispatch_slave_dirty(ScreenPtr pScreen) if (!drmmode_crtc) continue; - if (!drmmode_crtc->prime_pixmap) - continue; - dispatch_dirty_crtc(scrn, crtc); + if (drmmode_crtc->prime_pixmap) + dispatch_dirty_pixmap(scrn, crtc, drmmode_crtc->prime_pixmap); + if (drmmode_crtc->prime_pixmap_back) + dispatch_dirty_pixmap(scrn, crtc, drmmode_crtc->prime_pixmap_back); } } @@ -972,10 +967,46 @@ msUpdatePacked(ScreenPtr pScreen, shadowBufPtr pBuf) shadowUpdatePacked(pScreen, pBuf); } +static Bool +msEnableSharedPixmapFlipping(RRCrtcPtr crtc, PixmapPtr front, PixmapPtr back) +{ + ScreenPtr screen = crtc->pScreen; + ScrnInfoPtr scrn = xf86ScreenToScrn(screen); + modesettingPtr ms = modesettingPTR(scrn); + xf86CrtcPtr xf86Crtc = crtc->devPrivate; + + if (!xf86Crtc) + return FALSE; + + /* Not supported if we can't flip */ + if (!ms->drmmode.pageflip) + return FALSE; + + /* Not currently supported with reverse PRIME */ + if (ms->drmmode.reverse_prime_offload_mode) + return FALSE; + + return drmmode_EnableSharedPixmapFlipping(xf86Crtc, &ms->drmmode, + front, back); +} + +static void +msDisableSharedPixmapFlipping(RRCrtcPtr crtc) +{ + ScreenPtr screen = crtc->pScreen; + ScrnInfoPtr scrn = xf86ScreenToScrn(screen); + modesettingPtr ms = modesettingPTR(scrn); + xf86CrtcPtr xf86Crtc = crtc->devPrivate; + + if (xf86Crtc) + drmmode_DisableSharedPixmapFlipping(xf86Crtc, &ms->drmmode); +} + static Bool CreateScreenResources(ScreenPtr pScreen) { ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); + rrScrPrivPtr pScrPriv = rrGetScrPriv(pScreen); modesettingPtr ms = modesettingPTR(pScrn); PixmapPtr rootPixmap; Bool ret; @@ -1034,6 +1065,10 @@ CreateScreenResources(ScreenPtr pScreen) return FALSE; } } + + pScrPriv->rrEnableSharedPixmapFlipping = msEnableSharedPixmapFlipping; + pScrPriv->rrDisableSharedPixmapFlipping = msDisableSharedPixmapFlipping; + return ret; } @@ -1096,6 +1131,39 @@ msSetSharedPixmapBacking(PixmapPtr ppix, void *fd_handle) #endif } +static Bool +msSharedPixmapNotifyDamage(PixmapPtr ppix) +{ + Bool ret = FALSE; + int c; + + ScreenPtr screen = ppix->drawable.pScreen; + ScrnInfoPtr scrn = xf86ScreenToScrn(screen); + modesettingPtr ms = modesettingPTR(scrn); + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); + + msPixmapPrivPtr ppriv = msGetPixmapPriv(&ms->drmmode, ppix); + + if (!ppriv->wait_for_damage) + return ret; + ppriv->wait_for_damage = FALSE; + + for (c = 0; c < xf86_config->num_crtc; c++) { + xf86CrtcPtr crtc = xf86_config->crtc[c]; + drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; + + if (!drmmode_crtc) + continue; + if (!(drmmode_crtc->prime_pixmap && drmmode_crtc->prime_pixmap_back)) + continue; + + // Received damage on master screen pixmap, schedule present on vblank + ret |= drmmode_SharedPixmapPresentOnVBlank(ppix, crtc, &ms->drmmode); + } + + return ret; +} + static Bool SetMaster(ScrnInfoPtr pScrn) { @@ -1260,6 +1328,8 @@ ScreenInit(ScreenPtr pScreen, int argc, char **argv) pScreen->StartPixmapTracking = PixmapStartDirtyTracking; pScreen->StopPixmapTracking = PixmapStopDirtyTracking; + pScreen->SharedPixmapNotifyDamage = msSharedPixmapNotifyDamage; + if (!xf86CrtcScreenInit(pScreen)) return FALSE; diff --git a/hw/xfree86/drivers/modesetting/drmmode_display.c b/hw/xfree86/drivers/modesetting/drmmode_display.c index cce9a3378..2915b7801 100644 --- a/hw/xfree86/drivers/modesetting/drmmode_display.c +++ b/hw/xfree86/drivers/modesetting/drmmode_display.c @@ -229,6 +229,239 @@ drmmode_SetSlaveBO(PixmapPtr ppix, return TRUE; } +static Bool +drmmode_SharedPixmapPresent(PixmapPtr ppix, xf86CrtcPtr crtc, + drmmode_ptr drmmode) +{ + ScreenPtr master = crtc->randr_crtc->pScreen->current_master; + + if (master->PresentSharedPixmap(ppix)) { + /* Success, queue flip to back target */ + if (drmmode_SharedPixmapFlip(ppix, crtc, drmmode)) + return TRUE; + + xf86DrvMsg(drmmode->scrn->scrnIndex, X_WARNING, + "drmmode_SharedPixmapFlip() failed, trying again next vblank\n"); + + return drmmode_SharedPixmapPresentOnVBlank(ppix, crtc, drmmode); + } + + /* Failed to present, try again on next vblank after damage */ + if (master->RequestSharedPixmapNotifyDamage) { + msPixmapPrivPtr ppriv = msGetPixmapPriv(drmmode, ppix); + + /* Set flag first in case we are immediately notified */ + ppriv->wait_for_damage = TRUE; + + if (master->RequestSharedPixmapNotifyDamage(ppix)) + return TRUE; + else + ppriv->wait_for_damage = FALSE; + } + + /* Damage notification not available, just try again on vblank */ + return drmmode_SharedPixmapPresentOnVBlank(ppix, crtc, drmmode); +} + +struct vblank_event_args { + PixmapPtr frontTarget; + PixmapPtr backTarget; + xf86CrtcPtr crtc; + drmmode_ptr drmmode; + Bool flip; +}; +static void +drmmode_SharedPixmapVBlankEventHandler(uint64_t frame, uint64_t usec, + void *data) +{ + struct vblank_event_args *args = data; + + drmmode_crtc_private_ptr drmmode_crtc = args->crtc->driver_private; + + if (args->flip) { + /* frontTarget is being displayed, update crtc to reflect */ + drmmode_crtc->prime_pixmap = args->frontTarget; + drmmode_crtc->prime_pixmap_back = args->backTarget; + + /* Safe to present on backTarget, no longer displayed */ + drmmode_SharedPixmapPresent(args->backTarget, args->crtc, args->drmmode); + } else { + /* backTarget is still being displayed, present on frontTarget */ + drmmode_SharedPixmapPresent(args->frontTarget, args->crtc, args->drmmode); + } + + free(args); +} + +static void +drmmode_SharedPixmapVBlankEventAbort(void *data) +{ + struct vblank_event_args *args = data; + + msGetPixmapPriv(args->drmmode, args->frontTarget)->flip_seq = 0; + + free(args); +} + +Bool +drmmode_SharedPixmapPresentOnVBlank(PixmapPtr ppix, xf86CrtcPtr crtc, + drmmode_ptr drmmode) +{ + drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; + msPixmapPrivPtr ppriv = msGetPixmapPriv(drmmode, ppix); + + drmVBlank vbl; + struct vblank_event_args *event_args; + + if (ppix == drmmode_crtc->prime_pixmap) + return FALSE; /* Already flipped to this pixmap */ + if (ppix != drmmode_crtc->prime_pixmap_back) + return FALSE; /* Pixmap is not a scanout pixmap for CRTC */ + + event_args = calloc(1, sizeof(*event_args)); + if (!event_args) + return FALSE; + + event_args->frontTarget = ppix; + event_args->backTarget = drmmode_crtc->prime_pixmap; + event_args->crtc = crtc; + event_args->drmmode = drmmode; + event_args->flip = FALSE; + + ppriv->flip_seq = + ms_drm_queue_alloc(crtc, event_args, + drmmode_SharedPixmapVBlankEventHandler, + drmmode_SharedPixmapVBlankEventAbort); + + vbl.request.type = + DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT | drmmode_crtc->vblank_pipe; + vbl.request.sequence = 1; + vbl.request.signal = (unsigned long) ppriv->flip_seq; + + return drmWaitVBlank(drmmode->fd, &vbl) >= 0; +} + +Bool +drmmode_SharedPixmapFlip(PixmapPtr frontTarget, xf86CrtcPtr crtc, + drmmode_ptr drmmode) +{ + drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; + msPixmapPrivPtr ppriv_front = msGetPixmapPriv(drmmode, frontTarget); + + struct vblank_event_args *event_args; + + event_args = calloc(1, sizeof(*event_args)); + if (!event_args) + return FALSE; + + event_args->frontTarget = frontTarget; + event_args->backTarget = drmmode_crtc->prime_pixmap; + event_args->crtc = crtc; + event_args->drmmode = drmmode; + event_args->flip = TRUE; + + ppriv_front->flip_seq = + ms_drm_queue_alloc(crtc, event_args, + drmmode_SharedPixmapVBlankEventHandler, + drmmode_SharedPixmapVBlankEventAbort); + + if (drmModePageFlip(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, + ppriv_front->fb_id, DRM_MODE_PAGE_FLIP_EVENT, + (void *)(intptr_t) ppriv_front->flip_seq) < 0) { + ms_drm_abort_seq(crtc->scrn, ppriv_front->flip_seq); + return FALSE; + } + + return TRUE; +} + +static Bool +drmmode_InitSharedPixmapFlipping(xf86CrtcPtr crtc, drmmode_ptr drmmode) +{ + drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; + + if (!drmmode_crtc->enable_flipping) + return FALSE; + + if (drmmode_crtc->flipping_active) + return TRUE; + + drmmode_crtc->flipping_active = + drmmode_SharedPixmapPresent(drmmode_crtc->prime_pixmap_back, + crtc, drmmode); + + return drmmode_crtc->flipping_active; +} + +static void +drmmode_FiniSharedPixmapFlipping(xf86CrtcPtr crtc, drmmode_ptr drmmode) +{ + uint32_t seq; + drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; + + if (!drmmode_crtc->flipping_active) + return; + + drmmode_crtc->flipping_active = FALSE; + + /* Abort page flip event handler on prime_pixmap */ + seq = msGetPixmapPriv(drmmode, drmmode_crtc->prime_pixmap)->flip_seq; + if (seq) + ms_drm_abort_seq(crtc->scrn, seq); + + /* Abort page flip event handler on prime_pixmap_back */ + seq = msGetPixmapPriv(drmmode, + drmmode_crtc->prime_pixmap_back)->flip_seq; + if (seq) + ms_drm_abort_seq(crtc->scrn, seq); +} + +static Bool drmmode_set_target_scanout_pixmap(xf86CrtcPtr crtc, PixmapPtr ppix, + PixmapPtr *target); + +Bool +drmmode_EnableSharedPixmapFlipping(xf86CrtcPtr crtc, drmmode_ptr drmmode, + PixmapPtr front, PixmapPtr back) +{ + drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; + + drmmode_crtc->enable_flipping = TRUE; + + /* Set front scanout pixmap */ + drmmode_crtc->enable_flipping &= + drmmode_set_target_scanout_pixmap(crtc, front, + &drmmode_crtc->prime_pixmap); + if (!drmmode_crtc->enable_flipping) + return FALSE; + + /* Set back scanout pixmap */ + drmmode_crtc->enable_flipping &= + drmmode_set_target_scanout_pixmap(crtc, back, + &drmmode_crtc->prime_pixmap_back); + if (!drmmode_crtc->enable_flipping) { + drmmode_set_target_scanout_pixmap(crtc, NULL, + &drmmode_crtc->prime_pixmap); + return FALSE; + } + + return TRUE; +} + +void +drmmode_DisableSharedPixmapFlipping(xf86CrtcPtr crtc, drmmode_ptr drmmode) +{ + drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; + + drmmode_crtc->enable_flipping = FALSE; + + drmmode_FiniSharedPixmapFlipping(crtc, drmmode); + + drmmode_set_target_scanout_pixmap(crtc, NULL, &drmmode_crtc->prime_pixmap); + + drmmode_set_target_scanout_pixmap(crtc, NULL, + &drmmode_crtc->prime_pixmap_back); +} + static void drmmode_ConvertFromKMode(ScrnInfoPtr scrn, drmModeModeInfo * kmode, DisplayModePtr mode) @@ -499,6 +732,9 @@ drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode, drmmode_crtc->need_modeset = FALSE; crtc->funcs->dpms(crtc, DPMSModeOn); + if (drmmode_crtc->prime_pixmap_back) + drmmode_InitSharedPixmapFlipping(crtc, drmmode); + /* go through all the outputs and force DPMS them back on? */ for (i = 0; i < xf86_config->num_output; i++) { xf86OutputPtr output = xf86_config->output[i]; @@ -629,7 +865,8 @@ drmmode_crtc_gamma_set(xf86CrtcPtr crtc, uint16_t * red, uint16_t * green, } static Bool -drmmode_set_scanout_pixmap_gpu(xf86CrtcPtr crtc, PixmapPtr ppix) +drmmode_set_target_scanout_pixmap_gpu(xf86CrtcPtr crtc, PixmapPtr ppix, + PixmapPtr *target) { ScreenPtr screen = xf86ScrnToScreen(crtc->scrn); PixmapPtr screenpix = screen->GetScreenPixmap(screen); @@ -638,13 +875,14 @@ drmmode_set_scanout_pixmap_gpu(xf86CrtcPtr crtc, PixmapPtr ppix) drmmode_ptr drmmode = drmmode_crtc->drmmode; int c, total_width = 0, max_height = 0, this_x = 0; - if (drmmode_crtc->prime_pixmap) { - PixmapStopDirtyTracking(drmmode_crtc->prime_pixmap, screenpix); + if (*target) { + PixmapStopDirtyTracking(*target, screenpix); if (drmmode->fb_id) { drmModeRmFB(drmmode->fd, drmmode->fb_id); drmmode->fb_id = 0; } drmmode_crtc->prime_pixmap_x = 0; + *target = NULL; } if (!ppix) @@ -679,41 +917,43 @@ drmmode_set_scanout_pixmap_gpu(xf86CrtcPtr crtc, PixmapPtr ppix) } drmmode_crtc->prime_pixmap_x = this_x; PixmapStartDirtyTracking(ppix, screenpix, 0, 0, this_x, 0, RR_Rotate_0); + *target = ppix; return TRUE; } static Bool -drmmode_set_scanout_pixmap_cpu(xf86CrtcPtr crtc, PixmapPtr ppix) +drmmode_set_target_scanout_pixmap_cpu(xf86CrtcPtr crtc, PixmapPtr ppix, + PixmapPtr *target) { drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; drmmode_ptr drmmode = drmmode_crtc->drmmode; msPixmapPrivPtr ppriv; void *ptr; - if (drmmode_crtc->prime_pixmap) { - ppriv = msGetPixmapPriv(drmmode, drmmode_crtc->prime_pixmap); + if (*target) { + ppriv = msGetPixmapPriv(drmmode, *target); drmModeRmFB(drmmode->fd, ppriv->fb_id); ppriv->fb_id = 0; - } - if (drmmode_crtc->slave_damage) { - DamageUnregister(drmmode_crtc->slave_damage); - drmmode_crtc->slave_damage = NULL; + if (ppriv->slave_damage) { + DamageUnregister(ppriv->slave_damage); + ppriv->slave_damage = NULL; + } } if (!ppix) 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); + if (!ppriv->slave_damage) { + ppriv->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); + DamageRegister(&ppix->drawable, ppriv->slave_damage); if (ppriv->fb_id == 0) { drmModeAddFB(drmmode->fd, ppix->drawable.width, @@ -722,25 +962,34 @@ drmmode_set_scanout_pixmap_cpu(xf86CrtcPtr crtc, PixmapPtr ppix) ppix->drawable.bitsPerPixel, ppix->devKind, ppriv->backing_bo->handle, &ppriv->fb_id); } + *target = ppix; return TRUE; } +static Bool +drmmode_set_target_scanout_pixmap(xf86CrtcPtr crtc, PixmapPtr ppix, + PixmapPtr *target) +{ + drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; + drmmode_ptr drmmode = drmmode_crtc->drmmode; + + if (drmmode->reverse_prime_offload_mode) + return drmmode_set_target_scanout_pixmap_gpu(crtc, ppix, target); + else + return drmmode_set_target_scanout_pixmap_cpu(crtc, ppix, target); +} + static Bool drmmode_set_scanout_pixmap(xf86CrtcPtr crtc, PixmapPtr ppix) { - Bool ret; drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; - drmmode_ptr drmmode = drmmode_crtc->drmmode; - if (drmmode->reverse_prime_offload_mode) - ret = drmmode_set_scanout_pixmap_gpu(crtc, ppix); - else - ret = drmmode_set_scanout_pixmap_cpu(crtc, ppix); + /* Use DisableSharedPixmapFlipping before switching to single buf */ + if (drmmode_crtc->enable_flipping) + return FALSE; - if (ret) - drmmode_crtc->prime_pixmap = ppix; - - return ret; + return drmmode_set_target_scanout_pixmap(crtc, ppix, + &drmmode_crtc->prime_pixmap); } static void * diff --git a/hw/xfree86/drivers/modesetting/drmmode_display.h b/hw/xfree86/drivers/modesetting/drmmode_display.h index 36c6e919a..3161bba3f 100644 --- a/hw/xfree86/drivers/modesetting/drmmode_display.h +++ b/hw/xfree86/drivers/modesetting/drmmode_display.h @@ -99,12 +99,12 @@ typedef struct { struct dumb_bo *cursor_bo; Bool cursor_up; uint16_t lut_r[256], lut_g[256], lut_b[256]; - DamagePtr slave_damage; drmmode_bo rotate_bo; unsigned rotate_fb_id; PixmapPtr prime_pixmap; + PixmapPtr prime_pixmap_back; unsigned prime_pixmap_x; /** @@ -120,6 +120,9 @@ typedef struct { /** @} */ Bool need_modeset; + + Bool enable_flipping; + Bool flipping_active; } drmmode_crtc_private_rec, *drmmode_crtc_private_ptr; typedef struct { @@ -146,6 +149,12 @@ typedef struct { typedef struct _msPixmapPriv { uint32_t fb_id; struct dumb_bo *backing_bo; /* if this pixmap is backed by a dumb bo */ + + DamagePtr slave_damage; + + /** Fields for flipping shared pixmaps */ + int flip_seq; /* seq of current page flip event handler */ + Bool wait_for_damage; /* if we have requested damage notification from source */ } msPixmapPrivRec, *msPixmapPrivPtr; extern DevPrivateKeyRec msPixmapPrivateKeyRec; @@ -164,6 +173,14 @@ Bool drmmode_SetSlaveBO(PixmapPtr ppix, drmmode_ptr drmmode, int fd_handle, int pitch, int size); +Bool drmmode_EnableSharedPixmapFlipping(xf86CrtcPtr crtc, drmmode_ptr drmmode, + PixmapPtr front, PixmapPtr back); +Bool drmmode_SharedPixmapPresentOnVBlank(PixmapPtr frontTarget, xf86CrtcPtr crtc, + drmmode_ptr drmmode); +Bool drmmode_SharedPixmapFlip(PixmapPtr frontTarget, xf86CrtcPtr crtc, + drmmode_ptr drmmode); +void drmmode_DisableSharedPixmapFlipping(xf86CrtcPtr crtc, drmmode_ptr drmmode); + 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); extern Bool drmmode_set_desired_modes(ScrnInfoPtr pScrn, drmmode_ptr drmmode, Bool set_hw);