diff options
author | Dave Airlie <airlied@gmail.com> | 2015-06-30 14:54:42 +1000 |
---|---|---|
committer | Keith Packard <keithp@keithp.com> | 2015-07-08 11:13:09 -0700 |
commit | 90db5edf119187f8b1b9207c8c384d6cd7ef9edc (patch) | |
tree | ce513a85f857e677b0b91a692f5d5cabd64c8145 /dix | |
parent | 991712f1e8deeb6289ee0abd9910e279d6396246 (diff) |
prime: add rotation support for offloaded outputs (v2)
One of the lacking features with output offloading was
that screen rotation didn't work at all.
This patch makes 0/90/180/270 rotation work with USB output
and GPU outputs.
When it allocates the shared pixmap it allocates it rotated,
and any updates to the shared pixmap are done using a composite
path that does the rotation. The slave GPU then doesn't need
to know about the rotation and just displays the pixmap.
v2:
rewrite the sync dirty helper to use the dst pixmap, and
avoid any strange hobbits and rotations.
This breaks ABI in two places.
Signed-off-by: Dave Airlie <airlied@redhat.com>
Reviewed-by: Alex Deucher <alexander.deucher@amd.com>
Signed-off-by: Keith Packard <keithp@keithp.com>
Diffstat (limited to 'dix')
-rw-r--r-- | dix/pixmap.c | 180 |
1 files changed, 136 insertions, 44 deletions
diff --git a/dix/pixmap.c b/dix/pixmap.c index 00e298f5c..05aebc42c 100644 --- a/dix/pixmap.c +++ b/dix/pixmap.c @@ -40,7 +40,9 @@ from The Open Group. #include "gcstruct.h" #include "servermd.h" #include "site.h" - +#include "X11/extensions/render.h" +#include "picturestr.h" +#include "randrstr.h" /* * Scratch pixmap management and device independent pixmap allocation * function. @@ -164,9 +166,10 @@ PixmapPtr PixmapShareToSlave(PixmapPtr pixmap, ScreenPtr slave) } Bool -PixmapStartDirtyTracking2(PixmapPtr src, - PixmapPtr slave_dst, - int x, int y, int dst_x, int dst_y) +PixmapStartDirtyTracking(PixmapPtr src, + PixmapPtr slave_dst, + int x, int y, int dst_x, int dst_y, + Rotation rotation) { ScreenPtr screen = src->drawable.pScreen; PixmapDirtyUpdatePtr dirty_update; @@ -181,11 +184,22 @@ PixmapStartDirtyTracking2(PixmapPtr src, dirty_update->y = y; dirty_update->dst_x = dst_x; dirty_update->dst_y = dst_y; - + dirty_update->rotation = rotation; dirty_update->damage = DamageCreate(NULL, NULL, DamageReportNone, TRUE, src->drawable.pScreen, src->drawable.pScreen); + + if (rotation != RR_Rotate_0) { + RRTransformCompute(x, y, + slave_dst->drawable.width, + slave_dst->drawable.height, + rotation, + NULL, + &dirty_update->transform, + &dirty_update->f_transform, + &dirty_update->f_inverse); + } if (!dirty_update->damage) { free(dirty_update); return FALSE; @@ -197,14 +211,6 @@ PixmapStartDirtyTracking2(PixmapPtr src, } Bool -PixmapStartDirtyTracking(PixmapPtr src, - PixmapPtr slave_dst, - int x, int y) -{ - return PixmapStartDirtyTracking2(src, slave_dst, x, y, 0, 0); -} - -Bool PixmapStopDirtyTracking(PixmapPtr src, PixmapPtr slave_dst) { ScreenPtr screen = src->drawable.pScreen; @@ -220,42 +226,16 @@ PixmapStopDirtyTracking(PixmapPtr src, PixmapPtr slave_dst) return TRUE; } -/* - * this function can possibly be improved and optimised, by clipping - * instead of iterating - */ -Bool PixmapSyncDirtyHelper(PixmapDirtyUpdatePtr dirty, RegionPtr dirty_region) +static void +PixmapDirtyCopyArea(PixmapPtr dst, + PixmapDirtyUpdatePtr dirty, + RegionPtr dirty_region) { ScreenPtr pScreen = dirty->src->drawable.pScreen; int n; BoxPtr b; - RegionPtr region = DamageRegion(dirty->damage); GCPtr pGC; - PixmapPtr dst; - SourceValidateProcPtr SourceValidate; - - /* - * SourceValidate is used by the software cursor code - * to pull the cursor off of the screen when reading - * bits from the frame buffer. Bypassing this function - * leaves the software cursor in place - */ - SourceValidate = pScreen->SourceValidate; - pScreen->SourceValidate = NULL; - - RegionTranslate(dirty_region, dirty->x, dirty->y); - RegionIntersect(dirty_region, dirty_region, region); - - if (RegionNil(dirty_region)) { - RegionUninit(dirty_region); - return FALSE; - } - dst = dirty->slave_dst->master_pixmap; - if (!dst) - dst = dirty->slave_dst; - - RegionTranslate(dirty_region, -dirty->x, -dirty->y); n = RegionNumRects(dirty_region); b = RegionRects(dirty_region); @@ -271,11 +251,123 @@ Bool PixmapSyncDirtyHelper(PixmapDirtyUpdatePtr dirty, RegionPtr dirty_region) h = dst_box.y2 - dst_box.y1; pGC->ops->CopyArea(&dirty->src->drawable, &dst->drawable, pGC, - dirty->x + dst_box.x1, dirty->y + dst_box.y1, w, h, dirty->dst_x + dst_box.x1, dirty->dst_y + dst_box.y1); + dirty->x + dst_box.x1, dirty->y + dst_box.y1, w, h, + dirty->dst_x + dst_box.x1, + dirty->dst_y + dst_box.y1); b++; } FreeScratchGC(pGC); +} +static void +PixmapDirtyCompositeRotate(PixmapPtr dst_pixmap, + PixmapDirtyUpdatePtr dirty, + RegionPtr dirty_region) +{ + ScreenPtr pScreen = dirty->src->drawable.pScreen; + PictFormatPtr format = PictureWindowFormat(pScreen->root); + PicturePtr src, dst; + XID include_inferiors = IncludeInferiors; + int n = RegionNumRects(dirty_region); + BoxPtr b = RegionRects(dirty_region); + int error; + + src = CreatePicture(None, + &dirty->src->drawable, + format, + CPSubwindowMode, + &include_inferiors, serverClient, &error); + if (!src) + return; + + dst = CreatePicture(None, + &dst_pixmap->drawable, + format, 0L, NULL, serverClient, &error); + if (!dst) + return; + + error = SetPictureTransform(src, &dirty->transform); + if (error) + return; + while (n--) { + BoxRec dst_box; + + dst_box = *b; + dst_box.x1 += dirty->x; + dst_box.x2 += dirty->x; + dst_box.y1 += dirty->y; + dst_box.y2 += dirty->y; + pixman_f_transform_bounds(&dirty->f_inverse, &dst_box); + + CompositePicture(PictOpSrc, + src, NULL, dst, + dst_box.x1, + dst_box.y1, + 0, 0, + dst_box.x1, + dst_box.y1, + dst_box.x2 - dst_box.x1, + dst_box.y2 - dst_box.y1); + b++; + } + + FreePicture(src, None); + FreePicture(dst, None); +} + +/* + * this function can possibly be improved and optimised, by clipping + * instead of iterating + * Drivers are free to implement their own version of this. + */ +Bool PixmapSyncDirtyHelper(PixmapDirtyUpdatePtr dirty) +{ + ScreenPtr pScreen = dirty->src->drawable.pScreen; + RegionPtr region = DamageRegion(dirty->damage); + PixmapPtr dst; + SourceValidateProcPtr SourceValidate; + RegionRec pixregion; + BoxRec box; + + dst = dirty->slave_dst->master_pixmap; + if (!dst) + dst = dirty->slave_dst; + + box.x1 = 0; + box.y1 = 0; + if (dirty->rotation == RR_Rotate_90 || + dirty->rotation == RR_Rotate_270) { + box.x2 = dst->drawable.height; + box.y2 = dst->drawable.width; + } else { + box.x2 = dst->drawable.width; + box.y2 = dst->drawable.height; + } + RegionInit(&pixregion, &box, 1); + + /* + * SourceValidate is used by the software cursor code + * to pull the cursor off of the screen when reading + * bits from the frame buffer. Bypassing this function + * leaves the software cursor in place + */ + SourceValidate = pScreen->SourceValidate; + pScreen->SourceValidate = NULL; + + RegionTranslate(&pixregion, dirty->x, dirty->y); + RegionIntersect(&pixregion, &pixregion, region); + + if (RegionNil(&pixregion)) { + RegionUninit(&pixregion); + return FALSE; + } + + RegionTranslate(&pixregion, -dirty->x, -dirty->y); + + if (!pScreen->root || dirty->rotation == RR_Rotate_0) + PixmapDirtyCopyArea(dst, dirty, &pixregion); + else + PixmapDirtyCompositeRotate(dst, dirty, &pixregion); pScreen->SourceValidate = SourceValidate; return TRUE; } |