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>
This commit is contained in:
Dave Airlie
2015-06-30 14:54:42 +10:00
committed by Keith Packard
parent 991712f1e8
commit 90db5edf11
8 changed files with 197 additions and 73 deletions

View File

@@ -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;
@@ -196,14 +210,6 @@ PixmapStartDirtyTracking2(PixmapPtr src,
return TRUE;
}
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)
{
@@ -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;
}