diff options
author | Keith Packard <keithp@neko.keithp.com> | 2007-07-14 09:03:40 -0700 |
---|---|---|
committer | Keith Packard <keithp@neko.keithp.com> | 2007-07-14 09:03:47 -0700 |
commit | 393171034c15d8a1b82232b8f9455a358035e932 (patch) | |
tree | ccda99731559953cfe75d7e6e95e4809f23dba57 /hw/xfree86/modes | |
parent | 8773ad023eb28950eb0f802d2ca31a67f84adddc (diff) |
Add RandR reflection support.
Replace the ad-hoc transformation mechanisms with matrices.
Prepares for more general transformation as well.
Diffstat (limited to 'hw/xfree86/modes')
-rw-r--r-- | hw/xfree86/modes/xf86Crtc.c | 3 | ||||
-rw-r--r-- | hw/xfree86/modes/xf86Crtc.h | 11 | ||||
-rw-r--r-- | hw/xfree86/modes/xf86Cursors.c | 116 | ||||
-rw-r--r-- | hw/xfree86/modes/xf86Rotate.c | 378 |
4 files changed, 369 insertions, 139 deletions
diff --git a/hw/xfree86/modes/xf86Crtc.c b/hw/xfree86/modes/xf86Crtc.c index d20a3a338..722b62be4 100644 --- a/hw/xfree86/modes/xf86Crtc.c +++ b/hw/xfree86/modes/xf86Crtc.c @@ -676,7 +676,8 @@ xf86CrtcScreenInit (ScreenPtr screen) } if (c == config->num_crtc) 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 xf86RandR12SetRotations (screen, RR_Rotate_0); diff --git a/hw/xfree86/modes/xf86Crtc.h b/hw/xfree86/modes/xf86Crtc.h index 2d6260030..982a3d778 100644 --- a/hw/xfree86/modes/xf86Crtc.h +++ b/hw/xfree86/modes/xf86Crtc.h @@ -279,6 +279,17 @@ struct _xf86Crtc { * Track state of cursor associated with this CRTC */ 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 { diff --git a/hw/xfree86/modes/xf86Cursors.c b/hw/xfree86/modes/xf86Cursors.c index 009cccf89..396bf3091 100644 --- a/hw/xfree86/modes/xf86Cursors.c +++ b/hw/xfree86/modes/xf86Cursors.c @@ -58,29 +58,73 @@ xf86_crtc_rotate_coord (Rotation rotation, int *x_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) x_dst = width - x_dst - 1; if (rotation & RR_Reflect_Y) 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) { case RR_Rotate_0: - *x_src = x_dst; - *y_src = y_dst; break; case RR_Rotate_90: - *x_src = height - y_dst - 1; - *y_src = x_dst; + t = x_dst; + x_dst = y_dst; + y_dst = width - t - 1; break; case RR_Rotate_180: - *x_src = width - x_dst - 1; - *y_src = height - y_dst - 1; + x_dst = width - x_dst - 1; + y_dst = height - y_dst - 1; break; case RR_Rotate_270: - *x_src = y_dst; - *y_src = width - x_dst - 1; + t = x_dst; + x_dst = height - y_dst - 1; + y_dst = t; break; } + *x_src = x_dst; + *y_src = y_dst; } /* @@ -261,49 +305,33 @@ xf86_crtc_set_cursor_position (xf86CrtcPtr crtc, int x, int y) xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); xf86CursorInfoPtr cursor_info = xf86_config->cursor_info; DisplayModePtr mode = &crtc->mode; - int x_temp; - int y_temp; 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) { - case RR_Rotate_0: - break; - case RR_Rotate_90: - x_temp = y; - y_temp = mode->VDisplay - cursor_info->MaxWidth - x; - x = x_temp; - y = y_temp; - break; - case RR_Rotate_180: - x_temp = mode->HDisplay - cursor_info->MaxWidth - x; - 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; + if (crtc->transform_in_use) + { + PictVector v; + 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]); + } + else + { + x -= crtc->x; + y -= crtc->y; } - /* - * Reflect + * Transform position of cursor upper left corner */ - if (crtc->rotation & RR_Reflect_X) - x = mode->HDisplay - cursor_info->MaxWidth - x; - if (crtc->rotation & RR_Reflect_Y) - y = mode->VDisplay - cursor_info->MaxHeight - y; + xf86_crtc_rotate_coord_back (crtc->rotation, + cursor_info->MaxWidth, + cursor_info->MaxHeight, + 0, 0, &dx, &dy); + x -= dx; + y -= dy; /* * Disable the cursor when it is outside the viewport diff --git a/hw/xfree86/modes/xf86Rotate.c b/hw/xfree86/modes/xf86Rotate.c index 137993926..4016b9733 100644 --- a/hw/xfree86/modes/xf86Rotate.c +++ b/hw/xfree86/modes/xf86Rotate.c @@ -68,57 +68,204 @@ compWindowFormat (WindowPtr pWin) compGetWindowVisual (pWin)); } +#define F(x) IntToxFixed(x) + 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; - b->y1 += dy; - b->x2 += dx; - b->y2 += dy; + PictTransform d; + int dx, dy; + int o; + + 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 -xf86TransformBox (BoxPtr dst, BoxPtr src, Rotation rotation, - int xoff, int yoff, - int dest_width, int dest_height) +PictureTransformInitScale (PictTransformPtr t, xFixed sx, xFixed sy) +{ + 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); - switch (rotation & 0xf) { - default: - case RR_Rotate_0: - *dst = stmp; - break; - case RR_Rotate_90: - dst->x1 = stmp.y1; - dst->y1 = dest_height - stmp.x2; - dst->x2 = stmp.y2; - dst->y2 = dest_height - stmp.x1; - break; - case RR_Rotate_180: - dst->x1 = dest_width - stmp.x2; - dst->y1 = dest_height - stmp.y2; - dst->x2 = dest_width - stmp.x1; - dst->y2 = dest_height - stmp.y1; - break; - case RR_Rotate_270: - dst->x1 = dest_width - stmp.y2; - dst->y1 = stmp.x1; - dst->y2 = stmp.x2; - dst->x2 = dest_width - stmp.y1; - break; - } - if (rotation & RR_Reflect_X) { - int x1 = dst->x1; - dst->x1 = dest_width - dst->x2; - dst->x2 = dest_width - x1; + PictureTransformInitScale (&t, sx, sy); + if (!PictureTransformMultiply (forward, &t, forward)) + return FALSE; + PictureTransformInitScale (&t, fixed_inverse (sx), fixed_inverse (sy)); + if (!PictureTransformMultiply (reverse, reverse, &t)) + return FALSE; + return TRUE; +} + +static void +PictureTransformInitRotate (PictTransformPtr t, xFixed c, xFixed s) +{ + memset (t, '\0', sizeof (PictTransform)); + t->matrix[0][0] = c; + t->matrix[0][1] = -s; + t->matrix[1][0] = s; + t->matrix[1][1] = c; + t->matrix[2][2] = F (1); +} + +static Bool +PictureTransformRotate (PictTransformPtr forward, + PictTransformPtr reverse, + xFixed c, xFixed s) +{ + PictTransform t; + PictureTransformInitRotate (&t, c, s); + if (!PictureTransformMultiply (forward, &t, forward)) + 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; - dst->y2 = dest_height - y1; +} + +static Bool +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 @@ -131,7 +278,6 @@ xf86RotateCrtcRedisplay (xf86CrtcPtr crtc, RegionPtr region) PictFormatPtr format = compWindowFormat (WindowTable[screen->myNum]); int error; PicturePtr src, dst; - PictTransform transform; int n = REGION_NUM_RECTS(region); BoxPtr b = REGION_RECTS(region); XID include_inferiors = IncludeInferiors; @@ -156,45 +302,7 @@ xf86RotateCrtcRedisplay (xf86CrtcPtr crtc, RegionPtr region) if (!dst) return; - memset (&transform, '\0', sizeof (transform)); - 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); + error = SetPictureTransform (src, &crtc->crtc_to_framebuffer); if (error) return; @@ -202,9 +310,8 @@ xf86RotateCrtcRedisplay (xf86CrtcPtr crtc, RegionPtr region) { BoxRec dst_box; - xf86TransformBox (&dst_box, b, crtc->rotation, - crtc->x, crtc->y, - crtc->mode.HDisplay, crtc->mode.VDisplay); + dst_box = *b; + PictureTransformBounds (&dst_box, &crtc->framebuffer_to_crtc); CompositePicture (PictOpSrc, src, NULL, dst, dst_box.x1, dst_box.y1, 0, 0, dst_box.x1, dst_box.y1, @@ -296,15 +403,10 @@ xf86RotateRedisplay(ScreenPtr pScreen) if (crtc->rotation != RR_Rotate_0 && crtc->enabled) { - BoxRec box; RegionRec crtc_damage; /* compute portion of damage that overlaps crtc */ - box.x1 = crtc->x; - 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_INIT(pScreen, &crtc_damage, &crtc->bounds, 1); REGION_INTERSECT (pScreen, &crtc_damage, &crtc_damage, region); /* update damaged region */ @@ -393,13 +495,93 @@ xf86CrtcRotate (xf86CrtcPtr crtc, DisplayModePtr mode, Rotation rotation) ScrnInfoPtr pScrn = crtc->scrn; xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 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); + } + + PictureTransformScale (&crtc_to_fb, &fb_to_crtc, scale_x, scale_y); + PictureTransformIsInverse ("scale", &crtc_to_fb, &fb_to_crtc); + + PictureTransformTranslate (&crtc_to_fb, &fb_to_crtc, scale_dx, scale_dy); + PictureTransformIsInverse ("scale translate", &crtc_to_fb, &fb_to_crtc); + + } - if (rotation == RR_Rotate_0) + /* + * If the untranslated transformation is the identity, + * disable the shadow buffer + */ + if (PictureTransformIsIdentity (&crtc_to_fb)) { + crtc->transform_in_use = FALSE; + PictureTransformInitTranslate (&crtc->crtc_to_framebuffer, + F (-crtc->x), F (-crtc->y)); + PictureTransformInitTranslate (&crtc->framebuffer_to_crtc, + F ( crtc->x), F ( crtc->y)); xf86RotateDestroy (crtc); } else { + PictureTransformTranslate (&crtc_to_fb, &fb_to_crtc, crtc->x, crtc->y); + PictureTransformIsInverse ("offset", &crtc_to_fb, &fb_to_crtc); + /* * these are the size of the shadow pixmap, which * matches the mode, not the pre-rotated copy in the @@ -448,14 +630,14 @@ xf86CrtcRotate (xf86CrtcPtr crtc, DisplayModePtr mode, Rotation rotation) } if (0) { -bail2: + bail2: if (shadow || shadowData) { crtc->funcs->shadow_destroy (crtc, shadow, shadowData); crtc->rotatedPixmap = NULL; crtc->rotatedData = NULL; } -bail1: + bail1: if (old_width && old_height) crtc->rotatedPixmap = crtc->funcs->shadow_create (crtc, NULL, @@ -463,6 +645,14 @@ bail1: old_height); return FALSE; } + crtc->transform_in_use = TRUE; + crtc->crtc_to_framebuffer = crtc_to_fb; + crtc->framebuffer_to_crtc = fb_to_crtc; + crtc->bounds.x1 = 0; + crtc->bounds.x2 = crtc->mode.HDisplay; + crtc->bounds.y1 = 0; + crtc->bounds.y2 = crtc->mode.VDisplay; + PictureTransformBounds (&crtc->bounds, &crtc_to_fb); } /* All done */ |