diff options
author | Dave Airlie <airlied@linux.ie> | 2006-12-15 19:48:42 +1100 |
---|---|---|
committer | Dave Airlie <airlied@linux.ie> | 2006-12-15 19:48:42 +1100 |
commit | 62a5e7565b66d7b7d65609c034f34b55bd266617 (patch) | |
tree | 87d1db987e990ac4fbe9d2742a72e33d32f43d70 | |
parent | 29124400c7f193317d41d8cfd748371a239cfea1 (diff) |
bring over latest code from Intel git repo.
this code doesn't work yet just realigns with intel work
-rw-r--r-- | src/radeon.h | 1 | ||||
-rw-r--r-- | src/radeon_display.c | 55 | ||||
-rw-r--r-- | src/radeon_driver.c | 31 | ||||
-rw-r--r-- | src/radeon_modes.c | 10 | ||||
-rw-r--r-- | src/radeon_randr.c | 723 | ||||
-rw-r--r-- | src/radeon_xf86Crtc.c | 632 | ||||
-rw-r--r-- | src/radeon_xf86Crtc.h | 148 |
7 files changed, 1328 insertions, 272 deletions
diff --git a/src/radeon.h b/src/radeon.h index 733b9c50..04b51c44 100644 --- a/src/radeon.h +++ b/src/radeon.h @@ -407,7 +407,6 @@ typedef struct { }RADEONTMDSPll; typedef struct { - xf86CrtcConfigRec xf86_config; EntityInfoPtr pEnt; pciVideoPtr PciInfo; PCITAG PciTag; diff --git a/src/radeon_display.c b/src/radeon_display.c index f8db2ecf..260f5a17 100644 --- a/src/radeon_display.c +++ b/src/radeon_display.c @@ -2379,7 +2379,34 @@ void RADEONDisplayPowerManagementSet(ScrnInfoPtr pScrn, #endif } +static void +radeon_crtc_dpms(xf86CrtcPtr crtc, int mode) +{ + +} + +static Bool +radeon_crtc_mode_fixup(xf86CrtcPtr crtc, DisplayModePtr mode, + DisplayModePtr adjusted_mode) +{ + return TRUE; +} + +static void +radeon_crtc_mode_set(xf86CrtcPtr crtc, DisplayModePtr mode, + DisplayModePtr adjusted_mode) +{ + ScrnInfoPtr pScrn = crtc->scrn; + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); +} + static const xf86CrtcFuncsRec radeon_crtc_funcs = { + .dpms = radeon_crtc_dpms, + .save = NULL, /* XXX */ + .restore = NULL, /* XXX */ + .mode_fixup = radeon_crtc_mode_fixup, + .mode_set = radeon_crtc_mode_set, + .destroy = NULL, /* XXX */ }; static void @@ -2407,19 +2434,23 @@ radeon_mode_valid(xf86OutputPtr output, DisplayModePtr pMode) return MODE_OK; } -static void -radeon_pre_set_mode(xf86OutputPtr output, DisplayModePtr pMode) +static Bool +radeon_mode_fixup(xf86OutputPtr output, DisplayModePtr mode, + DisplayModePtr adjusted_mode) { + return TRUE; } static void -radeon_post_set_mode(xf86OutputPtr output, DisplayModePtr pMode) +radeon_mode_set(xf86OutputPtr output, DisplayModePtr mode, + DisplayModePtr adjusted_mode) { -} + +} -static enum detect_status +static xf86OutputStatus radeon_detect(xf86OutputPtr output) { ScrnInfoPtr pScrn = output->scrn; @@ -2428,11 +2459,11 @@ radeon_detect(xf86OutputPtr output) #if 0 // RADEONConnectorFindMonitor(pScrn, id); if (pRADEONEnt->PortInfo[id].MonType == MT_UNKNOWN) - return OUTPUT_STATUS_UNKNOWN; + return XF86OutputStatusUnknown; else if (pRADEONEnt->PortInfo[id].MonType == MT_NONE) - return OUTPUT_STATUS_DISCONNECTED; + return XF86OutputStatusDisconnected; else - return OUTPUT_STATUS_CONNECTED; + return XF86OutputStatusConnected; #endif } @@ -2452,8 +2483,8 @@ static const xf86OutputFuncsRec radeon_output_funcs = { .save = radeon_save, .restore = radeon_restore, .mode_valid = radeon_mode_valid, - .pre_set_mode = radeon_pre_set_mode, - .post_set_mode = radeon_post_set_mode, + .mode_fixup = radeon_mode_fixup, + .mode_set = radeon_mode_set, .detect = radeon_detect, .get_modes = radeon_get_modes, .destroy = radeon_destroy @@ -2471,7 +2502,7 @@ Bool RADEONAllocateControllers(ScrnInfoPtr pScrn) if (!pRADEONEnt->pCrtc[0]) return FALSE; - pRADEONEnt->Controller[0] = xnfcalloc(sizeof(xf86CrtcRec), 1); + pRADEONEnt->Controller[0] = xnfcalloc(sizeof(RADEONCrtcPrivateRec), 1); if (!pRADEONEnt->Controller[0]) return FALSE; @@ -2485,7 +2516,7 @@ Bool RADEONAllocateControllers(ScrnInfoPtr pScrn) if (!pRADEONEnt->pCrtc[1]) return FALSE; - pRADEONEnt->Controller[1] = xnfcalloc(sizeof(xf86CrtcRec), 1); + pRADEONEnt->Controller[1] = xnfcalloc(sizeof(RADEONCrtcPrivateRec), 1); if (!pRADEONEnt->Controller[1]) { xfree(pRADEONEnt->Controller[0]); diff --git a/src/radeon_driver.c b/src/radeon_driver.c index cf2af679..0aa594dc 100644 --- a/src/radeon_driver.c +++ b/src/radeon_driver.c @@ -2837,7 +2837,8 @@ static Bool RADEONPreInitXv(ScrnInfoPtr pScrn) static Bool RADEONPreInitControllers(ScrnInfoPtr pScrn, xf86Int10InfoPtr pInt10) { RADEONInfoPtr info = RADEONPTR(pScrn); - + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); + int i; if (!info->IsSecondary) { if (!RADEONAllocateConnectors(pScrn)) return FALSE; @@ -2855,7 +2856,13 @@ static Bool RADEONPreInitControllers(ScrnInfoPtr pScrn, xf86Int10InfoPtr pInt10 RADEONGetClockInfo(pScrn); RADEONGetPanelInfo(pScrn); RADEONGetTVDacAdjInfo(pScrn); - + + for (i = 0; i < config->num_output; i++) + { + xf86OutputPtr output = config->output[i]; + + output->status = (*output->funcs->detect) (output); + } return TRUE; } @@ -2872,6 +2879,7 @@ RADEONProbeDDC(ScrnInfoPtr pScrn, int indx) _X_EXPORT Bool RADEONPreInit(ScrnInfoPtr pScrn, int flags) { + xf86CrtcConfigPtr xf86_config; RADEONInfoPtr info; xf86Int10InfoPtr pInt10 = NULL; void *int10_save = NULL; @@ -2980,6 +2988,11 @@ _X_EXPORT Bool RADEONPreInit(ScrnInfoPtr pScrn, int flags) pScrn->racMemFlags = RAC_FB | RAC_COLORMAP | RAC_VIEWPORT | RAC_CURSOR; pScrn->monitor = pScrn->confScreen->monitor; + /* Allocate an xf86CrtcConfig */ + xf86CrtcConfigInit (pScrn); + xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); + + if (!RADEONPreInitVisual(pScrn)) goto fail; @@ -3202,6 +3215,7 @@ _X_EXPORT Bool RADEONPreInit(ScrnInfoPtr pScrn, int flags) info->directRenderingEnabled = RADEONPreInitDRI(pScrn); #endif + xf86CrtcSetSizeRange (pScrn, 320, 200, 16384, 2048); if (!RADEONPreInitVRAM(pScrn)) goto fail; @@ -3212,6 +3226,13 @@ _X_EXPORT Bool RADEONPreInit(ScrnInfoPtr pScrn, int flags) if (!RADEONPreInitControllers(pScrn, pInt10)) goto fail; + + if (!xf86InitialConfiguration (pScrn)) + { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No valid modes.\n"); + goto fail; + } + /* Get ScreenInit function */ if (!xf86LoadSubModule(pScrn, "fb")) return FALSE; @@ -3226,9 +3247,6 @@ _X_EXPORT Bool RADEONPreInit(ScrnInfoPtr pScrn, int flags) if (!RADEONPreInitGamma(pScrn)) goto fail; - if (!RADEONRandRPreInit(pScrn)) - goto fail; - if (!RADEONPreInitCursor(pScrn)) goto fail; if (!RADEONPreInitAccel(pScrn)) goto fail; @@ -4262,7 +4280,8 @@ _X_EXPORT Bool RADEONScreenInit(int scrnIndex, ScreenPtr pScreen, xf86DrvMsg(pScrn->scrnIndex, X_INFO, "RandR enabled, ignore the following RandR disabled message.\n"); xf86DisableRandR(); /* Disable built-in RandR extension */ /* support all rotations */ - RADEONRandRInit(pScreen, RR_Rotate_0); /* only 0 degrees for Radeon */ + xf86RandR12Init (pScreen); + xf86RandR12SetRotations (pScreen, RR_Rotate_0); /* only 0 degrees for I965G */ info->CreateScreenResources = pScreen->CreateScreenResources; pScreen->CreateScreenResources = RADEONCreateScreenResources; diff --git a/src/radeon_modes.c b/src/radeon_modes.c index bd11106e..639d39aa 100644 --- a/src/radeon_modes.c +++ b/src/radeon_modes.c @@ -595,14 +595,15 @@ int RADEONValidateMergeModes(ScrnInfoPtr pScrn1) void RADEONProbeOutputModes(ScrnInfoPtr pScrn) { + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR (pScrn); RADEONInfoPtr info = RADEONPTR(pScrn); RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); int i; DisplayModePtr ddc_modes, mode; DisplayModePtr test; - for (i = 0; i < info->xf86_config.num_output; i++) { - xf86OutputPtr output = info->xf86_config.output[i]; + for (i = 0; i < config->num_output; i++) { + xf86OutputPtr output = config->output[i]; test = output->probed_modes; while(test != NULL) { @@ -705,6 +706,7 @@ RADEONProbeOutputModes(ScrnInfoPtr pScrn) void RADEON_set_xf86_modes_from_outputs(ScrnInfoPtr pScrn) { + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR (pScrn); RADEONInfoPtr info = RADEONPTR(pScrn); RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); DisplayModePtr saved_mode, last; @@ -727,8 +729,8 @@ RADEON_set_xf86_modes_from_outputs(ScrnInfoPtr pScrn) * pScrn->modes should only be used for XF86VidMode now, which we don't * care about enough to make some sort of unioned list. */ - for (i = 0; i < info->xf86_config.num_output; i++) { - xf86OutputPtr output = info->xf86_config.output[i]; + for (i = 0; i < config->num_output; i++) { + xf86OutputPtr output = config->output[i]; if (output->probed_modes != NULL) { pScrn->modes = RADEONxf86DuplicateModes(pScrn, output->probed_modes); diff --git a/src/radeon_randr.c b/src/radeon_randr.c index d3bd4c83..baa92072 100644 --- a/src/radeon_randr.c +++ b/src/radeon_randr.c @@ -61,8 +61,8 @@ typedef struct _radeonRandRInfo { } XF86RandRInfoRec, *XF86RandRInfoPtr; #ifdef RANDR_12_INTERFACE -static Bool RADEONRandRInit12 (ScreenPtr pScreen); -static Bool RADEONRandRCreateScreenResources12 (ScreenPtr pScreen); +static Bool xf86RandR12Init12 (ScreenPtr pScreen); +static Bool xf86RandR12CreateScreenResources12 (ScreenPtr pScreen); #endif @@ -72,13 +72,279 @@ static int RADEONRandRGeneration; #define XF86RANDRINFO(p) ((XF86RandRInfoPtr) (p)->devPrivates[RADEONRandRIndex].ptr) #if RANDR_12_INTERFACE +static int +xf86RandR12ModeRefresh (DisplayModePtr mode) +{ + if (mode->VRefresh) + return (int) (mode->VRefresh + 0.5); + else + return (int) (mode->Clock * 1000.0 / mode->HTotal / mode->VTotal + 0.5); +} + +static Bool +xf86RandR12GetInfo (ScreenPtr pScreen, Rotation *rotations) +{ + RRScreenSizePtr pSize; + ScrnInfoPtr scrp = XF86SCRNINFO(pScreen); + XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen); + DisplayModePtr mode; + int refresh0 = 60; + int maxX = 0, maxY = 0; + + *rotations = randrp->supported_rotations; + + if (randrp->virtualX == -1 || randrp->virtualY == -1) + { + randrp->virtualX = scrp->virtualX; + randrp->virtualY = scrp->virtualY; + } + + /* Re-probe the outputs for new monitors or modes */ + xf86ProbeOutputModes (scrp); + xf86SetScrnInfoModes (scrp); + + for (mode = scrp->modes; ; mode = mode->next) + { + int refresh = xf86RandR12ModeRefresh (mode); + if (randrp->maxX == 0 || randrp->maxY == 0) + { + if (maxX < mode->HDisplay) + maxX = mode->HDisplay; + if (maxY < mode->VDisplay) + maxY = mode->VDisplay; + } + if (mode == scrp->modes) + refresh0 = refresh; + pSize = RRRegisterSize (pScreen, + mode->HDisplay, mode->VDisplay, + randrp->mmWidth, randrp->mmHeight); + if (!pSize) + return FALSE; + RRRegisterRate (pScreen, pSize, refresh); + + if (xf86ModesEqual(mode, scrp->currentMode) && + mode->HDisplay == scrp->virtualX && + mode->VDisplay == scrp->virtualY) + { + RRSetCurrentConfig (pScreen, randrp->rotation, refresh, pSize); + } + if (mode->next == scrp->modes) + break; + } + + if (randrp->maxX == 0 || randrp->maxY == 0) + { + randrp->maxX = maxX; + randrp->maxY = maxY; + } + + if (scrp->currentMode->HDisplay != randrp->virtualX || + scrp->currentMode->VDisplay != randrp->virtualY) + { + pSize = RRRegisterSize (pScreen, + randrp->virtualX, randrp->virtualY, + randrp->mmWidth, + randrp->mmHeight); + if (!pSize) + return FALSE; + RRRegisterRate (pScreen, pSize, refresh0); + if (scrp->virtualX == randrp->virtualX && + scrp->virtualY == randrp->virtualY) + { + RRSetCurrentConfig (pScreen, randrp->rotation, refresh0, pSize); + } + } + + return TRUE; +} + +static Bool +xf86RandR12SetMode (ScreenPtr pScreen, + DisplayModePtr mode, + Bool useVirtual, + int mmWidth, + int mmHeight) +{ + ScrnInfoPtr scrp = XF86SCRNINFO(pScreen); + XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen); + int oldWidth = pScreen->width; + int oldHeight = pScreen->height; + int oldmmWidth = pScreen->mmWidth; + int oldmmHeight = pScreen->mmHeight; + WindowPtr pRoot = WindowTable[pScreen->myNum]; + DisplayModePtr currentMode = NULL; + Bool ret = TRUE; + PixmapPtr pspix = NULL; + + if (pRoot) + (*scrp->EnableDisableFBAccess) (pScreen->myNum, FALSE); + if (useVirtual) + { + scrp->virtualX = randrp->virtualX; + scrp->virtualY = randrp->virtualY; + } + else + { + scrp->virtualX = mode->HDisplay; + scrp->virtualY = mode->VDisplay; + } + + if(randrp->rotation & (RR_Rotate_90 | RR_Rotate_270)) + { + /* If the screen is rotated 90 or 270 degrees, swap the sizes. */ + pScreen->width = scrp->virtualY; + pScreen->height = scrp->virtualX; + pScreen->mmWidth = mmHeight; + pScreen->mmHeight = mmWidth; + } + else + { + pScreen->width = scrp->virtualX; + pScreen->height = scrp->virtualY; + pScreen->mmWidth = mmWidth; + pScreen->mmHeight = mmHeight; + } + if (scrp->currentMode == mode) { + /* Save current mode */ + currentMode = scrp->currentMode; + /* Reset, just so we ensure the drivers SwitchMode is called */ + scrp->currentMode = NULL; + } + /* + * We know that if the driver failed to SwitchMode to the rotated + * version, then it should revert back to it's prior mode. + */ + if (!xf86SwitchMode (pScreen, mode)) + { + ret = FALSE; + scrp->virtualX = pScreen->width = oldWidth; + scrp->virtualY = pScreen->height = oldHeight; + pScreen->mmWidth = oldmmWidth; + pScreen->mmHeight = oldmmHeight; + scrp->currentMode = currentMode; + } + /* + * Get the new Screen pixmap ptr as SwitchMode might have called + * ModifyPixmapHeader and xf86EnableDisableFBAccess will put it back... + * Unfortunately. + */ + pspix = (*pScreen->GetScreenPixmap) (pScreen); + if (pspix->devPrivate.ptr) + scrp->pixmapPrivate = pspix->devPrivate; + + /* + * Make sure the layout is correct + */ + xf86ReconfigureLayout(); + + /* + * Make sure the whole screen is visible + */ + xf86SetViewport (pScreen, pScreen->width, pScreen->height); + xf86SetViewport (pScreen, 0, 0); + if (pRoot) + (*scrp->EnableDisableFBAccess) (pScreen->myNum, TRUE); + return ret; +} + +Bool +xf86RandR12SetConfig (ScreenPtr pScreen, + Rotation rotation, + int rate, + RRScreenSizePtr pSize) +{ + ScrnInfoPtr scrp = XF86SCRNINFO(pScreen); + XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen); + DisplayModePtr mode; + int px, py; + Bool useVirtual = FALSE; + int maxX = 0, maxY = 0; + Rotation oldRotation = randrp->rotation; + + randrp->rotation = rotation; + + if (randrp->virtualX == -1 || randrp->virtualY == -1) + { + randrp->virtualX = scrp->virtualX; + randrp->virtualY = scrp->virtualY; + } + + miPointerPosition (&px, &py); + for (mode = scrp->modes; ; mode = mode->next) + { + if (randrp->maxX == 0 || randrp->maxY == 0) + { + if (maxX < mode->HDisplay) + maxX = mode->HDisplay; + if (maxY < mode->VDisplay) + maxY = mode->VDisplay; + } + if (mode->HDisplay == pSize->width && + mode->VDisplay == pSize->height && + (rate == 0 || xf86RandR12ModeRefresh (mode) == rate)) + break; + if (mode->next == scrp->modes) + { + if (pSize->width == randrp->virtualX && + pSize->height == randrp->virtualY) + { + mode = scrp->modes; + useVirtual = TRUE; + break; + } + if (randrp->maxX == 0 || randrp->maxY == 0) + { + randrp->maxX = maxX; + randrp->maxY = maxY; + } + return FALSE; + } + } + + if (randrp->maxX == 0 || randrp->maxY == 0) + { + randrp->maxX = maxX; + randrp->maxY = maxY; + } + + if (!xf86RandR12SetMode (pScreen, mode, useVirtual, pSize->mmWidth, + pSize->mmHeight)) { + randrp->rotation = oldRotation; + return FALSE; + } + + /* + * Move the cursor back where it belongs; SwitchMode repositions it + */ + if (pScreen == miPointerCurrentScreen ()) + { + px = (px >= pScreen->width ? (pScreen->width - 1) : px); + py = (py >= pScreen->height ? (pScreen->height - 1) : py); + + xf86SetViewport(pScreen, px, py); + + (*pScreen->SetCursorPosition) (pScreen, px, py, FALSE); + } + + return TRUE; +} + +Rotation +xf86RandR12GetRotation(ScreenPtr pScreen) +{ + XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen); + + return randrp->rotation; +} + + static void RADEONRandRPointerMoved (int scrnIndex, int x, int y) { } static Bool -RADEONRandRScreenSetSize (ScreenPtr pScreen, +xf86RandR12ScreenSetSize (ScreenPtr pScreen, CARD16 width, CARD16 height, CARD32 mmWidth, @@ -89,7 +355,7 @@ RADEONRandRScreenSetSize (ScreenPtr pScreen, WindowPtr pRoot = WindowTable[pScreen->myNum]; Bool ret = TRUE; - if (randrp->virtualX == -1 || randrp->virtualY == -1) + if (randrp->virtualX == -1 || randrp->virtualY == -1) { randrp->virtualX = pScrn->virtualX; randrp->virtualY = pScrn->virtualY; @@ -103,7 +369,7 @@ RADEONRandRScreenSetSize (ScreenPtr pScreen, pScreen->height = pScrn->virtualY; pScreen->mmWidth = mmWidth; pScreen->mmHeight = mmHeight; - + xf86SetViewport (pScreen, pScreen->width, pScreen->height); xf86SetViewport (pScreen, 0, 0); if (pRoot) @@ -114,79 +380,93 @@ RADEONRandRScreenSetSize (ScreenPtr pScreen, } static Bool -RADEONRandRCrtcNotify (RRCrtcPtr randr_crtc) +xf86RandR12CrtcNotify (RRCrtcPtr randr_crtc) { - ScreenPtr pScreen = randr_crtc->pScreen; - XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen); - ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; - RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); - RADEONInfoPtr info = RADEONPTR(pScrn); - RRModePtr randr_mode = NULL; - int x, y; - Rotation rotation; - int numOutputs; - RROutputPtr randr_outputs[RADEON_MAX_CRTC]; - RROutputPtr randr_output; - xf86CrtcPtr crtc = randr_crtc->devPrivate; - xf86OutputPtr output; - int i, j; - DisplayModePtr curMode = &crtc->curMode; - - x = crtc->x; - y = crtc->y; - rotation = RR_Rotate_0; - numOutputs = 0; - randr_mode = NULL; - - for (i = 0; i < info->xf86_config.num_output; i++) { - output = info->xf86_config.output[i]; - if (output->crtc == crtc) { - - randr_output = output->randr_output; - randr_outputs[numOutputs++] = randr_output; - - for (j = 0; j < randr_output->numModes; j++) { - DisplayModePtr outMode = randr_output->modes[j]->devPrivate; - if (xf86ModesEqual(curMode, outMode)) { - randr_mode = randr_output->modes[j]; - break; + ScreenPtr pScreen = randr_crtc->pScreen; + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); + RRModePtr randr_mode = NULL; + int x; + int y; + Rotation rotation; + int numOutputs; + RROutputPtr *randr_outputs; + RROutputPtr randr_output; + xf86CrtcPtr crtc = randr_crtc->devPrivate; + xf86OutputPtr output; + int i, j; + DisplayModePtr curMode = &crtc->curMode; + Bool ret; + + randr_outputs = ALLOCATE_LOCAL(config->num_output * sizeof (RROutputPtr)); + if (!randr_outputs) + return FALSE; + x = crtc->x; + y = crtc->y; + rotation = RR_Rotate_0; + numOutputs = 0; + randr_mode = NULL; + for (i = 0; i < config->num_output; i++) + { + output = config->output[i]; + if (output->crtc == crtc) + { + randr_output = output->randr_output; + randr_outputs[numOutputs++] = randr_output; + /* + * We make copies of modes, so pointer equality + * isn't sufficient + */ + for (j = 0; j < randr_output->numModes; j++) + { + DisplayModePtr outMode = randr_output->modes[j]->devPrivate; + if (xf86ModesEqual(curMode, outMode)) + { + randr_mode = randr_output->modes[j]; + break; + } + } } - } } - } - - return RRCrtcNotify (randr_crtc, randr_mode, x, y, rotation, numOutputs, randr_outputs); + ret = RRCrtcNotify (randr_crtc, randr_mode, x, y, + rotation, numOutputs, randr_outputs); + DEALLOCATE_LOCAL(randr_outputs); + return ret; } static Bool -RADEONRandRCrtcSet (ScreenPtr pScreen, - RRCrtcPtr randr_crtc, - RRModePtr randr_mode, - int x, - int y, - Rotation rotation, - int num_randr_outputs, - RROutputPtr *randr_outputs) +xf86RandR12CrtcSet (ScreenPtr pScreen, + RRCrtcPtr randr_crtc, + RRModePtr randr_mode, + int x, + int y, + Rotation rotation, + int num_randr_outputs, + RROutputPtr *randr_outputs) { ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; - RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); - RADEONInfoPtr info = RADEONPTR(pScrn); + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); xf86CrtcPtr crtc = randr_crtc->devPrivate; - RADEONCrtcPrivatePtr pRcrtc = crtc->driver_private; DisplayModePtr mode = randr_mode ? randr_mode->devPrivate : NULL; Bool changed = FALSE; + Bool pos_changed; int o, ro; - xf86CrtcPtr save_crtcs[RADEON_MAX_CONNECTOR]; + xf86CrtcPtr *save_crtcs; Bool save_enabled = crtc->enabled; int ret; + save_crtcs = ALLOCATE_LOCAL(config->num_crtc * sizeof (xf86CrtcPtr)); if ((mode != NULL) != crtc->enabled) changed = TRUE; else if (mode && !xf86ModesEqual (&crtc->curMode, mode)) changed = TRUE; - for (o = 0; o < info->xf86_config.num_output; o++) { - xf86OutputPtr output = info->xf86_config.output[o]; + pos_changed = changed; + if (x != crtc->x || y != crtc->y) + pos_changed = TRUE; + + for (o = 0; o < config->num_output; o++) { + xf86OutputPtr output = config->output[o]; xf86CrtcPtr new_crtc; save_crtcs[o] = output->crtc; @@ -209,6 +489,9 @@ RADEONRandRCrtcSet (ScreenPtr pScreen, /* got to set the modes in here */ if (changed) { + RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); + RADEONInfoPtr info = RADEONPTR(pScrn); + RADEONCrtcPrivatePtr pRcrtc; crtc->enabled = mode != NULL; if (info->accelOn) @@ -222,31 +505,31 @@ RADEONRandRCrtcSet (ScreenPtr pScreen, if (!ret) { crtc->enabled = save_enabled; - for (o = 0; o < info->xf86_config.num_output; o++) { - xf86OutputPtr output = info->xf86_config.output[o]; + for (o = 0; o < config->num_output; o++) { + xf86OutputPtr output = config->output[o]; output->crtc = save_crtcs[o]; } + DEALLOCATE_LOCAL(save_crtcs); return FALSE; } crtc->desiredMode = *mode; + + pScrn->vtSema = TRUE; + RADEONBlank(pScrn); + RADEONRestoreMode(pScrn, &info->ModeReg); + RADEONUnblank(pScrn); + + if (info->DispPriority) + RADEONInitDispBandwidth(pScrn); } } - - if (changed) { - pScrn->vtSema = TRUE; - RADEONBlank(pScrn); - RADEONRestoreMode(pScrn, &info->ModeReg); - RADEONUnblank(pScrn); - - if (info->DispPriority) - RADEONInitDispBandwidth(pScrn); - } + DEALLOCATE_LOCAL(save_crtcs); return RADEONRandRCrtcNotify(randr_crtc); } static Bool -RADEONRandRCrtcSetGamma (ScreenPtr pScreen, +xf86RandR12CrtcSetGamma (ScreenPtr pScreen, RRCrtcPtr crtc) { return FALSE; @@ -257,7 +540,7 @@ RADEONRandRCrtcSetGamma (ScreenPtr pScreen, * RandR modes and assign them to the output */ static Bool -RADEONxf86RROutputSetModes (RROutputPtr randr_output, DisplayModePtr modes) +xf86RROutputSetModes (RROutputPtr randr_output, DisplayModePtr modes) { DisplayModePtr mode; RRModePtr *rrmodes = NULL; @@ -316,63 +599,80 @@ RADEONxf86RROutputSetModes (RROutputPtr randr_output, DisplayModePtr modes) * Mirror the current mode configuration to RandR */ static Bool -RADEONRandRSetInfo12 (ScrnInfoPtr pScrn) +xf86RandR12SetInfo12 (ScreenPtr pScreen) { - RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); - RROutputPtr clones[RADEON_MAX_CONNECTOR]; - RRCrtcPtr crtc; - int nclone; - RRCrtcPtr crtcs[RADEON_MAX_CRTC]; - int ncrtc; - DisplayModePtr modes, mode; - xRRModeInfo modeInfo; - RRModePtr rrmode, *rrmodes; - int nmode, npreferred; - int i, j, p; - CARD32 possibleOptions = 0; - CARD32 currentOptions = 0; - int connection; - int subpixel = SubPixelNone; - RRCrtcPtr randr_crtc; - xf86OutputPtr connector; - RADEONOutputPrivatePtr pRPort; - - for (i = 0; i < RADEON_MAX_CONNECTOR; i++) { - ncrtc = 0; - crtc = NULL; - - connector = pRADEONEnt->pOutput[i]; - pRPort = pRADEONEnt->PortInfo[i]; - - if (pRPort->MonType) { - crtc = pRADEONEnt->pCrtc[i]->randr_crtc; - crtcs[ncrtc++] = crtc; - randr_crtc = crtc; - } else - randr_crtc = NULL; - - - if (!RROutputSetCrtcs(connector->randr_output, crtcs, ncrtc)) - return FALSE; + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); + RROutputPtr *clones; + RRCrtcPtr *crtcs; + int ncrtc; + int o, c, l; + RRCrtcPtr randr_crtc; + int nclone; + + clones = ALLOCATE_LOCAL(config->num_output * sizeof (RROutputPtr)); + crtcs = ALLOCATE_LOCAL (config->num_crtc * sizeof (RRCrtcPtr)); + for (o = 0; o < config->num_output; o++) + { + xf86OutputPtr output = config->output[o]; + + ncrtc = 0; + for (c = 0; c < config->num_crtc; c++) + if (output->possible_crtcs & (1 << c)) + crtcs[ncrtc++] = config->crtc[c]->randr_crtc; - RROutputSetCrtc(connector->randr_output, crtc); + if (output->crtc) + randr_crtc = output->crtc->randr_crtc; + else + randr_crtc = NULL; - nmode = 0; - npreferred = 0; - rrmodes = NULL; - - if (connector->probed_modes) { - RADEONxf86RROutputSetModes (connector->randr_output, connector->probed_modes); - } + if (!RROutputSetCrtcs (output->randr_output, crtcs, ncrtc)) + { + DEALLOCATE_LOCAL (crtcs); + DEALLOCATE_LOCAL (clones); + return FALSE; + } - connection = RR_Disconnected; - if (pRPort->MonType > MT_NONE) - connection = RR_Connected; + RROutputSetCrtc (output->randr_output, randr_crtc); + RROutputSetPhysicalSize(output->randr_output, + output->mm_width, + output->mm_height); + xf86RROutputSetModes (output->randr_output, output->probed_modes); + + switch (output->status = (*output->funcs->detect)(output)) { + case XF86OutputStatusConnected: + RROutputSetConnection (output->randr_output, RR_Connected); + break; + case XF86OutputStatusDisconnected: + RROutputSetConnection (output->randr_output, RR_Disconnected); + break; + case XF86OutputStatusUnknown: + RROutputSetConnection (output->randr_output, RR_UnknownConnection); + break; + } - RROutputSetConnection(connector->randr_output, connection); + RROutputSetSubpixelOrder (output->randr_output, output->subpixel_order); - RROutputSetSubpixelOrder(connector->randr_output, subpixel); + /* + * Valid clones + */ + nclone = 0; + for (l = 0; l < config->num_output; l++) + { + xf86OutputPtr clone = config->output[l]; + + if (l != o && (output->possible_clones & (1 << l))) + clones[nclone++] = clone->randr_output; + } + if (!RROutputSetClones (output->randr_output, clones, nclone)) + { + DEALLOCATE_LOCAL (crtcs); + DEALLOCATE_LOCAL (clones); + return FALSE; + } } + DEALLOCATE_LOCAL (crtcs); + DEALLOCATE_LOCAL (clones); return TRUE; } @@ -381,11 +681,12 @@ RADEONRandRSetInfo12 (ScrnInfoPtr pScrn) * that to RandR */ static Bool -RADEONRandRGetInfo12 (ScreenPtr pScreen, Rotation *rotations) +xf86RandR12GetInfo12 (ScreenPtr pScreen, Rotation *rotations) { ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; - RADEONProbeOutputModes(pScrn); + xf86ProbeOutputModes (pScrn); + xf86SetScrnInfoModes (pScrn); return RADEONRandRSetInfo12 (pScrn); } @@ -402,100 +703,101 @@ RADEONRandRCreateScreenResources (ScreenPtr pScreen) } static Bool -RADEONRandRCreateObjects12(ScrnInfoPtr pScrn) +xf86RandR12CreateObjects12(ScreenPtr pScreen) { - int i; - RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); - RADEONInfoPtr info = RADEONPTR(pScrn); + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); + int c, o; if (!RRInit()) return FALSE; + /* - * Create RandR resources, then probe them + * Configure crtcs */ - for (i = 0; i < 2; i++) + for (c = 0; c < config->num_crtc; c++) { - RRCrtcPtr randr_crtc = RRCrtcCreate((void *)i); - - if (!randr_crtc) - return FALSE; - - RRCrtcGammaSetSize(randr_crtc, 256); - pRADEONEnt->pCrtc[i]->randr_crtc = randr_crtc; + xf86CrtcPtr crtc = config->crtc[c]; + + crtc->randr_crtc = RRCrtcCreate (crtc); + RRCrtcAttachScreen (crtc->randr_crtc, pScreen); + RRCrtcGammaSetSize (crtc->randr_crtc, 256); } - for (i = 0; i < 2; i++) + /* + * Configure outputs + */ + for (o = 0; o < config->num_output; o++) { - int output = pRADEONEnt->PortInfo[i]->ConnectorType; - const char *name = name = info->IsAtomBios ? ConnectorTypeNameATOM[output] : ConnectorTypeName[output]; - RROutputPtr randr_output = RROutputCreate(name, strlen(name), - (void *) i); + xf86OutputPtr output = config->output[o]; - if (!randr_output) - return FALSE; + output->randr_output = RROutputCreate (output->name, + strlen (output->name), + output); + RROutputAttachScreen (output->randr_output, pScreen); + } - pRADEONEnt->pOutput[i]->randr_output = randr_output; - } return TRUE; } static Bool -RADEONRandRCreateScreenResources12 (ScreenPtr pScreen) +xf86RandRCreateScreenResources12 (ScreenPtr pScreen) { - XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen); - ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; - RADEONInfoPtr info = RADEONPTR(pScrn); - RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); - DisplayModePtr mode; - const char *name; - int i; - - for (i = 0; i < 2; i++) - { - if (!RRCrtcAttachScreen(pRADEONEnt->pCrtc[i]->randr_crtc, pScreen)) - return FALSE; - } - - for (i = 0; i < 2; i++) { - if (!RROutputAttachScreen(pRADEONEnt->pOutput[i]->randr_output, pScreen)) - return FALSE; - } + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); + XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen); + int c; + int width, height; - mode = pScrn->currentMode; - if (mode) { - int mmWidth, mmHeight; + /* + * Compute width of screen + */ + width = 0; height = 0; + for (c = 0; c < config->num_crtc; c++) + { + xf86CrtcPtr crtc = config->crtc[c]; + int crtc_width = crtc->x + crtc->curMode.HDisplay; + int crtc_height = crtc->y + crtc->curMode.VDisplay; + + if (crtc->enabled && crtc_width > width) + width = crtc_width; + if (crtc->enabled && crtc_height > height) + height = crtc_height; + } - if (mode->HDisplay == pScreen->width && - mode->VDisplay == pScreen->height) - { - mmWidth = pScrn->widthmm; - mmHeight = pScrn->heightmm; - } else { -#define MMPERINCH 25.4 - mmWidth = (double) mode->HDisplay / pScrn->xDpi * MMPERINCH; - mmHeight = (double) mode->VDisplay / pScrn->yDpi * MMPERINCH; - } - RADEONRandRScreenSetSize (pScreen, - mode->HDisplay, - mode->VDisplay, - mmWidth, - mmHeight); - } + if (width && height) + { + int mmWidth, mmHeight; + + mmWidth = pScreen->mmWidth; + mmHeight = pScreen->mmHeight; + if (width != pScreen->width) + mmWidth = mmWidth * width / pScreen->width; + if (height != pScreen->height) + mmHeight = mmHeight * height / pScreen->height; + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Setting screen physical size to %d x %d\n", + mmWidth, mmHeight); + xf86RandR12ScreenSetSize (pScreen, + width, + height, + mmWidth, + mmHeight); + } - for (i = 0; i < RADEON_MAX_CRTC; i++) - RADEONRandRCrtcNotify (pRADEONEnt->pCrtc[i]->randr_crtc); + for (c = 0; c < config->num_crtc; c++) + xf86RandR12CrtcNotify (config->crtc[c]->randr_crtc); - if (randrp->virtualX == -1 || randrp->virtualY == -1) - { - randrp->virtualX = pScrn->virtualX; - randrp->virtualY = pScrn->virtualY; - } - - RRScreenSetSizeRange (pScreen, 320, 240, - randrp->virtualX, randrp->virtualY); - return TRUE; - + if (randrp->virtualX == -1 || randrp->virtualY == -1) + { + randrp->virtualX = pScrn->virtualX; + randrp->virtualY = pScrn->virtualY; + } + + RRScreenSetSizeRange (pScreen, 320, 240, + randrp->virtualX, randrp->virtualY); + return TRUE; } Bool @@ -548,19 +850,27 @@ RADEONRandRInit (ScreenPtr pScreen, int rotation) return TRUE; } -static Bool +Bool RADEONRandRInit12(ScreenPtr pScreen) { ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; rrScrPrivPtr rp = rrGetScrPriv(pScreen); - rp->rrGetInfo = RADEONRandRGetInfo12; - rp->rrScreenSetSize = RADEONRandRScreenSetSize; - rp->rrCrtcSet = RADEONRandRCrtcSet; - rp->rrCrtcSetGamma = RADEONRandRCrtcSetGamma; + rp->rrGetInfo = xf86RandR12GetInfo12; + rp->rrScreenSetSize = xf86RandR12ScreenSetSize; + rp->rrCrtcSet = xf86RandR12CrtcSet; + rp->rrCrtcSetGamma = xf86RandR12CrtcSetGamma; rp->rrSetConfig = NULL; // memset (rp->modes, '\0', sizeof (rp->modes)); pScrn->PointerMoved = RADEONRandRPointerMoved; + + if (!xf86RandR12CreateObjects12 (pScreen)) + return FALSE; + /* + * Configure output modes + */ + if (!xf86RandR12SetInfo12 (pScreen)) + return FALSE; return TRUE; } @@ -823,7 +1133,7 @@ RADEONRRDefaultScreenLimits (RROutputPtr *outputs, int num_outputs, *heightp = height; } - +#if 0 Bool RADEONRandRPreInit(ScrnInfoPtr pScrn) { @@ -841,7 +1151,7 @@ RADEONRandRPreInit(ScrnInfoPtr pScrn) RADEONProbeOutputModes(pScrn); #if RANDR_12_INTERFACE - if (!RADEONRandRCreateObjects12(pScrn)) + if (!xf86RandRCreateObjects12(pScrn)) return FALSE; if (!RADEONRandRSetInfo12(pScrn)) @@ -905,3 +1215,10 @@ RADEONRandRPreInit(ScrnInfoPtr pScrn) return TRUE; } #endif +#endif + +Bool +xf86RandR12PreInit (ScrnInfoPtr pScrn) +{ + return TRUE; +} diff --git a/src/radeon_xf86Crtc.c b/src/radeon_xf86Crtc.c index 41d6f860..22f7ae47 100644 --- a/src/radeon_xf86Crtc.c +++ b/src/radeon_xf86Crtc.c @@ -31,7 +31,43 @@ #include <stdio.h> #include "xf86.h" +#include "xf86DDC.h" +//#include "i.h" #include "radeon_xf86Crtc.h" +#include "X11/extensions/render.h" + +#define DPMS_SERVER +#include "X11/extensions/dpms.h" + +/* + * Initialize xf86CrtcConfig structure + */ + +int xf86CrtcConfigPrivateIndex = -1; + +void +xf86CrtcConfigInit (ScrnInfoPtr scrn) +{ + xf86CrtcConfigPtr config; + + if (xf86CrtcConfigPrivateIndex == -1) + xf86CrtcConfigPrivateIndex = xf86AllocateScrnInfoPrivateIndex(); + config = xnfcalloc (1, sizeof (xf86CrtcConfigRec)); + scrn->privates[xf86CrtcConfigPrivateIndex].ptr = config; +} + +void +xf86CrtcSetSizeRange (ScrnInfoPtr scrn, + int minWidth, int minHeight, + int maxWidth, int maxHeight) +{ + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); + + config->minWidth = minWidth; + config->minHeight = minHeight; + config->maxWidth = maxWidth; + config->maxHeight = maxHeight; +} /* * Crtc functions @@ -41,7 +77,7 @@ xf86CrtcCreate (ScrnInfoPtr scrn, const xf86CrtcFuncsRec *funcs) { xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); - xf86CrtcPtr crtc; + xf86CrtcPtr crtc, *crtcs; crtc = xcalloc (sizeof (xf86CrtcRec), 1); if (!crtc) @@ -49,13 +85,19 @@ xf86CrtcCreate (ScrnInfoPtr scrn, crtc->scrn = scrn; crtc->funcs = funcs; #ifdef RANDR_12_INTERFACE - crtc->randr_crtc = RRCrtcCreate (crtc); - if (!crtc->randr_crtc) + crtc->randr_crtc = NULL; +#endif + if (xf86_config->crtc) + crtcs = xrealloc (xf86_config->crtc, + (xf86_config->num_crtc + 1) * sizeof (xf86CrtcPtr)); + else + crtcs = xalloc ((xf86_config->num_crtc + 1) * sizeof (xf86CrtcPtr)); + if (!crtcs) { xfree (crtc); return NULL; } -#endif + xf86_config->crtc = crtcs; xf86_config->crtc[xf86_config->num_crtc++] = crtc; return crtc; } @@ -67,9 +109,6 @@ xf86CrtcDestroy (xf86CrtcPtr crtc) int c; (*crtc->funcs->destroy) (crtc); -#ifdef RANDR_12_INTERFACE - RRCrtcDestroy (crtc->randr_crtc); -#endif for (c = 0; c < xf86_config->num_crtc; c++) if (xf86_config->crtc[c] == crtc) { @@ -90,7 +129,7 @@ xf86OutputCreate (ScrnInfoPtr scrn, const xf86OutputFuncsRec *funcs, const char *name) { - xf86OutputPtr output; + xf86OutputPtr output, *outputs; xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); int len = strlen (name); @@ -100,20 +139,42 @@ xf86OutputCreate (ScrnInfoPtr scrn, output->scrn = scrn; output->funcs = funcs; output->name = (char *) (output + 1); + output->subpixel_order = SubPixelUnknown; strcpy (output->name, name); #ifdef RANDR_12_INTERFACE - output->randr_output = RROutputCreate (name, strlen (name), output); - if (!output->randr_output) + output->randr_output = NULL; +#endif + if (xf86_config->output) + outputs = xrealloc (xf86_config->output, + (xf86_config->num_output + 1) * sizeof (xf86OutputPtr)); + else + outputs = xalloc ((xf86_config->num_output + 1) * sizeof (xf86OutputPtr)); + if (!outputs) { xfree (output); return NULL; } -#endif + xf86_config->output = outputs; xf86_config->output[xf86_config->num_output++] = output; return output; } void +xf86OutputRename (xf86OutputPtr output, const char *name) +{ + int len = strlen(name); + char *newname = xalloc (len + 1); + + if (!newname) + return; /* so sorry... */ + + strcpy (newname, name); + if (output->name != (char *) (output + 1)) + xfree (output->name); + output->name = newname; +} + +void xf86OutputDestroy (xf86OutputPtr output) { ScrnInfoPtr scrn = output->scrn; @@ -121,9 +182,6 @@ xf86OutputDestroy (xf86OutputPtr output) int o; (*output->funcs->destroy) (output); -#ifdef RANDR_12_INTERFACE - RROutputDestroy (output->randr_output); -#endif while (output->probed_modes) xf86DeleteMode (&output->probed_modes, output->probed_modes); for (o = 0; o < xf86_config->num_output; o++) @@ -135,6 +193,552 @@ xf86OutputDestroy (xf86OutputPtr output) xf86_config->num_output--; break; } + if (output->name != (char *) (output + 1)) + xfree (output->name); xfree (output); } +static DisplayModePtr +xf86DefaultMode (xf86OutputPtr output, int width, int height) +{ + DisplayModePtr target_mode = NULL; + DisplayModePtr mode; + int target_diff = 0; + int target_preferred = 0; + int mm_height; + + mm_height = output->mm_height; + if (!mm_height) + mm_height = 203; /* 768 pixels at 96dpi */ + /* + * Pick a mode closest to 96dpi + */ + for (mode = output->probed_modes; mode; mode = mode->next) + { + int dpi; + 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); + diff = dpi - 96; + diff = diff < 0 ? -diff : diff; + if (target_mode == NULL || (preferred > target_preferred) || + (preferred == target_preferred && diff < target_diff)) + { + target_mode = mode; + target_diff = diff; + target_preferred = preferred; + } + } + return target_mode; +} + +static DisplayModePtr +xf86ClosestMode (xf86OutputPtr output, DisplayModePtr match, + int width, int height) +{ + DisplayModePtr target_mode = NULL; + DisplayModePtr mode; + int target_diff = 0; + + /* + * Pick a mode closest to the specified mode + */ + for (mode = output->probed_modes; mode; mode = mode->next) + { + int dx, dy; + int diff; + + if (mode->HDisplay > width || mode->VDisplay > height) continue; + + /* exact matches are preferred */ + if (xf86ModesEqual (mode, match)) + return mode; + + dx = match->HDisplay - mode->HDisplay; + dy = match->VDisplay - mode->VDisplay; + diff = dx * dx + dy * dy; + if (target_mode == NULL || diff < target_diff) + { + target_mode = mode; + target_diff = diff; + } + } + return target_mode; +} + +static Bool +xf86OutputHasPreferredMode (xf86OutputPtr output, int width, int height) +{ + DisplayModePtr mode; + + for (mode = output->probed_modes; mode; mode = mode->next) + { + if (mode->HDisplay > width || mode->VDisplay > height) continue; + if (mode->type & M_T_PREFERRED) + return TRUE; + } + return FALSE; +} + +static int +xf86PickCrtcs (ScrnInfoPtr pScrn, + xf86CrtcPtr *best_crtcs, + DisplayModePtr *modes, + int n, + int width, + int height) +{ + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); + int c, o, l; + xf86OutputPtr output; + xf86CrtcPtr crtc; + xf86CrtcPtr *crtcs; + xf86CrtcPtr best_crtc; + int best_score; + int score; + int my_score; + + if (n == config->num_output) + return 0; + output = config->output[n]; + + /* + * Compute score with this output disabled + */ + best_crtcs[n] = NULL; + best_crtc = NULL; + best_score = xf86PickCrtcs (pScrn, best_crtcs, modes, n+1, width, height); + if (modes[n] == NULL) + return best_score; + + crtcs = xalloc (config->num_output * sizeof (xf86CrtcPtr)); + if (!crtcs) + return best_score; + + my_score = 1; + /* Score outputs that are known to be connected higher */ + if (output->status == XF86OutputStatusConnected) + my_score++; + /* Score outputs with preferred modes higher */ + if (xf86OutputHasPreferredMode (output, width, height)) + my_score++; + /* + * Select a crtc for this output and + * then attempt to configure the remaining + * outputs + */ + for (c = 0; c < config->num_crtc; c++) + { + if ((output->possible_crtcs & (1 << c)) == 0) + continue; + + crtc = config->crtc[c]; + /* + * Check to see if some other output is + * using this crtc + */ + for (o = 0; o < n; o++) + if (best_crtcs[o] == crtc) + break; + if (o < n) + { + /* + * If the two outputs desire the same mode, + * see if they can be cloned + */ + if (xf86ModesEqual (modes[o], modes[n])) + { + for (l = 0; l < config->num_output; l++) + if (output->possible_clones & (1 << l)) + break; + if (l == config->num_output) + continue; /* nope, try next CRTC */ + } + else + continue; /* different modes, can't clone */ + } + crtcs[n] = crtc; + memcpy (crtcs, best_crtcs, n * sizeof (xf86CrtcPtr)); + score = my_score + xf86PickCrtcs (pScrn, crtcs, modes, n+1, width, height); + if (score >= best_score) + { + best_crtc = crtc; + best_score = score; + memcpy (best_crtcs, crtcs, config->num_output * sizeof (xf86CrtcPtr)); + } + } + xfree (crtcs); + return best_score; +} + + +/* + * Compute the virtual size necessary to place all of the available + * crtcs in a panorama configuration + */ + +static void +xf86DefaultScreenLimits (ScrnInfoPtr pScrn, int *widthp, int *heightp) +{ + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); + int width = 0, height = 0; + int o; + int c; + int s; + + for (c = 0; c < config->num_crtc; c++) + { + int crtc_width = 0, crtc_height = 0; + + for (o = 0; o < config->num_output; o++) + { + xf86OutputPtr output = config->output[o]; + + for (s = 0; s < config->num_crtc; s++) + if (output->possible_crtcs & (1 << s)) + { + DisplayModePtr mode; + for (mode = output->probed_modes; mode; mode = mode->next) + { + if (mode->HDisplay > crtc_width) + crtc_width = mode->HDisplay; + if (mode->VDisplay > crtc_height) + crtc_height = mode->VDisplay; + } + } + } + width += crtc_width; + if (crtc_height > height) + height = crtc_height; + } + if (config->maxWidth && width > config->maxWidth) width = config->maxWidth; + if (config->maxHeight && height > config->maxHeight) height = config->maxHeight; + if (config->minWidth && width < config->minWidth) width = config->minWidth; + if (config->minHeight && height < config->minHeight) height = config->minHeight; + *widthp = width; + *heightp = height; +} + +/* + * XXX walk the monitor mode list and prune out duplicates that + * are inserted by xf86DDCMonitorSet. In an ideal world, that + * function would do this work by itself. + */ + +static void +xf86PruneDuplicateMonitorModes (MonPtr Monitor) +{ + DisplayModePtr master, clone, next; + + for (master = Monitor->Modes; + master && master != Monitor->Last; + master = master->next) + { + for (clone = master->next; clone && clone != Monitor->Modes; clone = next) + { + next = clone->next; + if (xf86ModesEqual (master, clone)) + xf86DeleteMode (&Monitor->Modes, clone); + } + } +} + +void +xf86ProbeOutputModes (ScrnInfoPtr pScrn) +{ + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); + Bool properties_set = FALSE; + int o; + + /* Elide duplicate modes before defaulting code uses them */ + xf86PruneDuplicateMonitorModes (pScrn->monitor); + + /* Probe the list of modes for each output. */ + for (o = 0; o < config->num_output; o++) + { + xf86OutputPtr output = config->output[o]; + DisplayModePtr mode; + + while (output->probed_modes != NULL) + xf86DeleteMode(&output->probed_modes, output->probed_modes); + + output->probed_modes = (*output->funcs->get_modes) (output); + + /* Set the DDC properties to whatever first output has DDC information. + */ + if (output->MonInfo != NULL && !properties_set) { + xf86SetDDCproperties(pScrn, output->MonInfo); + properties_set = TRUE; + } + +#ifdef DEBUG_REPROBE + if (output->probed_modes != NULL) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Printing probed modes for output %s\n", + output->name); + } else { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "No remaining probed modes for output %s\n", + output->name); + } +#endif + for (mode = output->probed_modes; mode != NULL; mode = mode->next) + { + /* The code to choose the best mode per pipe later on will require + * VRefresh to be set. + */ + mode->VRefresh = xf86ModeVRefresh(mode); + xf86SetModeCrtc(mode, INTERLACE_HALVE_V); + +#ifdef DEBUG_REPROBE + xf86PrintModeline(pScrn->scrnIndex, mode); +#endif + } + } +} + + +/** + * Copy one of the output mode lists to the ScrnInfo record + */ + +/* XXX where does this function belong? Here? */ +void +xf86RandR12GetOriginalVirtualSize(ScrnInfoPtr pScrn, int *x, int *y); + +void +xf86SetScrnInfoModes (ScrnInfoPtr pScrn) +{ + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); + xf86OutputPtr output; + xf86CrtcPtr crtc; + DisplayModePtr last, mode; + int originalVirtualX, originalVirtualY; + + output = config->output[config->compat_output]; + if (!output->crtc) + { + int o; + + output = NULL; + for (o = 0; o < config->num_output; o++) + if (config->output[o]->crtc) + { + config->compat_output = o; + output = config->output[o]; + break; + } + /* no outputs are active, punt and leave things as they are */ + if (!output) + return; + } + crtc = output->crtc; + + /* Clear any existing modes from pScrn->modes */ + while (pScrn->modes != NULL) + xf86DeleteMode(&pScrn->modes, pScrn->modes); + + /* Set pScrn->modes to the mode list for the 'compat' output */ + pScrn->modes = xf86DuplicateModes(pScrn, output->probed_modes); + + xf86RandR12GetOriginalVirtualSize(pScrn, &originalVirtualX, &originalVirtualY); + + /* Disable modes in the XFree86 DDX list that are larger than the current + * virtual size. + */ + i830xf86ValidateModesSize(pScrn, pScrn->modes, + originalVirtualX, originalVirtualY, + pScrn->displayWidth); + + /* Strip out anything that we threw out for virtualX/Y. */ + i830xf86PruneInvalidModes(pScrn, &pScrn->modes, TRUE); + + for (mode = pScrn->modes; mode; mode = mode->next) + if (xf86ModesEqual (mode, &crtc->desiredMode)) + break; + + /* For some reason, pScrn->modes is circular, unlike the other mode lists. + * How great is that? + */ + for (last = pScrn->modes; last && last->next; last = last->next); + last->next = pScrn->modes; + pScrn->modes->prev = last; + if (mode) + while (pScrn->modes != mode) + pScrn->modes = pScrn->modes->next; + pScrn->currentMode = pScrn->modes; +} + +/** + * Construct default screen configuration + * + * Given auto-detected (and, eventually, configured) values, + * construct a usable configuration for the system + */ + +Bool +xf86InitialConfiguration (ScrnInfoPtr pScrn) +{ + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); + int o, c; + DisplayModePtr target_mode = NULL; + xf86CrtcPtr *crtcs; + DisplayModePtr *modes; + int width, height; + + xf86ProbeOutputModes (pScrn); + + if (pScrn->display->virtualX == 0) + { + /* + * Expand virtual size to cover potential mode switches + */ + xf86DefaultScreenLimits (pScrn, &width, &height); + + pScrn->display->virtualX = width; + pScrn->display->virtualY = height; + } + else + { + width = pScrn->display->virtualX; + height = pScrn->display->virtualY; + } + if (width > pScrn->virtualX) + pScrn->virtualX = width; + if (height > pScrn->virtualY) + pScrn->virtualY = height; + + crtcs = xnfcalloc (config->num_output, sizeof (xf86CrtcPtr)); + modes = xnfcalloc (config->num_output, sizeof (DisplayModePtr)); + + for (o = 0; o < config->num_output; o++) + modes[o] = NULL; + + /* + * Let outputs with preferred modes drive screen size + */ + for (o = 0; o < config->num_output; o++) + { + xf86OutputPtr output = config->output[o]; + + if (output->status != XF86OutputStatusDisconnected && + xf86OutputHasPreferredMode (output, width, height)) + { + target_mode = xf86DefaultMode (output, width, height); + if (target_mode) + { + modes[o] = target_mode; + config->compat_output = o; + break; + } + } + } + if (!target_mode) + { + for (o = 0; o < config->num_output; o++) + { + xf86OutputPtr output = config->output[o]; + if (output->status != XF86OutputStatusDisconnected) + { + target_mode = xf86DefaultMode (output, width, height); + if (target_mode) + { + modes[o] = target_mode; + config->compat_output = o; + break; + } + } + } + } + for (o = 0; o < config->num_output; o++) + { + xf86OutputPtr output = config->output[o]; + + if (output->status != XF86OutputStatusDisconnected && !modes[o]) + modes[o] = xf86ClosestMode (output, target_mode, width, height); + } + + if (!xf86PickCrtcs (pScrn, crtcs, modes, 0, width, height)) + { + xfree (crtcs); + xfree (modes); + return FALSE; + } + + /* XXX override xf86 common frame computation code */ + + pScrn->display->frameX0 = 0; + pScrn->display->frameY0 = 0; + + for (c = 0; c < config->num_crtc; c++) + { + xf86CrtcPtr crtc = config->crtc[c]; + + crtc->enabled = FALSE; + memset (&crtc->desiredMode, '\0', sizeof (crtc->desiredMode)); + } + + /* + * Set initial configuration + */ + for (o = 0; o < config->num_output; o++) + { + xf86OutputPtr output = config->output[o]; + DisplayModePtr mode = modes[o]; + xf86CrtcPtr crtc = crtcs[o]; + + if (mode && crtc) + { + crtc->desiredMode = *mode; + crtc->enabled = TRUE; + crtc->x = 0; + crtc->y = 0; + output->crtc = crtc; + /* XXX set position; for now, we clone */ + } + } + + /* Mirror output modes to pScrn mode list */ + xf86SetScrnInfoModes (pScrn); + + xfree (crtcs); + xfree (modes); + return TRUE; +} + +/** + * Set the DPMS power mode of all outputs and CRTCs. + * + * If the new mode is off, it will turn off outputs and then CRTCs. + * Otherwise, it will affect CRTCs before outputs. + */ +void +xf86DPMSSet(ScrnInfoPtr pScrn, int mode, int flags) +{ + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); + int i; + + if (mode == DPMSModeOff) { + for (i = 0; i < config->num_output; i++) { + xf86OutputPtr output = config->output[i]; + if (output->crtc != NULL) + (*output->funcs->dpms) (output, mode); + } + } + + for (i = 0; i < config->num_crtc; i++) { + xf86CrtcPtr crtc = config->crtc[i]; + if (crtc->enabled) + (*crtc->funcs->dpms) (crtc, mode); + } + + if (mode != DPMSModeOff) { + for (i = 0; i < config->num_output; i++) { + xf86OutputPtr output = config->output[i]; + if (output->crtc != NULL) + (*output->funcs->dpms) (output, mode); + } + } +} diff --git a/src/radeon_xf86Crtc.h b/src/radeon_xf86Crtc.h index 36311d0f..174647f2 100644 --- a/src/radeon_xf86Crtc.h +++ b/src/radeon_xf86Crtc.h @@ -24,23 +24,24 @@ #include <edid.h> #include "randrstr.h" -//#include "xf86Modes.h" - -enum detect_status { - OUTPUT_STATUS_CONNECTED, - OUTPUT_STATUS_DISCONNECTED, - OUTPUT_STATUS_UNKNOWN -}; +#include "radeon_xf86Modes.h" typedef struct _xf86Crtc xf86CrtcRec, *xf86CrtcPtr; +typedef struct _xf86Output xf86OutputRec, *xf86OutputPtr; + +typedef enum _xf86OutputStatus { + XF86OutputStatusConnected, + XF86OutputStatusDisconnected, + XF86OutputStatusUnknown, +} xf86OutputStatus; typedef struct _xf86CrtcFuncs { /** * Turns the crtc on/off, or sets intermediate power levels if available. * * Unsupported intermediate modes drop to the lower power setting. If the - * mode is DPMSModeOff, the crtc must be disabled, as the DPLL may be - * disabled afterwards. + * mode is DPMSModeOff, the crtc must be disabled sufficiently for it to + * be safe to call mode_set. */ void (*dpms)(xf86CrtcPtr crtc, @@ -58,6 +59,27 @@ typedef struct _xf86CrtcFuncs { void (*restore)(xf86CrtcPtr crtc); + + /** + * Callback to adjust the mode to be set in the CRTC. + * + * This allows a CRTC to adjust the clock or even the entire set of + * timings, which is used for panels with fixed timings or for + * buses with clock limitations. + */ + Bool + (*mode_fixup)(xf86CrtcPtr crtc, + DisplayModePtr mode, + DisplayModePtr adjusted_mode); + + /** + * Callback for setting up a video mode after fixups have been made. + */ + void + (*mode_set)(xf86CrtcPtr crtc, + DisplayModePtr mode, + DisplayModePtr adjusted_mode); + /** * Clean up driver-specific bits of the crtc */ @@ -133,8 +155,6 @@ struct _xf86Crtc { #endif }; -typedef struct _xf86Output xf86OutputRec, *xf86OutputPtr; - typedef struct _xf86OutputFuncs { /** * Turns the output on/off, or sets intermediate power levels if available. @@ -163,7 +183,7 @@ typedef struct _xf86OutputFuncs { * Callback for testing a video mode for a given output. * * This function should only check for cases where a mode can't be supported - * on the pipe specifically, and not represent generic CRTC limitations. + * on the output specifically, and not represent generic CRTC limitations. * * \return MODE_OK if the mode is valid, or another MODE_* otherwise. */ @@ -172,27 +192,33 @@ typedef struct _xf86OutputFuncs { DisplayModePtr pMode); /** - * Callback for setting up a video mode before any crtc/dpll changes. + * Callback to adjust the mode to be set in the CRTC. * - * \param pMode the mode that will be set, or NULL if the mode to be set is - * unknown (such as the restore path of VT switching). + * This allows an output to adjust the clock or even the entire set of + * timings, which is used for panels with fixed timings or for + * buses with clock limitations. */ - void - (*pre_set_mode)(xf86OutputPtr output, - DisplayModePtr pMode); + Bool + (*mode_fixup)(xf86OutputPtr output, + DisplayModePtr mode, + DisplayModePtr adjusted_mode); /** - * Callback for setting up a video mode after the DPLL update but before - * the plane is enabled. + * Callback for setting up a video mode after fixups have been made. + * + * This is only called while the output is disabled. The dpms callback + * must be all that's necessary for the output, to turn the output on + * after this function is called. */ void - (*post_set_mode)(xf86OutputPtr output, - DisplayModePtr pMode); + (*mode_set)(xf86OutputPtr output, + DisplayModePtr mode, + DisplayModePtr adjusted_mode); /** * Probe for a connected output, and return detect_status. */ - enum detect_status + xf86OutputStatus (*detect)(xf86OutputPtr output); /** @@ -217,12 +243,23 @@ struct _xf86Output { * Associated ScrnInfo */ ScrnInfoPtr scrn; + /** * Currently connected crtc (if any) * * If this output is not in use, this field will be NULL. */ xf86CrtcPtr crtc; + + /** + * Possible CRTCs for this output as a mask of crtc indices + */ + CARD32 possible_crtcs; + + /** + * Possible outputs to share the same CRTC as a mask of output indices + */ + CARD32 possible_clones; /** * List of available modes on this output. * @@ -231,9 +268,20 @@ struct _xf86Output { */ DisplayModePtr probed_modes; + /** + * Current connection status + * + * This indicates whether a monitor is known to be connected + * to this output or not, or whether there is no way to tell + */ + xf86OutputStatus status; + /** EDID monitor information */ xf86MonPtr MonInfo; + /** subpixel order */ + int subpixel_order; + /** Physical size of the currently attached output device. */ int mm_width, mm_height; @@ -259,18 +307,39 @@ struct _xf86Output { #endif }; -#define XF86_MAX_CRTC 4 -#define XF86_MAX_OUTPUT 16 - typedef struct _xf86CrtcConfig { - int num_output; - xf86OutputPtr output[XF86_MAX_OUTPUT]; - - int num_crtc; - xf86CrtcPtr crtc[XF86_MAX_CRTC]; + int num_output; + xf86OutputPtr *output; + /** + * compat_output is used whenever we deal + * with legacy code that only understands a single + * output. pScrn->modes will be loaded from this output, + * adjust frame will whack this output, etc. + */ + int compat_output; + + int num_crtc; + xf86CrtcPtr *crtc; + + int minWidth, minHeight; + int maxWidth, maxHeight; } xf86CrtcConfigRec, *xf86CrtcConfigPtr; -#define XF86_CRTC_CONFIG_PTR(p) ((xf86CrtcConfigPtr) ((p)->driverPrivate)) +extern int xf86CrtcConfigPrivateIndex; + +#define XF86_CRTC_CONFIG_PTR(p) ((xf86CrtcConfigPtr) ((p)->privates[xf86CrtcConfigPrivateIndex].ptr)) + +/* + * Initialize xf86CrtcConfig structure + */ + +void +xf86CrtcConfigInit (ScrnInfoPtr scrn); + +void +xf86CrtcSetSizeRange (ScrnInfoPtr scrn, + int minWidth, int minHeight, + int maxWidth, int maxHeight); /* * Crtc functions @@ -311,6 +380,21 @@ xf86OutputCreate (ScrnInfoPtr scrn, const char *name); void +xf86OutputRename (xf86OutputPtr output, const char *name); + +void xf86OutputDestroy (xf86OutputPtr output); +void +xf86ProbeOutputModes (ScrnInfoPtr pScrn); + +void +xf86SetScrnInfoModes (ScrnInfoPtr pScrn); + +Bool +xf86InitialConfiguration (ScrnInfoPtr pScrn); + +void +xf86DPMSSet(ScrnInfoPtr pScrn, int PowerManagementMode, int flags); + #endif /* _XF86CRTC_H_ */ |