summaryrefslogtreecommitdiff
path: root/dix
diff options
context:
space:
mode:
authorDave Airlie <airlied@gmail.com>2015-06-30 14:54:42 +1000
committerKeith Packard <keithp@keithp.com>2015-07-08 11:13:09 -0700
commit90db5edf119187f8b1b9207c8c384d6cd7ef9edc (patch)
treece513a85f857e677b0b91a692f5d5cabd64c8145 /dix
parent991712f1e8deeb6289ee0abd9910e279d6396246 (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.c180
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;
}