diff options
author | Michel Dänzer <michel.daenzer@amd.com> | 2016-09-01 12:54:13 +0900 |
---|---|---|
committer | Michel Dänzer <michel@daenzer.net> | 2016-09-06 17:13:16 +0900 |
commit | eda1f3df6aaed683036369fe8820da4dac3c2ae2 (patch) | |
tree | 2baa7e50b05c9eb6eac1dd8275651151a65e9053 /src/radeon_kms.c | |
parent | 2f6e5fb15f1a9ce523c85550e493f8bda9d0c00f (diff) |
Synchronize scanout pixmaps for TearFree
Copy the damaged areas which are still valid in the other scanout pixmap
from there, then only copy the remaining damaged area from the screen
pixmap.
This is slightly more efficient (only needs one Damage record instead of
two, and only needs to copy each screen update across PCIe once with
ShadowPrimary and a discrete GPU), and will be significantly more
efficient for PRIME with the following change.
Reviewed-by: Alex Deucher <alexander.deucher@amd.com>
Diffstat (limited to 'src/radeon_kms.c')
-rw-r--r-- | src/radeon_kms.c | 92 |
1 files changed, 75 insertions, 17 deletions
diff --git a/src/radeon_kms.c b/src/radeon_kms.c index 568c49e3..bcaa024c 100644 --- a/src/radeon_kms.c +++ b/src/radeon_kms.c @@ -402,8 +402,6 @@ radeon_scanout_extents_intersect(xf86CrtcPtr xf86_crtc, BoxPtr extents, int w, return (extents->x1 < extents->x2 && extents->y1 < extents->y2); } -#ifdef RADEON_PIXMAP_SHARING - static RegionPtr transform_region(RegionPtr region, struct pict_f_transform *transform, int w, int h) @@ -442,6 +440,70 @@ transform_region(RegionPtr region, struct pict_f_transform *transform, return transformed; } +static void +radeon_sync_scanout_pixmaps(xf86CrtcPtr xf86_crtc, RegionPtr new_region, + int scanout_id) +{ + drmmode_crtc_private_ptr drmmode_crtc = xf86_crtc->driver_private; + DrawablePtr dst = &drmmode_crtc->scanout[scanout_id].pixmap->drawable; + DrawablePtr src = &drmmode_crtc->scanout[scanout_id ^ 1].pixmap->drawable; + RegionPtr last_region = &drmmode_crtc->scanout_last_region; + ScrnInfoPtr scrn = xf86_crtc->scrn; + ScreenPtr pScreen = scrn->pScreen; + RADEONInfoPtr info = RADEONPTR(scrn); + RegionRec remaining; + RegionPtr sync_region = NULL; + BoxRec extents; + Bool force; + GCPtr gc; + + if (RegionNil(last_region)) + return; + + RegionNull(&remaining); + RegionSubtract(&remaining, last_region, new_region); + if (RegionNil(&remaining)) + goto uninit; + + extents = *RegionExtents(&remaining); + if (!radeon_scanout_extents_intersect(xf86_crtc, &extents, dst->width, + dst->height)) + goto uninit; + +#if XF86_CRTC_VERSION >= 4 + if (xf86_crtc->driverIsPerformingTransform) { + sync_region = transform_region(&remaining, + &xf86_crtc->f_framebuffer_to_crtc, + dst->width, dst->height); + } else +#endif /* XF86_CRTC_VERSION >= 4 */ + { + sync_region = RegionDuplicate(&remaining); + RegionTranslate(sync_region, -xf86_crtc->x, -xf86_crtc->y); + } + + force = info->accel_state->force; + info->accel_state->force = TRUE; + + gc = GetScratchGC(dst->depth, pScreen); + if (gc) { + ValidateGC(dst, gc); + gc->funcs->ChangeClip(gc, CT_REGION, sync_region, 0); + sync_region = NULL; + gc->ops->CopyArea(src, dst, gc, 0, 0, dst->width, dst->height, 0, 0); + FreeScratchGC(gc); + } + + info->accel_state->force = force; + + uninit: + if (sync_region) + RegionDestroy(sync_region); + RegionUninit(&remaining); +} + +#ifdef RADEON_PIXMAP_SHARING + static RegionPtr dirty_region(PixmapDirtyUpdatePtr dirty) { @@ -660,13 +722,12 @@ static Bool radeon_scanout_do_update(xf86CrtcPtr xf86_crtc, int scanout_id) { drmmode_crtc_private_ptr drmmode_crtc = xf86_crtc->driver_private; - ScrnInfoPtr scrn; - DamagePtr pDamage; - RegionPtr pRegion; + RegionPtr pRegion = DamageRegion(drmmode_crtc->scanout_damage); + ScrnInfoPtr scrn = xf86_crtc->scrn; + ScreenPtr pScreen = scrn->pScreen; + RADEONInfoPtr info = RADEONPTR(scrn); DrawablePtr pDraw; - ScreenPtr pScreen; BoxRec extents; - RADEONInfoPtr info; Bool force; if (!xf86_crtc->enabled || @@ -674,24 +735,21 @@ radeon_scanout_do_update(xf86CrtcPtr xf86_crtc, int scanout_id) !drmmode_crtc->scanout[scanout_id].pixmap) return FALSE; - pDamage = drmmode_crtc->scanout[scanout_id].damage; - if (!pDamage) - return FALSE; - - pRegion = DamageRegion(pDamage); if (!RegionNotEmpty(pRegion)) return FALSE; pDraw = &drmmode_crtc->scanout[scanout_id].pixmap->drawable; - pScreen = pDraw->pScreen; extents = *RegionExtents(pRegion); - RegionEmpty(pRegion); if (!radeon_scanout_extents_intersect(xf86_crtc, &extents, pDraw->width, pDraw->height)) return FALSE; - scrn = xf86_crtc->scrn; - info = RADEONPTR(scrn); + if (info->tear_free) { + radeon_sync_scanout_pixmaps(xf86_crtc, pRegion, scanout_id); + RegionCopy(&drmmode_crtc->scanout_last_region, pRegion); + } + RegionEmpty(pRegion); + force = info->accel_state->force; info->accel_state->force = TRUE; @@ -807,7 +865,7 @@ radeon_scanout_update(xf86CrtcPtr xf86_crtc) drmmode_crtc->pending_dpms_mode != DPMSModeOn) return; - pDamage = drmmode_crtc->scanout[0].damage; + pDamage = drmmode_crtc->scanout_damage; if (!pDamage) return; |