diff --git a/hw/xfree86/modes/xf86Crtc.c b/hw/xfree86/modes/xf86Crtc.c index bda805519..74e4c76c7 100644 --- a/hw/xfree86/modes/xf86Crtc.c +++ b/hw/xfree86/modes/xf86Crtc.c @@ -344,6 +344,7 @@ typedef enum { OPTION_MIN_CLOCK, OPTION_MAX_CLOCK, OPTION_IGNORE, + OPTION_ROTATE, } OutputOpts; static OptionInfoRec xf86OutputOptions[] = { @@ -358,6 +359,7 @@ static OptionInfoRec xf86OutputOptions[] = { {OPTION_MIN_CLOCK, "MinClock", OPTV_FREQ, {0}, FALSE }, {OPTION_MAX_CLOCK, "MaxClock", OPTV_FREQ, {0}, FALSE }, {OPTION_IGNORE, "Ignore", OPTV_BOOLEAN, {0}, FALSE }, + {OPTION_ROTATE, "Rotate", OPTV_STRING, {0}, FALSE }, {-1, NULL, OPTV_NONE, {0}, FALSE }, }; @@ -413,6 +415,29 @@ xf86OutputIgnored (xf86OutputPtr output) return xf86ReturnOptValBool (output->options, OPTION_IGNORE, FALSE); } +static char *direction[4] = { + "normal", + "left", + "inverted", + "right" +}; + +static Rotation +xf86OutputInitialRotation (xf86OutputPtr output) +{ + char *rotate_name = xf86GetOptValString (output->options, + OPTION_ROTATE); + int i; + + if (!rotate_name) + return RR_Rotate_0; + + for (i = 0; i < 4; i++) + if (xf86nameCompare (direction[i], rotate_name) == 0) + return (1 << i); + return RR_Rotate_0; +} + xf86OutputPtr xf86OutputCreate (ScrnInfoPtr scrn, const xf86OutputFuncsRec *funcs, @@ -533,8 +558,12 @@ xf86DefaultMode (xf86OutputPtr output, int width, int height) int preferred = (mode->type & M_T_PREFERRED) != 0; int diff; - if (mode->HDisplay > width || mode->VDisplay > height) continue; - dpi = (mode->HDisplay * 254) / (mm_height * 10); + if (xf86ModeWidth (mode, output->initial_rotation) > width || + xf86ModeHeight (mode, output->initial_rotation) > height) + continue; + + /* yes, use VDisplay here, not xf86ModeHeight */ + dpi = (mode->VDisplay * 254) / (mm_height * 10); diff = dpi - 96; diff = diff < 0 ? -diff : diff; if (target_mode == NULL || (preferred > target_preferred) || @@ -549,7 +578,8 @@ xf86DefaultMode (xf86OutputPtr output, int width, int height) } static DisplayModePtr -xf86ClosestMode (xf86OutputPtr output, DisplayModePtr match, +xf86ClosestMode (xf86OutputPtr output, + DisplayModePtr match, Rotation match_rotation, int width, int height) { DisplayModePtr target_mode = NULL; @@ -564,14 +594,17 @@ xf86ClosestMode (xf86OutputPtr output, DisplayModePtr match, int dx, dy; int diff; - if (mode->HDisplay > width || mode->VDisplay > height) continue; + if (xf86ModeWidth (mode, output->initial_rotation) > width || + xf86ModeHeight (mode, output->initial_rotation) > height) + continue; /* exact matches are preferred */ - if (xf86ModesEqual (mode, match)) + if (output->initial_rotation == match_rotation && + xf86ModesEqual (mode, match)) return mode; - dx = match->HDisplay - mode->HDisplay; - dy = match->VDisplay - mode->VDisplay; + dx = xf86ModeWidth (match, match_rotation) - xf86ModeWidth (mode, output->initial_rotation); + dy = xf86ModeHeight (match, match_rotation) - xf86ModeHeight (mode, output->initial_rotation); diff = dx * dx + dy * dy; if (target_mode == NULL || diff < target_diff) { @@ -589,7 +622,10 @@ xf86OutputHasPreferredMode (xf86OutputPtr output, int width, int height) for (mode = output->probed_modes; mode; mode = mode->next) { - if (mode->HDisplay > width || mode->VDisplay > height) continue; + if (xf86ModeWidth (mode, output->initial_rotation) > width || + xf86ModeHeight (mode, output->initial_rotation) > height) + continue; + if (mode->type & M_T_PREFERRED) return TRUE; } @@ -605,7 +641,7 @@ xf86PickCrtcs (ScrnInfoPtr scrn, int height) { xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); - int c, o, l; + int c, o; xf86OutputPtr output; xf86CrtcPtr crtc; xf86CrtcPtr *crtcs; @@ -663,13 +699,11 @@ xf86PickCrtcs (ScrnInfoPtr scrn, * see if they can be cloned */ if (xf86ModesEqual (modes[o], modes[n]) && + config->output[0]->initial_rotation == config->output[n]->initial_rotation && config->output[o]->initial_x == config->output[n]->initial_x && config->output[o]->initial_y == config->output[n]->initial_y) { - for (l = 0; l < config->num_output; l++) - if (output->possible_clones & (1 << l)) - break; - if (l == config->num_output) + if ((output->possible_clones & (1 << o)) == 0) continue; /* nope, try next CRTC */ } else @@ -712,8 +746,8 @@ xf86DefaultScreenLimits (ScrnInfoPtr scrn, int *widthp, int *heightp) if (crtc->enabled) { - crtc_width = crtc->x + crtc->desiredMode.HDisplay; - crtc_height = crtc->y + crtc->desiredMode.VDisplay; + crtc_width = crtc->x + xf86ModeWidth (&crtc->desiredMode, crtc->desiredRotation); + crtc_height = crtc->y + xf86ModeHeight (&crtc->desiredMode, crtc->desiredRotation); } for (o = 0; o < config->num_output; o++) { @@ -727,8 +761,12 @@ xf86DefaultScreenLimits (ScrnInfoPtr scrn, int *widthp, int *heightp) { if (mode->HDisplay > crtc_width) crtc_width = mode->HDisplay; + if (mode->VDisplay > crtc_width) + crtc_width = mode->VDisplay; if (mode->VDisplay > crtc_height) crtc_height = mode->VDisplay; + if (mode->HDisplay > crtc_height) + crtc_height = mode->HDisplay; } } } @@ -858,16 +896,16 @@ xf86InitialOutputPositions (ScrnInfoPtr scrn, DisplayModePtr *modes) output->initial_y = relative->initial_y; switch (relation) { case OPTION_BELOW: - output->initial_y += modes[or]->VDisplay; + output->initial_y += xf86ModeHeight (modes[or], relative->initial_rotation); break; case OPTION_RIGHT_OF: - output->initial_x += modes[or]->HDisplay; + output->initial_x += xf86ModeWidth (modes[or], relative->initial_rotation); break; case OPTION_ABOVE: - output->initial_y -= modes[o]->VDisplay; + output->initial_y -= xf86ModeHeight (modes[or], relative->initial_rotation); break; case OPTION_LEFT_OF: - output->initial_x -= modes[o]->HDisplay; + output->initial_x -= xf86ModeWidth (modes[or], relative->initial_rotation); break; default: break; @@ -1208,6 +1246,8 @@ xf86ProbeOutputModes (ScrnInfoPtr scrn, int maxX, int maxY) } } + output->initial_rotation = xf86OutputInitialRotation (output); + #ifdef DEBUG_REPROBE if (output->probed_modes != NULL) { xf86DrvMsg(scrn->scrnIndex, X_INFO, @@ -1310,6 +1350,7 @@ xf86InitialConfiguration (ScrnInfoPtr scrn) xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); int o, c; DisplayModePtr target_mode = NULL; + Rotation target_rotation = RR_Rotate_0; xf86CrtcPtr *crtcs; DisplayModePtr *modes; Bool *enabled; @@ -1351,6 +1392,7 @@ xf86InitialConfiguration (ScrnInfoPtr scrn) xf86OutputHasPreferredMode (output, width, height)) { target_mode = xf86DefaultMode (output, width, height); + target_rotation = output->initial_rotation; if (target_mode) { modes[o] = target_mode; @@ -1367,6 +1409,7 @@ xf86InitialConfiguration (ScrnInfoPtr scrn) if (enabled[o]) { target_mode = xf86DefaultMode (output, width, height); + target_rotation = output->initial_rotation; if (target_mode) { modes[o] = target_mode; @@ -1381,7 +1424,7 @@ xf86InitialConfiguration (ScrnInfoPtr scrn) xf86OutputPtr output = config->output[o]; if (enabled[o] && !modes[o]) - modes[o] = xf86ClosestMode (output, target_mode, width, height); + modes[o] = xf86ClosestMode (output, target_mode, target_rotation, width, height); } /* @@ -1429,6 +1472,7 @@ xf86InitialConfiguration (ScrnInfoPtr scrn) if (mode && crtc) { crtc->desiredMode = *mode; + crtc->desiredRotation = output->initial_rotation; crtc->enabled = TRUE; crtc->x = output->initial_x; crtc->y = output->initial_y; diff --git a/hw/xfree86/modes/xf86Crtc.h b/hw/xfree86/modes/xf86Crtc.h index 07f7d4960..9a70be4b9 100644 --- a/hw/xfree86/modes/xf86Crtc.h +++ b/hw/xfree86/modes/xf86Crtc.h @@ -111,17 +111,23 @@ typedef struct _xf86CrtcFuncs { (*gamma_set)(xf86CrtcPtr crtc, CARD16 *red, CARD16 *green, CARD16 *blue, int size); + /** + * Allocate the shadow area, delay the pixmap creation until needed + */ + void * + (*shadow_allocate) (xf86CrtcPtr crtc, int width, int height); + /** * Create shadow pixmap for rotation support */ PixmapPtr - (*shadow_create) (xf86CrtcPtr crtc, int width, int height); + (*shadow_create) (xf86CrtcPtr crtc, void *data, int width, int height); /** * Destroy shadow pixmap */ void - (*shadow_destroy) (xf86CrtcPtr crtc, PixmapPtr pPixmap); + (*shadow_destroy) (xf86CrtcPtr crtc, PixmapPtr pPixmap, void *data); /** * Clean up driver-specific bits of the crtc @@ -159,6 +165,8 @@ struct _xf86Crtc { DisplayModeRec mode; Rotation rotation; PixmapPtr rotatedPixmap; + void *rotatedData; + /** * Position on screen * @@ -356,6 +364,11 @@ struct _xf86Output { */ int initial_x, initial_y; + /** + * Desired initial rotation + */ + Rotation initial_rotation; + /** * Current connection status * diff --git a/hw/xfree86/modes/xf86Modes.c b/hw/xfree86/modes/xf86Modes.c index 0706783ae..37d0eb656 100644 --- a/hw/xfree86/modes/xf86Modes.c +++ b/hw/xfree86/modes/xf86Modes.c @@ -94,6 +94,36 @@ xf86ModeVRefresh(DisplayModePtr mode) return refresh; } +int +xf86ModeWidth (DisplayModePtr mode, Rotation rotation) +{ + switch (rotation & 0xf) { + case RR_Rotate_0: + case RR_Rotate_180: + return mode->HDisplay; + case RR_Rotate_90: + case RR_Rotate_270: + return mode->VDisplay; + default: + return 0; + } +} + +int +xf86ModeHeight (DisplayModePtr mode, Rotation rotation) +{ + switch (rotation & 0xf) { + case RR_Rotate_0: + case RR_Rotate_180: + return mode->VDisplay; + case RR_Rotate_90: + case RR_Rotate_270: + return mode->HDisplay; + default: + return 0; + } +} + /** Sets a default mode name of x on a mode. */ void xf86SetModeDefaultName(DisplayModePtr mode) diff --git a/hw/xfree86/modes/xf86Modes.h b/hw/xfree86/modes/xf86Modes.h index 60e279083..94943339e 100644 --- a/hw/xfree86/modes/xf86Modes.h +++ b/hw/xfree86/modes/xf86Modes.h @@ -36,6 +36,13 @@ double xf86ModeHSync(DisplayModePtr mode); double xf86ModeVRefresh(DisplayModePtr mode); + +int +xf86ModeWidth (DisplayModePtr mode, Rotation rotation); + +int +xf86ModeHeight (DisplayModePtr mode, Rotation rotation); + DisplayModePtr xf86DuplicateMode(DisplayModePtr pMode); DisplayModePtr xf86DuplicateModes(ScrnInfoPtr pScrn, DisplayModePtr modeList); diff --git a/hw/xfree86/modes/xf86Rename.h b/hw/xfree86/modes/xf86Rename.h index ce4d21796..6cfa5caa1 100644 --- a/hw/xfree86/modes/xf86Rename.h +++ b/hw/xfree86/modes/xf86Rename.h @@ -74,5 +74,7 @@ #define xf86RandR12SetRotations XF86NAME(xf86RandR12SetRotations) #define xf86SaveScreen XF86NAME(xf86SaveScreen) #define xf86CrtcSetScreenSubpixelOrder XF86NAME(xf86CrtcSetScreenSubpixelOrder) +#define xf86ModeWidth XF86NAME(xf86ModeWidth) +#define xf86ModeHeight XF86NAME(xf86ModeHeight) #endif /* _XF86RENAME_H_ */ diff --git a/hw/xfree86/modes/xf86Rotate.c b/hw/xfree86/modes/xf86Rotate.c index 1d55a6e79..7b20498cc 100644 --- a/hw/xfree86/modes/xf86Rotate.c +++ b/hw/xfree86/modes/xf86Rotate.c @@ -44,36 +44,6 @@ #include "X11/extensions/dpms.h" #include "X11/Xatom.h" -static int -mode_height (DisplayModePtr mode, Rotation rotation) -{ - switch (rotation & 0xf) { - case RR_Rotate_0: - case RR_Rotate_180: - return mode->VDisplay; - case RR_Rotate_90: - case RR_Rotate_270: - return mode->HDisplay; - default: - return 0; - } -} - -static int -mode_width (DisplayModePtr mode, Rotation rotation) -{ - switch (rotation & 0xf) { - case RR_Rotate_0: - case RR_Rotate_180: - return mode->HDisplay; - case RR_Rotate_90: - case RR_Rotate_270: - return mode->VDisplay; - default: - return 0; - } -} - /* borrowed from composite extension, move to Render and publish? */ static VisualPtr @@ -237,6 +207,42 @@ xf86RotateCrtcRedisplay (xf86CrtcPtr crtc, RegionPtr region) FreePicture (dst, None); } +static void +xf86RotatePrepare (ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); + int c; + + for (c = 0; c < xf86_config->num_crtc; c++) + { + xf86CrtcPtr crtc = xf86_config->crtc[c]; + + if (crtc->rotatedData && !crtc->rotatedPixmap) + { + BoxRec damage_box; + RegionRec damage_region; + + crtc->rotatedPixmap = crtc->funcs->shadow_create (crtc, + crtc->rotatedData, + crtc->mode.HDisplay, + crtc->mode.VDisplay); + /* Hook damage to screen pixmap */ + DamageRegister (&(*pScreen->GetScreenPixmap)(pScreen)->drawable, + xf86_config->rotationDamage); + + damage_box.x1 = 0; + damage_box.y1 = 0; + damage_box.x2 = xf86ModeWidth (&crtc->mode, crtc->rotation); + damage_box.y2 = xf86ModeHeight (&crtc->mode, crtc->rotation); + REGION_INIT (pScreen, &damage_region, &damage_box, 1); + DamageDamageRegion (&(*pScreen->GetScreenPixmap)(pScreen)->drawable, + &damage_region); + REGION_UNINIT (pScreen, &damage_region); + } + } +} + static void xf86RotateRedisplay(ScreenPtr pScreen) { @@ -247,6 +253,7 @@ xf86RotateRedisplay(ScreenPtr pScreen) if (!damage) return; + xf86RotatePrepare (pScreen); region = DamageRegion(damage); if (REGION_NOTEMPTY(pScreen, region)) { @@ -263,9 +270,9 @@ xf86RotateRedisplay(ScreenPtr pScreen) /* compute portion of damage that overlaps crtc */ box.x1 = crtc->x; - box.x2 = crtc->x + mode_width (&crtc->mode, crtc->rotation); + box.x2 = crtc->x + xf86ModeWidth (&crtc->mode, crtc->rotation); box.y1 = crtc->y; - box.y2 = crtc->y + mode_height (&crtc->mode, crtc->rotation); + box.y2 = crtc->y + xf86ModeHeight (&crtc->mode, crtc->rotation); REGION_INIT(pScreen, &crtc_damage, &box, 1); REGION_INTERSECT (pScreen, &crtc_damage, &crtc_damage, region); @@ -303,10 +310,11 @@ xf86CrtcRotate (xf86CrtcPtr crtc, DisplayModePtr mode, Rotation rotation) if (rotation == RR_Rotate_0) { /* Free memory from rotation */ - if (crtc->rotatedPixmap) + if (crtc->rotatedPixmap || crtc->rotatedData) { - crtc->funcs->shadow_destroy (crtc, crtc->rotatedPixmap); + crtc->funcs->shadow_destroy (crtc, crtc->rotatedPixmap, crtc->rotatedData); crtc->rotatedPixmap = NULL; + crtc->rotatedData = NULL; } if (xf86_config->rotationDamage) @@ -331,24 +339,24 @@ xf86CrtcRotate (xf86CrtcPtr crtc, DisplayModePtr mode, Rotation rotation) */ 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; - BoxRec damage_box; - RegionRec damage_region; /* Allocate memory for rotation */ if (old_width != width || old_height != height) { - if (shadow) + if (shadow || shadowData) { - crtc->funcs->shadow_destroy (crtc, shadow); + crtc->funcs->shadow_destroy (crtc, shadow, shadowData); crtc->rotatedPixmap = NULL; + crtc->rotatedData = NULL; } - shadow = crtc->funcs->shadow_create (crtc, width, height); - if (!shadow) + shadowData = crtc->funcs->shadow_allocate (crtc, width, height); + if (!shadowData) goto bail1; - crtc->rotatedPixmap = shadow; + crtc->rotatedData = shadowData; } if (!xf86_config->rotationDamage) @@ -360,10 +368,6 @@ xf86CrtcRotate (xf86CrtcPtr crtc, DisplayModePtr mode, Rotation rotation) if (!xf86_config->rotationDamage) goto bail2; - /* Hook damage to screen pixmap */ - DamageRegister (&(*pScreen->GetScreenPixmap)(pScreen)->drawable, - xf86_config->rotationDamage); - /* Assign block/wakeup handler */ if (!RegisterBlockAndWakeupHandlers (xf86RotateBlockHandler, xf86RotateWakeupHandler, @@ -371,14 +375,6 @@ xf86CrtcRotate (xf86CrtcPtr crtc, DisplayModePtr mode, Rotation rotation) { goto bail3; } - damage_box.x1 = 0; - damage_box.y1 = 0; - damage_box.x2 = mode_width (mode, rotation); - damage_box.y2 = mode_height (mode, rotation); - REGION_INIT (pScreen, &damage_region, &damage_box, 1); - DamageDamageRegion (&(*pScreen->GetScreenPixmap)(pScreen)->drawable, - &damage_region); - REGION_UNINIT (pScreen, &damage_region); } if (0) { @@ -387,14 +383,16 @@ bail3: xf86_config->rotationDamage = NULL; bail2: - if (shadow) + if (shadow || shadowData) { - crtc->funcs->shadow_destroy (crtc, shadow); + crtc->funcs->shadow_destroy (crtc, shadow, shadowData); crtc->rotatedPixmap = NULL; + crtc->rotatedData = NULL; } bail1: if (old_width && old_height) crtc->rotatedPixmap = crtc->funcs->shadow_create (crtc, + NULL, old_width, old_height); return FALSE; diff --git a/hw/xfree86/modes/xf86cvt.c b/hw/xfree86/modes/xf86cvt.c index dd6febf2c..69ccc4259 100644 --- a/hw/xfree86/modes/xf86cvt.c +++ b/hw/xfree86/modes/xf86cvt.c @@ -40,6 +40,7 @@ #endif #include "xf86.h" +#include "xf86Modes.h" #include