Track damage accurately for RandR 1.4 slave scanout

This further reduces the PCIe bandwidth usage.

(Ported from radeon commit b0867063abb197b9134166706d99fcbe5f204bb5,
 plus leak fix from 5a57005178fc13b6f7e513458ca6dae72a3e5783)
Reviewed-by: Alex Deucher <alexander.deucher@amd.com>
This commit is contained in:
Michel Dänzer
2016-09-08 17:15:03 +09:00
committed by Michel Dänzer
parent 6d31fb124d
commit 61ceefe17f

View File

@@ -304,23 +304,77 @@ static Bool AMDGPUCreateScreenResources_KMS(ScreenPtr pScreen)
}
#ifdef AMDGPU_PIXMAP_SHARING
static RegionPtr
dirty_region(PixmapDirtyUpdatePtr dirty)
{
RegionPtr damageregion = DamageRegion(dirty->damage);
RegionPtr dstregion;
#ifdef HAS_DIRTYTRACKING_ROTATION
if (dirty->rotation != RR_Rotate_0) {
BoxPtr boxes = RegionRects(damageregion);
int nboxes = RegionNumRects(damageregion);
xRectanglePtr rects = malloc(nboxes * sizeof(*rects));
int dst_w = dirty->slave_dst->drawable.width;
int dst_h = dirty->slave_dst->drawable.height;
int nrects = 0;
BoxRec box;
int i;
for (i = 0; i < nboxes; i++) {
box.x1 = boxes[i].x1;
box.x2 = boxes[i].x2;
box.y1 = boxes[i].y1;
box.y2 = boxes[i].y2;
pixman_f_transform_bounds(&dirty->f_inverse, &box);
box.x1 = max(box.x1, 0);
box.y1 = max(box.y1, 0);
box.x2 = min(box.x2, dst_w);
box.y2 = min(box.y2, dst_h);
if (box.x1 >= box.x2 || box.y1 >= box.y2)
continue;
rects[nrects].x = box.x1;
rects[nrects].y = box.y1;
rects[nrects].width = box.x2 - box.x1;
rects[nrects].height = box.y2 - box.y1;
nrects++;
}
dstregion = RegionFromRects(nrects, rects, CT_UNSORTED);
free(rects);
} else
#endif
{
RegionRec pixregion;
dstregion = RegionDuplicate(damageregion);
RegionTranslate(dstregion, -dirty->x, -dirty->y);
PixmapRegionInit(&pixregion, dirty->slave_dst);
RegionIntersect(dstregion, dstregion, &pixregion);
RegionUninit(&pixregion);
}
return dstregion;
}
static void
redisplay_dirty(PixmapDirtyUpdatePtr dirty)
redisplay_dirty(PixmapDirtyUpdatePtr dirty, RegionPtr region)
{
ScrnInfoPtr scrn = xf86ScreenToScrn(dirty->src->drawable.pScreen);
RegionRec pixregion;
PixmapRegionInit(&pixregion, dirty->slave_dst);
DamageRegionAppend(&dirty->slave_dst->drawable, &pixregion);
if (dirty->slave_dst->master_pixmap)
DamageRegionAppend(&dirty->slave_dst->drawable, region);
#ifdef HAS_DIRTYTRACKING_ROTATION
PixmapSyncDirtyHelper(dirty);
#else
PixmapSyncDirtyHelper(dirty, &pixregion);
PixmapSyncDirtyHelper(dirty, region);
#endif
amdgpu_glamor_flush(scrn);
DamageRegionProcessPending(&dirty->slave_dst->drawable);
RegionUninit(&pixregion);
if (dirty->slave_dst->master_pixmap)
DamageRegionProcessPending(&dirty->slave_dst->drawable);
DamageEmpty(dirty->damage);
}
@@ -346,7 +400,10 @@ amdgpu_prime_scanout_update_handler(xf86CrtcPtr crtc, uint32_t frame, uint64_t u
xorg_list_for_each_entry(dirty, &screen->pixmap_dirty_list, ent) {
if (dirty->src == scanoutpix &&
dirty->slave_dst == drmmode_crtc->scanout[0].pixmap) {
redisplay_dirty(dirty);
RegionPtr region = dirty_region(dirty);
redisplay_dirty(dirty, region);
RegionDestroy(region);
break;
}
}
@@ -410,20 +467,24 @@ amdgpu_prime_scanout_update(PixmapDirtyUpdatePtr dirty)
static void amdgpu_dirty_update(ScreenPtr screen)
{
RegionPtr region;
PixmapDirtyUpdatePtr ent;
if (xorg_list_is_empty(&screen->pixmap_dirty_list))
return;
xorg_list_for_each_entry(ent, &screen->pixmap_dirty_list, ent) {
region = DamageRegion(ent->damage);
RegionPtr region = dirty_region(ent);
if (RegionNotEmpty(region)) {
if (screen->isGPU)
amdgpu_prime_scanout_update(ent);
else
redisplay_dirty(ent);
redisplay_dirty(ent, region);
} else {
DamageEmpty(ent->damage);
}
RegionDestroy(region);
}
}
#endif