diff options
Diffstat (limited to 'src/amd_gx_randr.c')
-rw-r--r-- | src/amd_gx_randr.c | 331 |
1 files changed, 331 insertions, 0 deletions
diff --git a/src/amd_gx_randr.c b/src/amd_gx_randr.c new file mode 100644 index 0000000..a4fa743 --- /dev/null +++ b/src/amd_gx_randr.c @@ -0,0 +1,331 @@ +/* Originally derived from the Intel example + * Copyright (C) 2002 Keith Packard, member of The XFree86 Project, Inc. + + * Copyright (c) 2006 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Neither the name of the Advanced Micro Devices, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + */ + +#include "xf86.h" +#include "os.h" +#include "mibank.h" +#include "globals.h" +#include "xf86.h" +#include "xf86Priv.h" +#include "xf86DDC.h" +#include "mipointer.h" +#include "windowstr.h" +#include <X11/extensions/randr.h> +#include <randrstr.h> + +#include "amd.h" + +static int GXRandRIndex; +static int GXRandRGeneration; + +typedef struct _GXRandRInfo +{ + int virtualX; + int virtualY; + int mmWidth; + int mmHeight; + int maxX; + int maxY; + Rotation rotation; /* current mode */ + Rotation supported_rotations; /* driver supported */ +} XF86RandRInfoRec, *XF86RandRInfoPtr; + +#define XF86RANDRINFO(p) ((XF86RandRInfoPtr) (p)->devPrivates[GXRandRIndex].ptr) + +static int +GXRandRModeRefresh(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 +GXRandRGetInfo(ScreenPtr pScreen, Rotation * rotations) +{ + RRScreenSizePtr pSize; + ScrnInfoPtr pScrni = XF86SCRNINFO(pScreen); + XF86RandRInfoPtr pRandr = XF86RANDRINFO(pScreen); + DisplayModePtr mode; + int refresh0 = 60; + int maxX = 0, maxY = 0; + + *rotations = pRandr->supported_rotations; + + if (pRandr->virtualX == -1 || pRandr->virtualY == -1) { + pRandr->virtualX = pScrni->virtualX; + pRandr->virtualY = pScrni->virtualY; + } + + for (mode = pScrni->modes;; mode = mode->next) { + int refresh = GXRandRModeRefresh(mode); + + if (pRandr->maxX == 0 || pRandr->maxY == 0) { + if (maxX < mode->HDisplay) + maxX = mode->HDisplay; + if (maxY < mode->VDisplay) + maxY = mode->VDisplay; + } + + if (mode == pScrni->modes) + refresh0 = refresh; + + pSize = RRRegisterSize(pScreen, + mode->HDisplay, mode->VDisplay, + pRandr->mmWidth, pRandr->mmHeight); + if (!pSize) + return FALSE; + + RRRegisterRate(pScreen, pSize, refresh); + + if (mode == pScrni->currentMode && + mode->HDisplay == pScrni->virtualX + && mode->VDisplay == pScrni->virtualY) + RRSetCurrentConfig(pScreen, pRandr->rotation, refresh, pSize); + if (mode->next == pScrni->modes) + break; + } + + if (pRandr->maxX == 0 || pRandr->maxY == 0) { + pRandr->maxX = maxX; + pRandr->maxY = maxY; + } + + if (pScrni->currentMode->HDisplay != pScrni->virtualX || + pScrni->currentMode->VDisplay != pScrni->virtualY) { + + mode = pScrni->modes; + pSize = RRRegisterSize(pScreen, + pRandr->virtualX, pRandr->virtualY, + pRandr->mmWidth, pRandr->mmHeight); + if (!pSize) + return FALSE; + + RRRegisterRate(pScreen, pSize, refresh0); + if (pScrni->virtualX == pRandr->virtualX && + pScrni->virtualY == pRandr->virtualY) { + RRSetCurrentConfig(pScreen, pRandr->rotation, refresh0, pSize); + } + } + + return TRUE; +} + +static Bool +GXRandRSetMode(ScreenPtr pScreen, + DisplayModePtr mode, Bool useVirtual, int mmWidth, int mmHeight) +{ + ScrnInfoPtr pScrni = XF86SCRNINFO(pScreen); + XF86RandRInfoPtr pRandr = 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) + (*pScrni->EnableDisableFBAccess) (pScreen->myNum, FALSE); + + if (useVirtual) { + pScrni->virtualX = pRandr->virtualX; + pScrni->virtualY = pRandr->virtualY; + } else { + pScrni->virtualX = mode->HDisplay; + pScrni->virtualY = mode->VDisplay; + } + + if (pRandr->rotation & (RR_Rotate_90 | RR_Rotate_270)) { + pScreen->width = pScrni->virtualY; + pScreen->height = pScrni->virtualX; + pScreen->mmWidth = mmHeight; + pScreen->mmHeight = mmWidth; + } else { + pScreen->width = pScrni->virtualX; + pScreen->height = pScrni->virtualY; + pScreen->mmWidth = mmWidth; + pScreen->mmHeight = mmHeight; + } + + if (pScrni->currentMode == mode) { + currentMode = pScrni->currentMode; + pScrni->currentMode = NULL; + } + + if (!xf86SwitchMode(pScreen, mode)) { + ret = FALSE; + pScrni->virtualX = pScreen->width = oldWidth; + pScrni->virtualY = pScreen->height = oldHeight; + pScreen->mmWidth = oldmmWidth; + pScreen->mmHeight = oldmmHeight; + pScrni->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) + pScrni->pixmapPrivate = pspix->devPrivate; + + xf86ReconfigureLayout(); + + xf86SetViewport(pScreen, pScreen->width, pScreen->height); + xf86SetViewport(pScreen, 0, 0); + + if (pRoot) + (*pScrni->EnableDisableFBAccess) (pScreen->myNum, TRUE); + + return ret; +} + +Bool +GXRandRSetConfig(ScreenPtr pScreen, Rotation rotation, + int rate, RRScreenSizePtr pSize) +{ + ScrnInfoPtr pScrni = XF86SCRNINFO(pScreen); + XF86RandRInfoPtr pRandr = XF86RANDRINFO(pScreen); + + DisplayModePtr mode; + int px, py; + Bool useVirtual = FALSE; + int maxX = 0, maxY = 0; + Rotation oldRotation = pRandr->rotation; + + pRandr->rotation = rotation; + + if (pRandr->virtualX == -1 || pRandr->virtualY == -1) { + pRandr->virtualX = pScrni->virtualX; + pRandr->virtualY = pScrni->virtualY; + } + + miPointerPosition(&px, &py); + + for (mode = pScrni->modes;; mode = mode->next) { + if (pRandr->maxX == 0 || pRandr->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 || GXRandRModeRefresh(mode) == rate)) + break; + if (mode->next == pScrni->modes) { + if (pSize->width == pRandr->virtualX && + pSize->height == pRandr->virtualY) { + mode = pScrni->modes; + useVirtual = TRUE; + break; + } + if (pRandr->maxX == 0 || pRandr->maxY == 0) { + pRandr->maxX = maxX; + pRandr->maxY = maxY; + } + return FALSE; + } + } + + if (pRandr->maxX == 0 || pRandr->maxY == 0) { + pRandr->maxX = maxX; + pRandr->maxY = maxY; + } + + if (!GXRandRSetMode(pScreen, mode, useVirtual, pSize->mmWidth, + pSize->mmHeight)) { + pRandr->rotation = oldRotation; + return FALSE; + } + + 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 +GXGetRotation(ScreenPtr pScreen) +{ + XF86RandRInfoPtr pRandr = XF86RANDRINFO(pScreen); + + return pRandr->rotation; +} + +Bool +GXRandRInit(ScreenPtr pScreen, int rotation) +{ + XF86RandRInfoPtr pRandr; + rrScrPrivPtr rp; + + if (GXRandRGeneration != serverGeneration) { + GXRandRIndex = AllocateScreenPrivateIndex(); + GXRandRGeneration = serverGeneration; + } + + pRandr = xcalloc(sizeof(XF86RandRInfoRec), 1); + if (pRandr == NULL) + return FALSE; + + if (!RRScreenInit(pScreen)) { + xfree(pRandr); + return FALSE; + } + + rp = rrGetScrPriv(pScreen); + rp->rrGetInfo = GXRandRGetInfo; + rp->rrSetConfig = GXRandRSetConfig; + + pRandr->virtualX = -1; + pRandr->virtualY = -1; + + pRandr->mmWidth = pScreen->mmWidth; + pRandr->mmHeight = pScreen->mmHeight; + + pRandr->rotation = RR_Rotate_0; + pRandr->supported_rotations = rotation; + pRandr->maxX = pRandr->maxY = 0; + + pScreen->devPrivates[GXRandRIndex].ptr = pRandr; + return TRUE; +} |