[PATCH 09/16] prime: add rotation support for offloaded outputs
Dave Airlie
airlied at gmail.com
Thu Jun 25 16:51:12 PDT 2015
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.
Signed-off-by: Dave Airlie <airlied at redhat.com>
---
dix/pixmap.c | 155 ++++++++++++++++++-----
hw/xfree86/drivers/modesetting/drmmode_display.c | 2 +-
hw/xfree86/modes/xf86Rotate.c | 2 +
include/pixmap.h | 12 +-
include/pixmapstr.h | 5 +
include/scrnintstr.h | 5 +-
randr/rrcrtc.c | 60 ++++++---
7 files changed, 179 insertions(+), 62 deletions(-)
diff --git a/dix/pixmap.c b/dix/pixmap.c
index 00e298f..a20c38d 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,6 +226,95 @@ PixmapStopDirtyTracking(PixmapPtr src, PixmapPtr slave_dst)
return TRUE;
}
+static void
+PixmapDirtyCopyArea(PixmapPtr dst,
+ PixmapDirtyUpdatePtr dirty,
+ RegionPtr dirty_region)
+{
+ ScreenPtr pScreen = dirty->src->drawable.pScreen;
+ int n;
+ BoxPtr b;
+ GCPtr pGC;
+
+ n = RegionNumRects(dirty_region);
+ b = RegionRects(dirty_region);
+
+ pGC = GetScratchGC(dirty->src->drawable.depth, pScreen);
+ ValidateGC(&dst->drawable, pGC);
+
+ while (n--) {
+ BoxRec dst_box;
+ int w, h;
+
+ dst_box = *b;
+ w = dst_box.x2 - dst_box.x1;
+ 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);
+ 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
@@ -227,10 +322,7 @@ PixmapStopDirtyTracking(PixmapPtr src, PixmapPtr slave_dst)
Bool PixmapSyncDirtyHelper(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;
@@ -242,6 +334,14 @@ Bool PixmapSyncDirtyHelper(PixmapDirtyUpdatePtr dirty, RegionPtr dirty_region)
*/
SourceValidate = pScreen->SourceValidate;
pScreen->SourceValidate = NULL;
+ /* nasty hobbits */
+ if (dirty->rotation == RR_Rotate_90 ||
+ dirty->rotation == RR_Rotate_270) {
+ int tmp;
+ tmp = dirty_region->extents.x2;
+ dirty_region->extents.x2 = dirty_region->extents.y2;
+ dirty_region->extents.y2 = tmp;
+ }
RegionTranslate(dirty_region, dirty->x, dirty->y);
RegionIntersect(dirty_region, dirty_region, region);
@@ -256,26 +356,11 @@ Bool PixmapSyncDirtyHelper(PixmapDirtyUpdatePtr dirty, RegionPtr dirty_region)
dst = dirty->slave_dst;
RegionTranslate(dirty_region, -dirty->x, -dirty->y);
- n = RegionNumRects(dirty_region);
- b = RegionRects(dirty_region);
-
- pGC = GetScratchGC(dirty->src->drawable.depth, pScreen);
- ValidateGC(&dst->drawable, pGC);
-
- while (n--) {
- BoxRec dst_box;
- int w, h;
-
- dst_box = *b;
- w = dst_box.x2 - dst_box.x1;
- 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);
- b++;
- }
- FreeScratchGC(pGC);
+ if (!pScreen->root || dirty->rotation == RR_Rotate_0)
+ PixmapDirtyCopyArea(dst, dirty, dirty_region);
+ else
+ PixmapDirtyCompositeRotate(dst, dirty, dirty_region);
pScreen->SourceValidate = SourceValidate;
return TRUE;
}
diff --git a/hw/xfree86/drivers/modesetting/drmmode_display.c b/hw/xfree86/drivers/modesetting/drmmode_display.c
index 506ea24..a5dfc2b 100644
--- a/hw/xfree86/drivers/modesetting/drmmode_display.c
+++ b/hw/xfree86/drivers/modesetting/drmmode_display.c
@@ -549,7 +549,7 @@ drmmode_set_scanout_pixmap_gpu(xf86CrtcPtr crtc, PixmapPtr ppix)
screen->height = screenpix->drawable.height = max_height;
}
drmmode_crtc->prime_pixmap_x = this_x;
- PixmapStartDirtyTracking2(ppix, screenpix, 0, 0, this_x, 0);
+ PixmapStartDirtyTracking(ppix, screenpix, 0, 0, this_x, 0, RR_Rotate_0);
return TRUE;
}
diff --git a/hw/xfree86/modes/xf86Rotate.c b/hw/xfree86/modes/xf86Rotate.c
index 01cc764..63f27ca 100644
--- a/hw/xfree86/modes/xf86Rotate.c
+++ b/hw/xfree86/modes/xf86Rotate.c
@@ -361,6 +361,8 @@ xf86CrtcRotate(xf86CrtcPtr crtc)
RRTransformPtr transform = NULL;
Bool damage = FALSE;
+ if (pScreen->isGPU)
+ return TRUE;
if (crtc->transformPresent)
transform = &crtc->transform;
diff --git a/include/pixmap.h b/include/pixmap.h
index 9656c3a..a553c2e 100644
--- a/include/pixmap.h
+++ b/include/pixmap.h
@@ -50,7 +50,7 @@ SOFTWARE.
#include "misc.h"
#include "screenint.h"
#include "regionstr.h"
-
+#include <X11/extensions/randr.h>
/* types for Drawable */
#define DRAWABLE_WINDOW 0
#define DRAWABLE_PIXMAP 1
@@ -115,16 +115,12 @@ extern _X_EXPORT void FreePixmap(PixmapPtr /*pPixmap */ );
extern _X_EXPORT PixmapPtr
PixmapShareToSlave(PixmapPtr pixmap, ScreenPtr slave);
+#define HAS_DIRTYTRACKING_ROTATION 1
extern _X_EXPORT Bool
PixmapStartDirtyTracking(PixmapPtr src,
PixmapPtr slave_dst,
- int x, int y);
-
-#define HAS_DIRTYTRACKING2 1
-extern _X_EXPORT Bool
-PixmapStartDirtyTracking2(PixmapPtr src,
- PixmapPtr slave_dst,
- int x, int y, int dst_x, int dst_y);
+ int x, int y, int dst_x, int dst_y,
+ Rotation rotation);
extern _X_EXPORT Bool
PixmapStopDirtyTracking(PixmapPtr src, PixmapPtr slave_dst);
diff --git a/include/pixmapstr.h b/include/pixmapstr.h
index 380e483..4bd2465 100644
--- a/include/pixmapstr.h
+++ b/include/pixmapstr.h
@@ -51,6 +51,8 @@ SOFTWARE.
#include "regionstr.h"
#include "privates.h"
#include "damage.h"
+#include <X11/extensions/randr.h>
+#include "picturestr.h"
typedef struct _Drawable {
unsigned char type; /* DRAWABLE_<type> */
@@ -91,6 +93,9 @@ typedef struct _PixmapDirtyUpdate {
DamagePtr damage;
struct xorg_list ent;
int dst_x, dst_y;
+ Rotation rotation;
+ PictTransform transform;
+ struct pixman_f_transform f_transform, f_inverse;
} PixmapDirtyUpdateRec;
static inline void
diff --git a/include/scrnintstr.h b/include/scrnintstr.h
index faf0563..a627fe7 100644
--- a/include/scrnintstr.h
+++ b/include/scrnintstr.h
@@ -55,6 +55,7 @@ SOFTWARE.
#include <X11/Xproto.h>
#include "dix.h"
#include "privates.h"
+#include <X11/extensions/randr.h>
typedef struct _PixmapFormat {
unsigned char depth;
@@ -340,7 +341,9 @@ typedef Bool (*SharePixmapBackingProcPtr)(PixmapPtr, ScreenPtr, void **);
typedef Bool (*SetSharedPixmapBackingProcPtr)(PixmapPtr, void *);
typedef Bool (*StartPixmapTrackingProcPtr)(PixmapPtr, PixmapPtr,
- int x, int y);
+ int x, int y,
+ int dst_x, int dst_y,
+ Rotation rotation);
typedef Bool (*StopPixmapTrackingProcPtr)(PixmapPtr, PixmapPtr);
diff --git a/randr/rrcrtc.c b/randr/rrcrtc.c
index e95b049..050d975 100644
--- a/randr/rrcrtc.c
+++ b/randr/rrcrtc.c
@@ -387,7 +387,7 @@ RRCrtcDetachScanoutPixmap(RRCrtcPtr crtc)
static Bool
rrCreateSharedPixmap(RRCrtcPtr crtc, int width, int height,
- int x, int y)
+ int x, int y, Rotation rotation)
{
PixmapPtr mpix, spix;
ScreenPtr master = crtc->pScreen->current_master;
@@ -434,13 +434,33 @@ rrCreateSharedPixmap(RRCrtcPtr crtc, int width, int height,
crtc->scanout_pixmap = spix;
- master->StartPixmapTracking(mscreenpix, spix, x, y);
+ master->StartPixmapTracking(mscreenpix, spix, x, y, 0, 0, rotation);
return TRUE;
}
+static void crtc_to_box(BoxPtr box, RRCrtcPtr crtc)
+{
+ box->x1 = crtc->x;
+ box->y1 = crtc->y;
+ switch (crtc->rotation) {
+ case RR_Rotate_0:
+ case RR_Rotate_180:
+ default:
+ box->x2 = crtc->x + crtc->mode->mode.width;
+ box->y2 = crtc->y + crtc->mode->mode.height;
+ break;
+ case RR_Rotate_90:
+ case RR_Rotate_270:
+ box->x2 = crtc->x + crtc->mode->mode.height;
+ box->y2 = crtc->y + crtc->mode->mode.width;
+ break;
+ }
+}
+
static Bool
rrCheckPixmapBounding(ScreenPtr pScreen,
- RRCrtcPtr rr_crtc, int x, int y, int w, int h)
+ RRCrtcPtr rr_crtc, Rotation rotation,
+ int x, int y, int w, int h)
{
RegionRec root_pixmap_region, total_region, new_crtc_region;
int c;
@@ -461,16 +481,19 @@ rrCheckPixmapBounding(ScreenPtr pScreen,
if (crtc == rr_crtc) {
newbox.x1 = x;
- newbox.x2 = x + w;
newbox.y1 = y;
- newbox.y2 = y + h;
+ if (rotation == RR_Rotate_90 ||
+ rotation == RR_Rotate_270) {
+ newbox.x2 = x + h;
+ newbox.y2 = y + w;
+ } else {
+ newbox.x2 = x + w;
+ newbox.y2 = y + h;
+ }
} else {
if (!crtc->mode)
continue;
- newbox.x1 = crtc->x;
- newbox.x2 = crtc->x + crtc->mode->mode.width;
- newbox.y1 = crtc->y;
- newbox.y2 = crtc->y + crtc->mode->mode.height;
+ crtc_to_box(&newbox, crtc);
}
RegionInit(&new_crtc_region, &newbox, 1);
RegionUnion(&total_region, &total_region, &new_crtc_region);
@@ -483,17 +506,20 @@ rrCheckPixmapBounding(ScreenPtr pScreen,
if (slave_crtc == rr_crtc) {
newbox.x1 = x;
- newbox.x2 = x + w;
newbox.y1 = y;
- newbox.y2 = y + h;
+ if (rotation == RR_Rotate_90 ||
+ rotation == RR_Rotate_270) {
+ newbox.x2 = x + h;
+ newbox.y2 = y + w;
+ } else {
+ newbox.x2 = x + w;
+ newbox.y2 = y + h;
+ }
}
else {
if (!slave_crtc->mode)
continue;
- newbox.x1 = slave_crtc->x;
- newbox.x2 = slave_crtc->x + slave_crtc->mode->mode.width;
- newbox.y1 = slave_crtc->y;
- newbox.y2 = slave_crtc->y + slave_crtc->mode->mode.height;
+ crtc_to_box(&newbox, slave_crtc);
}
RegionInit(&new_crtc_region, &newbox, 1);
RegionUnion(&total_region, &total_region, &new_crtc_region);
@@ -561,12 +587,12 @@ RRCrtcSet(RRCrtcPtr crtc,
height = mode->mode.height;
}
ret = rrCheckPixmapBounding(master, crtc,
- x, y, width, height);
+ rotation, x, y, width, height);
if (!ret)
return FALSE;
if (pScreen->current_master) {
- ret = rrCreateSharedPixmap(crtc, width, height, x, y);
+ ret = rrCreateSharedPixmap(crtc, width, height, x, y, rotation);
}
}
#if RANDR_12_INTERFACE
--
2.4.3
More information about the xorg-devel
mailing list