summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichel Dänzer <michel.daenzer@amd.com>2016-09-08 17:15:03 +0900
committerMichel Dänzer <michel@daenzer.net>2016-09-09 19:02:47 +0900
commit61ceefe17fe9e6ffbaaad0e216b2bd37fd39f47d (patch)
tree5326f5eab7762fad1273cf76f56e5718a6e53c05
parent6d31fb124d4418e64c949bde9ed1facf95967762 (diff)
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>
-rw-r--r--src/amdgpu_kms.c83
1 files changed, 72 insertions, 11 deletions
diff --git a/src/amdgpu_kms.c b/src/amdgpu_kms.c
index aaaee1a..0342ef8 100644
--- a/src/amdgpu_kms.c
+++ b/src/amdgpu_kms.c
@@ -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