Commit 39317103 authored by Keith Packard's avatar Keith Packard

Add RandR reflection support.

Replace the ad-hoc transformation mechanisms with matrices.
Prepares for more general transformation as well.
parent 8773ad02
...@@ -676,7 +676,8 @@ xf86CrtcScreenInit (ScreenPtr screen) ...@@ -676,7 +676,8 @@ xf86CrtcScreenInit (ScreenPtr screen)
} }
if (c == config->num_crtc) if (c == config->num_crtc)
xf86RandR12SetRotations (screen, RR_Rotate_0 | RR_Rotate_90 | xf86RandR12SetRotations (screen, RR_Rotate_0 | RR_Rotate_90 |
RR_Rotate_180 | RR_Rotate_270); RR_Rotate_180 | RR_Rotate_270 |
RR_Reflect_X | RR_Reflect_Y);
else else
xf86RandR12SetRotations (screen, RR_Rotate_0); xf86RandR12SetRotations (screen, RR_Rotate_0);
......
...@@ -279,6 +279,17 @@ struct _xf86Crtc { ...@@ -279,6 +279,17 @@ struct _xf86Crtc {
* Track state of cursor associated with this CRTC * Track state of cursor associated with this CRTC
*/ */
Bool cursor_shown; Bool cursor_shown;
/**
* Current transformation matrix
*/
PictTransform crtc_to_framebuffer;
PictTransform framebuffer_to_crtc;
Bool transform_in_use;
/**
* Bounding box in screen space
*/
BoxRec bounds;
}; };
typedef struct _xf86OutputFuncs { typedef struct _xf86OutputFuncs {
......
...@@ -58,29 +58,73 @@ xf86_crtc_rotate_coord (Rotation rotation, ...@@ -58,29 +58,73 @@ xf86_crtc_rotate_coord (Rotation rotation,
int *x_src, int *x_src,
int *y_src) int *y_src)
{ {
int t;
switch (rotation & 0xf) {
case RR_Rotate_0:
break;
case RR_Rotate_90:
t = x_dst;
x_dst = height - y_dst - 1;
y_dst = t;
break;
case RR_Rotate_180:
x_dst = width - x_dst - 1;
y_dst = height - y_dst - 1;
break;
case RR_Rotate_270:
t = x_dst;
x_dst = y_dst;
y_dst = width - t - 1;
break;
}
if (rotation & RR_Reflect_X) if (rotation & RR_Reflect_X)
x_dst = width - x_dst - 1; x_dst = width - x_dst - 1;
if (rotation & RR_Reflect_Y) if (rotation & RR_Reflect_Y)
y_dst = height - y_dst - 1; y_dst = height - y_dst - 1;
*x_src = x_dst;
*y_src = y_dst;
}
/*
* Given a cursor source coordinate, rotate to a screen coordinate
*/
static void
xf86_crtc_rotate_coord_back (Rotation rotation,
int width,
int height,
int x_dst,
int y_dst,
int *x_src,
int *y_src)
{
int t;
if (rotation & RR_Reflect_X)
x_dst = width - x_dst - 1;
if (rotation & RR_Reflect_Y)
y_dst = height - y_dst - 1;
switch (rotation & 0xf) { switch (rotation & 0xf) {
case RR_Rotate_0: case RR_Rotate_0:
*x_src = x_dst;
*y_src = y_dst;
break; break;
case RR_Rotate_90: case RR_Rotate_90:
*x_src = height - y_dst - 1; t = x_dst;
*y_src = x_dst; x_dst = y_dst;
y_dst = width - t - 1;
break; break;
case RR_Rotate_180: case RR_Rotate_180:
*x_src = width - x_dst - 1; x_dst = width - x_dst - 1;
*y_src = height - y_dst - 1; y_dst = height - y_dst - 1;
break; break;
case RR_Rotate_270: case RR_Rotate_270:
*x_src = y_dst; t = x_dst;
*y_src = width - x_dst - 1; x_dst = height - y_dst - 1;
y_dst = t;
break; break;
} }
*x_src = x_dst;
*y_src = y_dst;
} }
/* /*
...@@ -261,49 +305,33 @@ xf86_crtc_set_cursor_position (xf86CrtcPtr crtc, int x, int y) ...@@ -261,49 +305,33 @@ xf86_crtc_set_cursor_position (xf86CrtcPtr crtc, int x, int y)
xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
xf86CursorInfoPtr cursor_info = xf86_config->cursor_info; xf86CursorInfoPtr cursor_info = xf86_config->cursor_info;
DisplayModePtr mode = &crtc->mode; DisplayModePtr mode = &crtc->mode;
int x_temp;
int y_temp;
Bool in_range; Bool in_range;
int dx, dy;
/*
* Move to crtc coordinate space
*/
x -= crtc->x;
y -= crtc->y;
/* /*
* Rotate * Transform position of cursor on screen
*/ */
switch ((crtc->rotation) & 0xf) { if (crtc->transform_in_use)
case RR_Rotate_0: {
break; PictVector v;
case RR_Rotate_90: v.vector[0] = IntToxFixed (x); v.vector[1] = IntToxFixed (y); v.vector[2] = IntToxFixed(1);
x_temp = y; PictureTransformPoint (&crtc->framebuffer_to_crtc, &v);
y_temp = mode->VDisplay - cursor_info->MaxWidth - x; x = xFixedToInt (v.vector[0]); y = xFixedToInt (v.vector[1]);
x = x_temp; }
y = y_temp; else
break; {
case RR_Rotate_180: x -= crtc->x;
x_temp = mode->HDisplay - cursor_info->MaxWidth - x; y -= crtc->y;
y_temp = mode->VDisplay - cursor_info->MaxHeight - y;
x = x_temp;
y = y_temp;
break;
case RR_Rotate_270:
x_temp = mode->HDisplay - cursor_info->MaxHeight - y;
y_temp = x;
x = x_temp;
y = y_temp;
break;
} }
/* /*
* Reflect * Transform position of cursor upper left corner
*/ */
if (crtc->rotation & RR_Reflect_X) xf86_crtc_rotate_coord_back (crtc->rotation,
x = mode->HDisplay - cursor_info->MaxWidth - x; cursor_info->MaxWidth,
if (crtc->rotation & RR_Reflect_Y) cursor_info->MaxHeight,
y = mode->VDisplay - cursor_info->MaxHeight - y; 0, 0, &dx, &dy);
x -= dx;
y -= dy;
/* /*
* Disable the cursor when it is outside the viewport * Disable the cursor when it is outside the viewport
......
...@@ -68,57 +68,204 @@ compWindowFormat (WindowPtr pWin) ...@@ -68,57 +68,204 @@ compWindowFormat (WindowPtr pWin)
compGetWindowVisual (pWin)); compGetWindowVisual (pWin));
} }
#define F(x) IntToxFixed(x)
static void static void
xf86TranslateBox (BoxPtr b, int dx, int dy) PictureTransformIdentity (PictTransformPtr matrix)
{
int i;
memset (matrix, '\0', sizeof (PictTransform));
for (i = 0; i < 3; i++)
matrix->matrix[i][i] = F(1);
}
static Bool
PictureTransformMultiply (PictTransformPtr dst, PictTransformPtr l, PictTransformPtr r)
{ {
b->x1 += dx; PictTransform d;
b->y1 += dy; int dx, dy;
b->x2 += dx; int o;
b->y2 += dy;
for (dy = 0; dy < 3; dy++)
for (dx = 0; dx < 3; dx++)
{
xFixed_48_16 v;
xFixed_32_32 partial;
v = 0;
for (o = 0; o < 3; o++)
{
partial = (xFixed_32_32) l->matrix[dy][o] * (xFixed_32_32) r->matrix[o][dx];
v += partial >> 16;
}
if (v > MAX_FIXED_48_16 || v < MIN_FIXED_48_16)
return FALSE;
d.matrix[dy][dx] = (xFixed) v;
}
*dst = d;
return TRUE;
} }
static void static void
xf86TransformBox (BoxPtr dst, BoxPtr src, Rotation rotation, PictureTransformInitScale (PictTransformPtr t, xFixed sx, xFixed sy)
int xoff, int yoff, {
int dest_width, int dest_height) memset (t, '\0', sizeof (PictTransform));
t->matrix[0][0] = sx;
t->matrix[1][1] = sy;
t->matrix[2][2] = F (1);
}
static xFixed
fixed_inverse (xFixed x)
{
return (xFixed) ((((xFixed_48_16) F(1)) * F(1)) / x);
}
static Bool
PictureTransformScale (PictTransformPtr forward,
PictTransformPtr reverse,
xFixed sx, xFixed sy)
{ {
BoxRec stmp = *src; PictTransform t;
xf86TranslateBox (&stmp, -xoff, -yoff); PictureTransformInitScale (&t, sx, sy);
switch (rotation & 0xf) { if (!PictureTransformMultiply (forward, &t, forward))
default: return FALSE;
case RR_Rotate_0: PictureTransformInitScale (&t, fixed_inverse (sx), fixed_inverse (sy));
*dst = stmp; if (!PictureTransformMultiply (reverse, reverse, &t))
break; return FALSE;
case RR_Rotate_90: return TRUE;
dst->x1 = stmp.y1; }
dst->y1 = dest_height - stmp.x2;
dst->x2 = stmp.y2; static void
dst->y2 = dest_height - stmp.x1; PictureTransformInitRotate (PictTransformPtr t, xFixed c, xFixed s)
break; {
case RR_Rotate_180: memset (t, '\0', sizeof (PictTransform));
dst->x1 = dest_width - stmp.x2; t->matrix[0][0] = c;
dst->y1 = dest_height - stmp.y2; t->matrix[0][1] = -s;
dst->x2 = dest_width - stmp.x1; t->matrix[1][0] = s;
dst->y2 = dest_height - stmp.y1; t->matrix[1][1] = c;
break; t->matrix[2][2] = F (1);
case RR_Rotate_270: }
dst->x1 = dest_width - stmp.y2;
dst->y1 = stmp.x1; static Bool
dst->y2 = stmp.x2; PictureTransformRotate (PictTransformPtr forward,
dst->x2 = dest_width - stmp.y1; PictTransformPtr reverse,
break; xFixed c, xFixed s)
} {
if (rotation & RR_Reflect_X) { PictTransform t;
int x1 = dst->x1; PictureTransformInitRotate (&t, c, s);
dst->x1 = dest_width - dst->x2; if (!PictureTransformMultiply (forward, &t, forward))
dst->x2 = dest_width - x1; return FALSE;
PictureTransformInitRotate (&t, c, -s);
if (!PictureTransformMultiply (reverse, reverse, &t))
return FALSE;
return TRUE;
}
static void
PictureTransformInitTranslate (PictTransformPtr t, xFixed tx, xFixed ty)
{
memset (t, '\0', sizeof (PictTransform));
t->matrix[0][0] = F (1);
t->matrix[0][2] = tx;
t->matrix[1][1] = F (1);
t->matrix[1][2] = ty;
t->matrix[2][2] = F (1);
}
static Bool
PictureTransformTranslate (PictTransformPtr forward,
PictTransformPtr reverse,
xFixed tx, xFixed ty)
{
PictTransform t;
PictureTransformInitTranslate (&t, tx, ty);
if (!PictureTransformMultiply (forward, &t, forward))
return FALSE;
PictureTransformInitTranslate (&t, -tx, -ty);
if (!PictureTransformMultiply (reverse, reverse, &t))
return FALSE;
return TRUE;
}
static void
PictureTransformBounds (BoxPtr b, PictTransformPtr matrix)
{
PictVector v[4];
int i;
int x1, y1, x2, y2;
v[0].vector[0] = F (b->x1); v[0].vector[1] = F (b->y1); v[0].vector[2] = F(1);
v[1].vector[0] = F (b->x2); v[1].vector[1] = F (b->y1); v[1].vector[2] = F(1);
v[2].vector[0] = F (b->x2); v[2].vector[1] = F (b->y2); v[2].vector[2] = F(1);
v[3].vector[0] = F (b->x1); v[3].vector[1] = F (b->y2); v[3].vector[2] = F(1);
for (i = 0; i < 4; i++)
{
PictureTransformPoint (matrix, &v[i]);
x1 = xFixedToInt (v[i].vector[0]);
y1 = xFixedToInt (v[i].vector[1]);
x2 = xFixedToInt (xFixedCeil (v[i].vector[0]));
y2 = xFixedToInt (xFixedCeil (v[i].vector[1]));
if (i == 0)
{
b->x1 = x1; b->y1 = y1;
b->x2 = x2; b->y2 = y2;
}
else
{
if (x1 < b->x1) b->x1 = x1;
if (y1 < b->y1) b->y1 = y1;
if (x2 > b->x2) b->x2 = x2;
if (y2 > b->y2) b->y2 = y2;
}
} }
if (rotation & RR_Reflect_Y) { }
int y1 = dst->y1;
dst->y1 = dest_height - dst->y2; static Bool
dst->y2 = dest_height - y1; PictureTransformIsIdentity(PictTransform *t)
{
return ((t->matrix[0][0] == t->matrix[1][1]) &&
(t->matrix[0][0] == t->matrix[2][2]) &&
(t->matrix[0][0] != 0) &&
(t->matrix[0][1] == 0) &&
(t->matrix[0][2] == 0) &&
(t->matrix[1][0] == 0) &&
(t->matrix[1][2] == 0) &&
(t->matrix[2][0] == 0) &&
(t->matrix[2][1] == 0));
}
#define toF(x) ((float) (x) / 65536.0f)
static void
PictureTransformErrorF (PictTransform *t)
{
ErrorF ("{ { %f %f %f } { %f %f %f } { %f %f %f } }",
toF(t->matrix[0][0]), toF(t->matrix[0][1]), toF(t->matrix[0][2]),
toF(t->matrix[1][0]), toF(t->matrix[1][1]), toF(t->matrix[1][2]),
toF(t->matrix[2][0]), toF(t->matrix[2][1]), toF(t->matrix[2][2]));
}
static Bool
PictureTransformIsInverse (char *where, PictTransform *a, PictTransform *b)
{
PictTransform t;
PictureTransformMultiply (&t, a, b);
if (!PictureTransformIsIdentity (&t))
{
ErrorF ("%s: ", where);
PictureTransformErrorF (a);
ErrorF (" * ");
PictureTransformErrorF (b);
ErrorF (" = ");
PictureTransformErrorF (a);
ErrorF ("\n");
return FALSE;
} }
return TRUE;
} }
static void static void
...@@ -131,7 +278,6 @@ xf86RotateCrtcRedisplay (xf86CrtcPtr crtc, RegionPtr region) ...@@ -131,7 +278,6 @@ xf86RotateCrtcRedisplay (xf86CrtcPtr crtc, RegionPtr region)
PictFormatPtr format = compWindowFormat (WindowTable[screen->myNum]); PictFormatPtr format = compWindowFormat (WindowTable[screen->myNum]);
int error; int error;
PicturePtr src, dst; PicturePtr src, dst;
PictTransform transform;
int n = REGION_NUM_RECTS(region); int n = REGION_NUM_RECTS(region);
BoxPtr b = REGION_RECTS(region); BoxPtr b = REGION_RECTS(region);
XID include_inferiors = IncludeInferiors; XID include_inferiors = IncludeInferiors;
...@@ -156,45 +302,7 @@ xf86RotateCrtcRedisplay (xf86CrtcPtr crtc, RegionPtr region) ...@@ -156,45 +302,7 @@ xf86RotateCrtcRedisplay (xf86CrtcPtr crtc, RegionPtr region)
if (!dst) if (!dst)
return; return;
memset (&transform, '\0', sizeof (transform)); error = SetPictureTransform (src, &crtc->crtc_to_framebuffer);
transform.matrix[2][2] = IntToxFixed(1);
transform.matrix[0][2] = IntToxFixed(crtc->x);
transform.matrix[1][2] = IntToxFixed(crtc->y);
switch (crtc->rotation & 0xf) {
default:
case RR_Rotate_0:
transform.matrix[0][0] = IntToxFixed(1);
transform.matrix[1][1] = IntToxFixed(1);
break;
case RR_Rotate_90:
transform.matrix[0][1] = IntToxFixed(-1);
transform.matrix[1][0] = IntToxFixed(1);
transform.matrix[0][2] += IntToxFixed(crtc->mode.VDisplay);
break;
case RR_Rotate_180:
transform.matrix[0][0] = IntToxFixed(-1);
transform.matrix[1][1] = IntToxFixed(-1);
transform.matrix[0][2] += IntToxFixed(crtc->mode.HDisplay);
transform.matrix[1][2] += IntToxFixed(crtc->mode.VDisplay);
break;
case RR_Rotate_270:
transform.matrix[0][1] = IntToxFixed(1);
transform.matrix[1][0] = IntToxFixed(-1);
transform.matrix[1][2] += IntToxFixed(crtc->mode.HDisplay);
break;
}
/* handle reflection */
if (crtc->rotation & RR_Reflect_X)
{
/* XXX figure this out */
}
if (crtc->rotation & RR_Reflect_Y)
{
/* XXX figure this out too */
}
error = SetPictureTransform (src, &transform);
if (error) if (error)
return; return;
...@@ -202,9 +310,8 @@ xf86RotateCrtcRedisplay (xf86CrtcPtr crtc, RegionPtr region) ...@@ -202,9 +310,8 @@ xf86RotateCrtcRedisplay (xf86CrtcPtr crtc, RegionPtr region)
{ {
BoxRec dst_box; BoxRec dst_box;
xf86TransformBox (&dst_box, b, crtc->rotation, dst_box = *b;
crtc->x, crtc->y, PictureTransformBounds (&dst_box, &crtc->framebuffer_to_crtc);
crtc->mode.HDisplay, crtc->mode.VDisplay);
CompositePicture (PictOpSrc, CompositePicture (PictOpSrc,
src, NULL, dst, src, NULL, dst,
dst_box.x1, dst_box.y1, 0, 0, dst_box.x1, dst_box.y1, dst_box.x1, dst_box.y1, 0, 0, dst_box.x1, dst_box.y1,
...@@ -296,15 +403,10 @@ xf86RotateRedisplay(ScreenPtr pScreen) ...@@ -296,15 +403,10 @@ xf86RotateRedisplay(ScreenPtr pScreen)
if (crtc->rotation != RR_Rotate_0 && crtc->enabled) if (crtc->rotation != RR_Rotate_0 && crtc->enabled)
{ {
BoxRec box;
RegionRec crtc_damage; RegionRec crtc_damage;
/* compute portion of damage that overlaps crtc */ /* compute portion of damage that overlaps crtc */
box.x1 = crtc->x; REGION_INIT(pScreen, &crtc_damage, &crtc->bounds, 1);
box.x2 = crtc->x + xf86ModeWidth (&crtc->mode, crtc->rotation);
box.y1 = crtc->y;
box.y2 = crtc->y + xf86ModeHeight (&crtc->mode, crtc->rotation);
REGION_INIT(pScreen, &crtc_damage, &box, 1);
REGION_INTERSECT (pScreen, &crtc_damage, &crtc_damage, region); REGION_INTERSECT (pScreen, &crtc_damage, &crtc_damage, region);
/* update damaged region */ /* update damaged region */
...@@ -393,13 +495,93 @@ xf86CrtcRotate (xf86CrtcPtr crtc, DisplayModePtr mode, Rotation rotation) ...@@ -393,13 +495,93 @@ xf86CrtcRotate (xf86CrtcPtr crtc, DisplayModePtr mode, Rotation rotation)
ScrnInfoPtr pScrn = crtc->scrn; ScrnInfoPtr pScrn = crtc->scrn;
xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
ScreenPtr pScreen = pScrn->pScreen; ScreenPtr pScreen = pScrn->pScreen;
PictTransform crtc_to_fb, fb_to_crtc;
PictureTransformIdentity (&crtc_to_fb);
PictureTransformIdentity (&fb_to_crtc);
PictureTransformIsInverse ("identity", &crtc_to_fb, &fb_to_crtc);
if (rotation != RR_Rotate_0)
{
xFixed rot_cos, rot_sin, rot_dx, rot_dy;
xFixed scale_x, scale_y, scale_dx, scale_dy;
int mode_w = crtc->mode.HDisplay;
int mode_h = crtc->mode.VDisplay;
/* rotation */
switch (rotation & 0xf) {
default:
case RR_Rotate_0:
rot_cos = F ( 1); rot_sin = F ( 0);
rot_dx = F ( 0); rot_dy = F ( 0);
break;
case RR_Rotate_90:
rot_cos = F ( 0); rot_sin = F ( 1);
rot_dx = F ( mode_h); rot_dy = F (0);
break;
case RR_Rotate_180:
rot_cos = F (-1); rot_sin = F ( 0);
rot_dx = F (mode_w); rot_dy = F ( mode_h);
break;
case RR_Rotate_270:
rot_cos = F ( 0); rot_sin = F (-1);
rot_dx = F ( 0); rot_dy = F ( mode_w);
break;
}
PictureTransformRotate (&crtc_to_fb, &fb_to_crtc, rot_cos, rot_sin);
PictureTransformIsInverse ("rotate", &crtc_to_fb, &fb_to_crtc);
PictureTransformTranslate (&crtc_to_fb, &fb_to_crtc, rot_dx, rot_dy);
PictureTransformIsInverse ("rotate translate", &crtc_to_fb, &fb_to_crtc);
/* reflection */
scale_x = F (1);
scale_dx = 0;
scale_y = F (1);
scale_dy = 0;
if (rotation & RR_Reflect_X)
{
scale_x = F(-1);
if (rotation & (RR_Rotate_0|RR_Rotate_180))
scale_dx = F(mode_w);
else
scale_dx = F(mode_h);
}
if (rotation & RR_Reflect_Y)
{
scale_y = F(-1);
if (rotation & (RR_Rotate_0|RR_Rotate_180))
scale_dy = F(mode_h);
else
scale_dy = F(mode_w);