Commit 49db14e4 authored by Keith Packard's avatar Keith Packard

Handle RandR transform matrices in floating point.

RandR matrix computations lose too much precision in fixed point;
computations using the inverted matrix can be as much as 10 pixels off.
Convert them to double precision values and pass those around. These API
changes are fairly heavyweight; the official Render interface remains fixed
point, so the fixed point matrix comes along for the ride everywhere.
parent 6f734aec
......@@ -104,7 +104,8 @@ xf86CrtcCreate (ScrnInfoPtr scrn,
crtc->rotation = RR_Rotate_0;
crtc->desiredRotation = RR_Rotate_0;
PictureTransformInitIdentity (&crtc->crtc_to_framebuffer);
PictureTransformInitIdentity (&crtc->framebuffer_to_crtc);
pict_f_transform_init_identity (&crtc->f_crtc_to_framebuffer);
pict_f_transform_init_identity (&crtc->f_framebuffer_to_crtc);
crtc->filter = NULL;
crtc->params = NULL;
crtc->nparams = 0;
......
......@@ -305,7 +305,8 @@ struct _xf86Crtc {
* Current transformation matrix
*/
PictTransform crtc_to_framebuffer;
PictTransform framebuffer_to_crtc;
struct pict_f_transform f_crtc_to_framebuffer;
struct pict_f_transform f_framebuffer_to_crtc;
PictFilterPtr filter;
xFixed *params;
int nparams;
......
......@@ -326,15 +326,13 @@ xf86_crtc_set_cursor_position (xf86CrtcPtr crtc, int x, int y)
xf86CursorScreenPtr ScreenPriv =
(xf86CursorScreenPtr)dixLookupPrivate(&screen->devPrivates,
xf86CursorScreenKey);
PictVector v;
x += ScreenPriv->HotX;
y += ScreenPriv->HotY;
v.vector[0] = IntToxFixed (x); v.vector[1] = IntToxFixed (y); v.vector[2] = IntToxFixed(1);
PictureTransformPoint (&crtc->framebuffer_to_crtc, &v);
x = xFixedToInt (v.vector[0]); y = xFixedToInt (v.vector[1]);
x -= ScreenPriv->HotX;
y -= ScreenPriv->HotY;
}
struct pict_f_vector v;
v.v[0] = x + ScreenPriv->HotX; v.v[1] = y + ScreenPriv->HotY; v.v[2] = 1;
pict_f_transform_point (&crtc->f_framebuffer_to_crtc, &v);
x = floor (v.v[0] + 0.5) - ScreenPriv->HotX;
y = floor (v.v[1] + 0.5) - ScreenPriv->HotY;
}
else
{
x -= crtc->x;
......
......@@ -122,7 +122,7 @@ xf86RotateCrtcRedisplay (xf86CrtcPtr crtc, RegionPtr region)
dst_box.x2 += crtc->filter_width >> 1;
dst_box.y1 -= crtc->filter_height >> 1;
dst_box.y2 += crtc->filter_height >> 1;
PictureTransformBounds (&dst_box, &crtc->framebuffer_to_crtc);
pict_f_transform_bounds (&crtc->f_framebuffer_to_crtc, &dst_box);
CompositePicture (PictOpSrc,
src, NULL, dst,
dst_box.x1, dst_box.y1, 0, 0, dst_box.x1, dst_box.y1,
......@@ -165,6 +165,8 @@ xf86CrtcShadowClear (xf86CrtcPtr crtc)
xRectangle rect;
int error;
if (!dst_pixmap)
return;
dst = CreatePicture (None,
&dst_pixmap->drawable,
format,
......@@ -199,7 +201,6 @@ xf86RotatePrepare (ScreenPtr pScreen)
crtc->rotatedData,
crtc->mode.HDisplay,
crtc->mode.VDisplay);
xf86CrtcShadowClear (crtc);
if (!xf86_config->rotation_damage_registered)
{
/* Hook damage to screen pixmap */
......@@ -355,109 +356,33 @@ xf86CrtcRotate (xf86CrtcPtr crtc, DisplayModePtr mode, Rotation rotation)
xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
/* if this is called during ScreenInit() we don't have pScrn->pScreen yet */
ScreenPtr pScreen = screenInfo.screens[pScrn->scrnIndex];
PictTransform crtc_to_fb, fb_to_crtc;
PictTransform crtc_to_fb;
struct pict_f_transform f_crtc_to_fb, f_fb_to_crtc;
xFixed *new_params = NULL;
int new_nparams = 0;
PictFilterPtr new_filter = NULL;
int new_width = 0;
int new_height = 0;
PictureTransformInitIdentity (&crtc_to_fb);
PictureTransformInitIdentity (&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);
PictureTransformTranslate (&crtc_to_fb, &fb_to_crtc, rot_dx, rot_dy);
/* 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);
}
PictureTransformScale (&crtc_to_fb, &fb_to_crtc, scale_x, scale_y);
PictureTransformTranslate (&crtc_to_fb, &fb_to_crtc, scale_dx, scale_dy);
}
RRTransformPtr transform = NULL;
#ifdef RANDR_12_INTERFACE
if (crtc->randr_crtc)
{
RRTransformPtr transform = RRCrtcGetTransform (crtc->randr_crtc);
if (transform)
{
if (transform->nparams) {
new_params = xalloc (transform->nparams * sizeof (xFixed));
if (new_params) {
memcpy (new_params, transform->params,
transform->nparams * sizeof (xFixed));
new_nparams = transform->nparams;
new_filter = transform->filter;
}
} else
new_filter = transform->filter;
if (new_filter)
{
new_width = new_filter->width;
new_height = new_filter->height;
}
PictureTransformMultiply (&crtc_to_fb, &transform->transform, &crtc_to_fb);
PictureTransformMultiply (&fb_to_crtc, &fb_to_crtc, &transform->inverse);
}
}
transform = RRCrtcGetTransform (crtc->randr_crtc);
#endif
/*
* If the untranslated transformation is the identity,
* disable the shadow buffer
*/
if (PictureTransformIsIdentity (&crtc_to_fb))
if (!transform ||
!RRComputeTransform (crtc->x, crtc->y,
crtc->mode.HDisplay, crtc->mode.VDisplay,
rotation,
transform,
&crtc_to_fb,
&f_crtc_to_fb,
&f_fb_to_crtc))
{
PictureTransformInitTranslate (&crtc_to_fb,
F (-crtc->x), F (-crtc->y));
PictureTransformInitTranslate (&fb_to_crtc,
F ( crtc->x), F ( crtc->y));
/*
* If the untranslated transformation is the identity,
* disable the shadow buffer
*/
xf86RotateDestroy (crtc);
crtc->transform_in_use = FALSE;
if (new_params)
......@@ -470,24 +395,18 @@ xf86CrtcRotate (xf86CrtcPtr crtc, DisplayModePtr mode, Rotation rotation)
}
else
{
int width, height, old_width, old_height;
void *shadowData;
PixmapPtr shadow;
PictureTransformTranslate (&crtc_to_fb, &fb_to_crtc, F(crtc->x), F(crtc->y));
/*
/*
* these are the size of the shadow pixmap, which
* matches the mode, not the pre-rotated copy in the
* frame buffer
*/
width = mode->HDisplay;
height = mode->VDisplay;
shadowData = crtc->rotatedData;
shadow = crtc->rotatedPixmap;
old_width = shadow ? shadow->drawable.width : 0;
old_height = shadow ? shadow->drawable.height : 0;
int width = mode->HDisplay;
int height = mode->VDisplay;
void *shadowData = crtc->rotatedData;
PixmapPtr shadow = crtc->rotatedPixmap;
int old_width = shadow ? shadow->drawable.width : 0;
int old_height = shadow ? shadow->drawable.height : 0;
/* Allocate memory for rotation */
if (old_width != width || old_height != height)
{
......@@ -522,6 +441,27 @@ xf86CrtcRotate (xf86CrtcPtr crtc, DisplayModePtr mode, Rotation rotation)
xf86_config->BlockHandler = pScreen->BlockHandler;
pScreen->BlockHandler = xf86RotateBlockHandler;
}
#ifdef RANDR_12_INTERFACE
if (transform)
{
if (transform->nparams) {
new_params = xalloc (transform->nparams * sizeof (xFixed));
if (new_params) {
memcpy (new_params, transform->params,
transform->nparams * sizeof (xFixed));
new_nparams = transform->nparams;
new_filter = transform->filter;
}
} else
new_filter = transform->filter;
if (new_filter)
{
new_width = new_filter->width;
new_height = new_filter->height;
}
}
#endif
if (0)
{
bail2:
......@@ -537,14 +477,13 @@ xf86CrtcRotate (xf86CrtcPtr crtc, DisplayModePtr mode, Rotation rotation)
NULL,
old_width,
old_height);
if (new_params)
xfree (new_params);
return FALSE;
}
crtc->transform_in_use = TRUE;
}
crtc->crtc_to_framebuffer = crtc_to_fb;
crtc->framebuffer_to_crtc = fb_to_crtc;
crtc->f_crtc_to_framebuffer = f_crtc_to_fb;
crtc->f_framebuffer_to_crtc = f_fb_to_crtc;
if (crtc->params)
xfree (crtc->params);
crtc->params = new_params;
......@@ -556,8 +495,8 @@ xf86CrtcRotate (xf86CrtcPtr crtc, DisplayModePtr mode, Rotation rotation)
crtc->bounds.x2 = crtc->mode.HDisplay;
crtc->bounds.y1 = 0;
crtc->bounds.y2 = crtc->mode.VDisplay;
PictureTransformBounds (&crtc->bounds, &crtc_to_fb);
pict_f_transform_bounds (&f_crtc_to_fb, &crtc->bounds);
/* All done */
return TRUE;
}
......@@ -107,7 +107,8 @@ struct _rrProperty {
struct _rrTransform {
PictTransform transform;
PictTransform inverse;
struct pict_f_transform f_transform;
struct pict_f_transform f_inverse;
PictFilterPtr filter;
xFixed *params;
int nparams;
......@@ -134,7 +135,8 @@ struct _rrCrtc {
RRTransformRec client_pending_transform;
RRTransformRec client_current_transform;
PictTransform transform;
PictTransform inverse;
struct pict_f_transform f_transform;
struct pict_f_transform f_inverse;
};
struct _rrOutput {
......@@ -616,14 +618,16 @@ RRCrtcGetScanoutSize(RRCrtcPtr crtc, int *width, int *height);
* Return TRUE if the resulting transform is not a simple translation.
*/
Bool
RRComputeTransform (RRModePtr mode,
Rotation rotation,
int x,
int y,
PictTransformPtr client_transform,
PictTransformPtr client_inverse,
PictTransformPtr transform,
PictTransformPtr inverse);
RRComputeTransform (int x,
int y,
int width,
int height,
Rotation rotation,
RRTransformPtr rr_transform,
PictTransformPtr transform,
struct pict_f_transform *f_transform,
struct pict_f_transform *f_inverse);
/*
* Return crtc transform
......@@ -657,7 +661,8 @@ RRCrtcDestroy (RRCrtcPtr crtc);
int
RRCrtcTransformSet (RRCrtcPtr crtc,
PictTransformPtr transform,
PictTransformPtr inverse,
struct pict_f_transform *f_transform,
struct pict_f_transform *f_inverse,
char *filter,
int filter_len,
xFixed *params,
......
......@@ -52,7 +52,8 @@ static void
RRTransformInit (RRTransformPtr transform)
{
PictureTransformInitIdentity (&transform->transform);
PictureTransformInitIdentity (&transform->inverse);
pict_f_transform_init_identity (&transform->f_transform);
pict_f_transform_init_identity (&transform->f_inverse);
transform->filter = NULL;
transform->params = NULL;
transform->nparams = 0;
......@@ -94,7 +95,8 @@ RRTransformCopy (RRTransformPtr dst, RRTransformPtr src)
src->params, src->nparams, src->width, src->height))
return FALSE;
dst->transform = src->transform;
dst->inverse = src->inverse;
dst->f_transform = src->f_transform;
dst->f_inverse = src->f_inverse;
return TRUE;
}
......@@ -142,7 +144,8 @@ RRCrtcCreate (ScreenPtr pScreen, void *devPrivate)
RRTransformInit (&crtc->client_pending_transform);
RRTransformInit (&crtc->client_current_transform);
PictureTransformInitIdentity (&crtc->transform);
PictureTransformInitIdentity (&crtc->inverse);
pict_f_transform_init_identity (&crtc->f_transform);
pict_f_transform_init_identity (&crtc->f_inverse);
if (!AddResource (crtc->id, RRCrtcType, (pointer) crtc))
return NULL;
......@@ -441,13 +444,19 @@ RRCrtcGetTransform (RRCrtcPtr crtc)
void
RRCrtcPostPendingTransform (RRCrtcPtr crtc)
{
if (!crtc->mode)
return;
RRTransformCopy (&crtc->client_current_transform,
&crtc->client_pending_transform);
RRComputeTransform (crtc->mode, crtc->rotation, crtc->x, crtc->y,
&crtc->client_current_transform.transform,
&crtc->client_current_transform.inverse,
RRComputeTransform (crtc->x, crtc->y,
crtc->mode->mode.width,
crtc->mode->mode.height,
crtc->rotation,
&crtc->client_current_transform,
&crtc->transform,
&crtc->inverse);
&crtc->f_transform,
&crtc->f_inverse);
}
/*
......@@ -608,7 +617,8 @@ RRCrtcGammaSetSize (RRCrtcPtr crtc,
int
RRCrtcTransformSet (RRCrtcPtr crtc,
PictTransformPtr transform,
PictTransformPtr inverse,
struct pict_f_transform *f_transform,
struct pict_f_transform *f_inverse,
char *filter_name,
int filter_len,
xFixed *params,
......@@ -648,7 +658,8 @@ RRCrtcTransformSet (RRCrtcPtr crtc,
return BadAlloc;
crtc->client_pending_transform.transform = *transform;
crtc->client_pending_transform.inverse = *inverse;
crtc->client_pending_transform.f_transform = *f_transform;
crtc->client_pending_transform.f_inverse = *f_inverse;
return Success;
}
......@@ -662,78 +673,110 @@ RRCrtcTransformSet (RRCrtcPtr crtc,
* Return TRUE if the resulting transform is not a simple translation.
*/
Bool
RRComputeTransform (RRModePtr mode,
Rotation rotation,
int x,
int y,
PictTransformPtr client_transform,
PictTransformPtr client_inverse,
PictTransformPtr transform,
PictTransformPtr inverse)
RRComputeTransform (int x,
int y,
int width,
int height,
Rotation rotation,
RRTransformPtr rr_transform,
PictTransformPtr transform,
struct pict_f_transform *f_transform,
struct pict_f_transform *f_inverse)
{
PictTransform inverse;
PictureTransformInitIdentity (transform);
PictureTransformInitIdentity (inverse);
PictureTransformInitIdentity (&inverse);
pict_f_transform_init_identity (f_transform);
pict_f_transform_init_identity (f_inverse);
if (rotation != RR_Rotate_0)
{
double f_rot_cos, f_rot_sin, f_rot_dx, f_rot_dy;
double f_scale_x, f_scale_y, f_scale_dx, f_scale_dy;
xFixed rot_cos, rot_sin, rot_dx, rot_dy;
xFixed scale_x, scale_y, scale_dx, scale_dy;
int mode_w = mode->mode.width;
int mode_h = mode->mode.height;
/* rotation */
switch (rotation & 0xf) {
default:
case RR_Rotate_0:
f_rot_cos = 1; f_rot_sin = 0;
f_rot_dx = 0; f_rot_dy = 0;
rot_cos = F ( 1); rot_sin = F ( 0);
rot_dx = F ( 0); rot_dy = F ( 0);
break;
case RR_Rotate_90:
f_rot_cos = 0; f_rot_sin = 1;
f_rot_dx = height; f_rot_dy = 0;
rot_cos = F ( 0); rot_sin = F ( 1);
rot_dx = F ( mode_h); rot_dy = F (0);
rot_dx = F ( height); rot_dy = F (0);
break;
case RR_Rotate_180:
f_rot_cos = -1; f_rot_sin = 0;
f_rot_dx = width; f_rot_dy = height;
rot_cos = F (-1); rot_sin = F ( 0);
rot_dx = F (mode_w); rot_dy = F ( mode_h);
rot_dx = F (width); rot_dy = F ( height);
break;
case RR_Rotate_270:
f_rot_cos = 0; f_rot_sin = -1;
f_rot_dx = 0; f_rot_dy = width;
rot_cos = F ( 0); rot_sin = F (-1);
rot_dx = F ( 0); rot_dy = F ( mode_w);
rot_dx = F ( 0); rot_dy = F ( width);
break;
}
PictureTransformRotate (inverse, transform, rot_cos, rot_sin);
PictureTransformTranslate (inverse, transform, rot_dx, rot_dy);
PictureTransformRotate (&inverse, transform, rot_cos, rot_sin);
PictureTransformTranslate (&inverse, transform, rot_dx, rot_dy);
pict_f_transform_rotate (f_inverse, f_transform, f_rot_cos, f_rot_sin);
pict_f_transform_translate (f_inverse, f_transform, f_rot_dx, f_rot_dy);
/* reflection */
f_scale_x = 1;
f_scale_dx = 0;
f_scale_y = 1;
f_scale_dy = 0;
scale_x = F (1);
scale_dx = 0;
scale_y = F (1);
scale_dy = 0;
if (rotation & RR_Reflect_X)
{
f_scale_x = -1;
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_Rotate_0|RR_Rotate_180)) {
f_scale_dx = width;
scale_dx = F(width);
} else {
f_scale_dx = height;
scale_dx = F(height);
}
}
if (rotation & RR_Reflect_Y)
{
f_scale_y = -1;
scale_y = F(-1);
if (rotation & (RR_Rotate_0|RR_Rotate_180))
scale_dy = F(mode_h);
else
scale_dy = F(mode_w);
if (rotation & (RR_Rotate_0|RR_Rotate_180)) {
f_scale_dy = height;
scale_dy = F(height);
} else {
f_scale_dy = width;
scale_dy = F(width);
}
}
PictureTransformScale (inverse, transform, scale_x, scale_y);
PictureTransformTranslate (inverse, transform, scale_dx, scale_dy);
PictureTransformScale (&inverse, transform, scale_x, scale_y);
pict_f_transform_scale (f_inverse, f_transform, f_scale_x, f_scale_y);
PictureTransformTranslate (&inverse, transform, scale_dx, scale_dy);
pict_f_transform_translate (f_inverse, f_transform, f_scale_dx, f_scale_dy);
}
#ifdef RANDR_12_INTERFACE
if (rr_transform)
{
PictureTransformMultiply (inverse, client_inverse, inverse);
PictureTransformMultiply (transform, transform, client_transform);
PictureTransformMultiply (transform, transform, &rr_transform->transform);
pict_f_transform_multiply (f_transform, f_transform, &rr_transform->f_transform);
pict_f_transform_multiply (f_inverse, &rr_transform->f_inverse, f_inverse);
}
#endif
/*
......@@ -741,13 +784,16 @@ RRComputeTransform (RRModePtr mode,
*/
if (PictureTransformIsIdentity (transform))
{
PictureTransformInitTranslate (inverse, F (-x), F (-y));
PictureTransformInitTranslate (transform, F ( x), F ( y));
pict_f_transform_init_translate (f_transform, F( x), F( y));
pict_f_transform_init_translate (f_inverse, F(-x), F(-y));
return FALSE;
}
else
{
PictureTransformTranslate (inverse, transform, x, y);
PictureTransformTranslate (&inverse, transform, x, y);
pict_f_transform_translate (f_inverse, f_transform, x, y);
return TRUE;
}
}
......@@ -1045,6 +1091,7 @@ ProcRRSetCrtcConfig (ClientPtr client)
}
#ifdef RANDR_12_INTERFACE
#if 0
/*
* Check screen size bounds if the DDX provides a 1.2 interface
* for setting screen size. Else, assume the CrtcSet sets
......@@ -1079,6 +1126,7 @@ ProcRRSetCrtcConfig (ClientPtr client)
return BadValue;
}
}
#endif
#endif
}
......@@ -1227,7 +1275,8 @@ ProcRRSetCrtcTransform (ClientPtr client)
{
REQUEST(xRRSetCrtcTransformReq);
RRCrtcPtr crtc;
PictTransform transform, inverse;
PictTransform transform;
struct pict_f_transform f_transform, f_inverse;
char *filter;
int nbytes;
xFixed *params;
......@@ -1239,7 +1288,8 @@ ProcRRSetCrtcTransform (ClientPtr client)
return RRErrorBase + BadRRCrtc;
PictTransform_from_xRenderTransform (&transform, &stuff->transform);
if (!PictureTransformInvert (&inverse, &transform))
pict_f_transform_from_pixman_transform (&f_transform, &transform);
if (!pict_f_transform_invert (&f_inverse, &f_transform))
return BadMatch;
filter = (char *) (stuff + 1);
......@@ -1249,7 +1299,7 @@ ProcRRSetCrtcTransform (ClientPtr client)
if (nparams < 0)
return BadLength;
return RRCrtcTransformSet (crtc, &transform, &inverse,
return RRCrtcTransformSet (crtc, &transform, &f_transform, &f_inverse,
filter, nbytes, params, nparams);
}
......
......@@ -262,83 +262,15 @@ PictureTransformBounds (BoxPtr b, PictTransformPtr matrix)
}
}
static const int a[3] = { 3, 3, 2 };
static const int b[3] = { 2, 1, 1 };
static void
to_doubles (double m[3][3], const PictTransformPtr t)
{
int i, j;
for (j = 0; j < 3; j++)
for (i = 0; i < 3; i++)
m[j][i] = pixman_fixed_to_double (t->matrix[j][i]);
}
static Bool
from_doubles (PictTransformPtr t, double m[3][3])
{
int i, j;
for (j = 0; j < 3; j++)
for (i = 0; i < 3; i++)
{
double d = m[j][i];
if (d < -32767.0 || d > 32767.0)
return FALSE;
d = d * 65536.0 + 0.5;
t->matrix[j][i] = (xFixed) floor (d);
}