> -----Original Message----- > From: amd-gfx [mailto:amd-gfx-boun...@lists.freedesktop.org] On Behalf > Of Michel Dänzer > Sent: Friday, September 02, 2016 6:04 AM > To: amd-gfx@lists.freedesktop.org > Subject: [PATCH xf86-video-ati 4/4] Make TearFree effective with PRIME > slave scanout > > From: Michel Dänzer <michel.daen...@amd.com> > > TearFree can now prevent tearing with any possible display > configuration. > > Note that with PRIME slave scanout, there may still be inter-GPU tearing > if the primary GPU uses a different driver. > > Signed-off-by: Michel Dänzer <michel.daen...@amd.com>
For the series: Reviewed-by: Alex Deucher <alexander.deuc...@amd.com> > --- > src/drmmode_display.c | 33 ++++++++++++--- > src/drmmode_display.h | 1 + > src/radeon_kms.c | 110 > ++++++++++++++++++++++++++++++++++++++++++++++---- > 3 files changed, 131 insertions(+), 13 deletions(-) > > diff --git a/src/drmmode_display.c b/src/drmmode_display.c > index 2b80c21..34f7735 100644 > --- a/src/drmmode_display.c > +++ b/src/drmmode_display.c > @@ -528,10 +528,19 @@ drmmode_crtc_scanout_destroy(drmmode_ptr > drmmode, > static void > drmmode_crtc_scanout_free(drmmode_crtc_private_ptr drmmode_crtc) > { > - drmmode_crtc_scanout_destroy(drmmode_crtc->drmmode, > - &drmmode_crtc->scanout[0]); > - drmmode_crtc_scanout_destroy(drmmode_crtc->drmmode, > - &drmmode_crtc->scanout[1]); > + if (drmmode_crtc->flip_pending) { > + drmmode_crtc->scanout_destroy[0] = drmmode_crtc- > >scanout[0]; > + drmmode_crtc->scanout[0].pixmap = NULL; > + drmmode_crtc->scanout[0].bo = NULL; > + drmmode_crtc->scanout_destroy[1] = drmmode_crtc- > >scanout[1]; > + drmmode_crtc->scanout[1].pixmap = NULL; > + drmmode_crtc->scanout[1].bo = NULL; > + } else { > + drmmode_crtc_scanout_destroy(drmmode_crtc- > >drmmode, > + &drmmode_crtc->scanout[0]); > + drmmode_crtc_scanout_destroy(drmmode_crtc- > >drmmode, > + &drmmode_crtc->scanout[1]); > + } > > if (drmmode_crtc->scanout_damage) { > DamageDestroy(drmmode_crtc->scanout_damage); > @@ -1120,11 +1129,12 @@ static Bool > drmmode_set_scanout_pixmap(xf86CrtcPtr crtc, PixmapPtr ppix) > { > drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; > + RADEONInfoPtr info = RADEONPTR(crtc->scrn); > > if (!ppix) { > if (crtc->randr_crtc->scanout_pixmap) > PixmapStopDirtyTracking(crtc->randr_crtc- > >scanout_pixmap, > - drmmode_crtc- > >scanout[0].pixmap); > + drmmode_crtc- > >scanout[drmmode_crtc->scanout_id].pixmap); > drmmode_crtc_scanout_free(drmmode_crtc); > return TRUE; > } > @@ -1134,6 +1144,14 @@ drmmode_set_scanout_pixmap(xf86CrtcPtr crtc, > PixmapPtr ppix) > ppix->drawable.height)) > return FALSE; > > + if (info->tear_free && > + !drmmode_crtc_scanout_create(crtc, &drmmode_crtc- > >scanout[1], > + ppix->drawable.width, > + ppix->drawable.height)) { > + drmmode_crtc_scanout_free(drmmode_crtc); > + return FALSE; > + } > + > #ifdef HAS_DIRTYTRACKING_ROTATION > PixmapStartDirtyTracking(ppix, drmmode_crtc->scanout[0].pixmap, > 0, 0, 0, 0, RR_Rotate_0); > @@ -2200,6 +2218,11 @@ drmmode_clear_pending_flip(xf86CrtcPtr crtc) > > drmmode_crtc_dpms(crtc, drmmode_crtc- > >pending_dpms_mode); > } > + > + drmmode_crtc_scanout_destroy(drmmode_crtc->drmmode, > + &drmmode_crtc->scanout_destroy[0]); > + drmmode_crtc_scanout_destroy(drmmode_crtc->drmmode, > + &drmmode_crtc->scanout_destroy[1]); > } > > static void > diff --git a/src/drmmode_display.h b/src/drmmode_display.h > index 5df9773..7602eb8 100644 > --- a/src/drmmode_display.h > +++ b/src/drmmode_display.h > @@ -84,6 +84,7 @@ typedef struct { > struct radeon_bo *cursor_bo; > struct drmmode_scanout rotate; > struct drmmode_scanout scanout[2]; > + struct drmmode_scanout scanout_destroy[2]; > DamagePtr scanout_damage; > RegionRec scanout_last_region; > unsigned scanout_id; > diff --git a/src/radeon_kms.c b/src/radeon_kms.c > index bcaa024..3418716 100644 > --- a/src/radeon_kms.c > +++ b/src/radeon_kms.c > @@ -597,31 +597,55 @@ slave_has_sync_shared_pixmap(ScrnInfoPtr scrn, > PixmapDirtyUpdatePtr dirty) > return slave_scrn->driverName == scrn->driverName; > } > > -void > -radeon_prime_scanout_update_handler(xf86CrtcPtr crtc, uint32_t frame, > uint64_t usec, > - void *event_data) > +static Bool > +radeon_prime_scanout_do_update(xf86CrtcPtr crtc, unsigned scanout_id) > { > ScrnInfoPtr scrn = crtc->scrn; > ScreenPtr screen = scrn->pScreen; > + RADEONInfoPtr info = RADEONPTR(scrn); > drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; > PixmapPtr scanoutpix = crtc->randr_crtc->scanout_pixmap; > PixmapDirtyUpdatePtr dirty; > + Bool ret = FALSE; > > xorg_list_for_each_entry(dirty, &screen->pixmap_dirty_list, ent) { > - if (dirty->src == scanoutpix && > - dirty->slave_dst == drmmode_crtc->scanout[0].pixmap) { > + if (dirty->src == scanoutpix) { > RegionPtr region; > > if (master_has_sync_shared_pixmap(scrn, dirty)) > radeon_sync_shared_pixmap(dirty); > > region = dirty_region(dirty); > + if (RegionNil(region)) > + goto destroy; > + > + if (info->tear_free) { > + RegionTranslate(region, crtc->x, crtc->y); > + radeon_sync_scanout_pixmaps(crtc, region, scanout_id); > + radeon_cs_flush_indirect(scrn); > + RegionCopy(&drmmode_crtc->scanout_last_region, region); > + RegionTranslate(region, -crtc->x, -crtc->y); > + dirty->slave_dst = drmmode_crtc- > >scanout[scanout_id].pixmap; > + } > + > redisplay_dirty(dirty, region); > + ret = TRUE; > + destroy: > RegionDestroy(region); > break; > } > } > > + return ret; > +} > + > +void > +radeon_prime_scanout_update_handler(xf86CrtcPtr crtc, uint32_t frame, > uint64_t usec, > + void *event_data) > +{ > + drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; > + > + radeon_prime_scanout_do_update(crtc, 0); > drmmode_crtc->scanout_update_pending = FALSE; > } > > @@ -679,8 +703,74 @@ > radeon_prime_scanout_update(PixmapDirtyUpdatePtr dirty) > } > > static void > +radeon_prime_scanout_flip_abort(xf86CrtcPtr crtc, void *event_data) > +{ > + drmmode_crtc_private_ptr drmmode_crtc = event_data; > + > + drmmode_crtc->scanout_update_pending = FALSE; > + drmmode_clear_pending_flip(crtc); > +} > + > +static void > +radeon_prime_scanout_flip(PixmapDirtyUpdatePtr ent) > +{ > + ScreenPtr screen = ent->slave_dst->drawable.pScreen; > + ScrnInfoPtr scrn = xf86ScreenToScrn(screen); > + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); > + xf86CrtcPtr crtc = NULL; > + drmmode_crtc_private_ptr drmmode_crtc = NULL; > + uintptr_t drm_queue_seq; > + unsigned scanout_id; > + int c; > + > + /* Find the CRTC which is scanning out from this slave pixmap */ > + for (c = 0; c < xf86_config->num_crtc; c++) { > + crtc = xf86_config->crtc[c]; > + drmmode_crtc = crtc->driver_private; > + scanout_id = drmmode_crtc->scanout_id; > + if (drmmode_crtc->scanout[scanout_id].pixmap == ent->slave_dst) > + break; > + } > + > + if (c == xf86_config->num_crtc || > + !crtc->enabled || > + drmmode_crtc->scanout_update_pending || > + !drmmode_crtc->scanout[drmmode_crtc->scanout_id].pixmap || > + drmmode_crtc->pending_dpms_mode != DPMSModeOn) > + return; > + > + scanout_id = drmmode_crtc->scanout_id ^ 1; > + if (!radeon_prime_scanout_do_update(crtc, scanout_id)) > + return; > + > + drm_queue_seq = radeon_drm_queue_alloc(crtc, > + > RADEON_DRM_QUEUE_CLIENT_DEFAULT, > + > RADEON_DRM_QUEUE_ID_DEFAULT, > + drmmode_crtc, NULL, > + radeon_prime_scanout_flip_abort); > + if (drm_queue_seq == RADEON_DRM_QUEUE_ERROR) { > + xf86DrvMsg(scrn->scrnIndex, X_WARNING, > + "Allocating DRM event queue entry failed for PRIME > flip.\n"); > + return; > + } > + > + if (drmModePageFlip(drmmode_crtc->drmmode->fd, drmmode_crtc- > >mode_crtc->crtc_id, > + drmmode_crtc->scanout[scanout_id].fb_id, > + DRM_MODE_PAGE_FLIP_EVENT, > (void*)drm_queue_seq)) { > + xf86DrvMsg(scrn->scrnIndex, X_WARNING, "flip queue failed in %s: > %s\n", > + __func__, strerror(errno)); > + return; > + } > + > + drmmode_crtc->scanout_id = scanout_id; > + drmmode_crtc->scanout_update_pending = TRUE; > + drmmode_crtc->flip_pending = TRUE; > +} > + > +static void > radeon_dirty_update(ScrnInfoPtr scrn) > { > + RADEONInfoPtr info = RADEONPTR(scrn); > ScreenPtr screen = scrn->pScreen; > PixmapDirtyUpdatePtr ent; > RegionPtr region; > @@ -700,10 +790,14 @@ radeon_dirty_update(ScrnInfoPtr scrn) > > region = dirty_region(region_ent); > > - if (RegionNotEmpty(region)) > - radeon_prime_scanout_update(ent); > - else > + if (RegionNotEmpty(region)) { > + if (info->tear_free) > + radeon_prime_scanout_flip(ent); > + else > + > radeon_prime_scanout_update(ent); > + } else { > DamageEmpty(region_ent->damage); > + } > > RegionDestroy(region); > } else { > -- > 2.9.3 > > _______________________________________________ > amd-gfx mailing list > amd-gfx@lists.freedesktop.org > https://lists.freedesktop.org/mailman/listinfo/amd-gfx _______________________________________________ amd-gfx mailing list amd-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/amd-gfx