summaryrefslogtreecommitdiff
path: root/src/amd_gx_rotate.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/amd_gx_rotate.c')
-rw-r--r--src/amd_gx_rotate.c190
1 files changed, 190 insertions, 0 deletions
diff --git a/src/amd_gx_rotate.c b/src/amd_gx_rotate.c
new file mode 100644
index 0000000..3e464ca
--- /dev/null
+++ b/src/amd_gx_rotate.c
@@ -0,0 +1,190 @@
+/* Copyrightg (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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "xf86.h"
+#include "shadow.h"
+#include "amd.h"
+
+static void *
+GXWindowLinear(ScreenPtr pScreen, CARD32 row, CARD32 offset, int mode,
+ CARD32 * size, void *closure)
+{
+ ScrnInfoPtr pScrni = xf86Screens[pScreen->myNum];
+ GeodeRec *pGeode = GEODEPTR(pScrni);
+
+ *size = pGeode->displayPitch;
+
+ return (pGeode->FBBase + pGeode->displayOffset) +
+ row * pGeode->displayPitch + offset;
+}
+
+static void
+GXUpdate(ScreenPtr pScreen, shadowBufPtr pBuf)
+{
+ ScrnInfoPtr pScrni = xf86Screens[pScreen->myNum];
+ GeodeRec *pGeode = GEODEPTR(pScrni);
+ int rotate = pGeode->rotation;
+
+ switch (rotate) {
+ case RR_Rotate_90:
+
+ if (pScrni->bitsPerPixel == 8)
+ shadowUpdateRotate8_90(pScreen, pBuf);
+ else if (pScrni->bitsPerPixel == 16)
+ shadowUpdateRotate16_90(pScreen, pBuf);
+ else
+ shadowUpdateRotate32_90(pScreen, pBuf);
+
+ break;
+
+ case RR_Rotate_180:
+
+ if (pScrni->bitsPerPixel == 8)
+ shadowUpdateRotate8_180(pScreen, pBuf);
+ else if (pScrni->bitsPerPixel == 16)
+ shadowUpdateRotate16_180(pScreen, pBuf);
+ else
+ shadowUpdateRotate32_180(pScreen, pBuf);
+
+ break;
+
+ case RR_Rotate_270:
+ if (pScrni->bitsPerPixel == 8)
+ shadowUpdateRotate8_270(pScreen, pBuf);
+ else if (pScrni->bitsPerPixel == 16)
+ shadowUpdateRotate16_270(pScreen, pBuf);
+ else
+ shadowUpdateRotate32_270(pScreen, pBuf);
+
+ break;
+ }
+}
+
+Bool
+GXRotate(ScrnInfoPtr pScrni, DisplayModePtr mode)
+{
+ GeodeRec *pGeode = GEODEPTR(pScrni);
+ Rotation curr = pGeode->rotation;
+ unsigned int curdw = pScrni->displayWidth;
+ PixmapPtr pPixmap;
+ BOOL ret;
+
+ pPixmap = pScrni->pScreen->GetScreenPixmap(pScrni->pScreen);
+ pGeode->rotation = GXGetRotation(pScrni->pScreen);
+
+ /* Leave if we have nothing to do */
+
+ if (pGeode->rotation == curr && pGeode->curMode == mode) {
+ return TRUE;
+ }
+
+ shadowRemove(pScrni->pScreen, NULL);
+
+ switch (pGeode->rotation) {
+ case RR_Rotate_0:
+ ErrorF("Rotate to 0 degrees\n");
+ pScrni->displayWidth = pGeode->displayWidth;
+ pGeode->Pitch = pGeode->displayPitch;
+ break;
+
+ case RR_Rotate_90:
+ ErrorF("Rotate to 90 degrees\n");
+ pScrni->displayWidth = pScrni->pScreen->width;
+ break;
+
+ case RR_Rotate_180:
+ ErrorF("Rotate to 180 degrees\n");
+ pScrni->displayWidth = pGeode->displayWidth;
+ break;
+
+ case RR_Rotate_270:
+ ErrorF("Rotate to 270 degrees\n");
+ pScrni->displayWidth = pScrni->pScreen->width;
+ break;
+ }
+
+ if (pGeode->rotation != RR_Rotate_0) {
+
+ ret =
+ shadowAdd(pScrni->pScreen, pPixmap, GXUpdate, GXWindowLinear,
+ pGeode->rotation, NULL);
+
+ /* XXX - FIXME - bail gracefully */
+
+ if (!ret)
+ ErrorF("shadowAdd failed\n");
+ }
+
+ if (pGeode->rotation == RR_Rotate_0)
+ pScrni->fbOffset = pGeode->displayOffset;
+ else
+ pScrni->fbOffset = pGeode->shadowOffset;
+
+ pScrni->pScreen->ModifyPixmapHeader(pPixmap,
+ pScrni->pScreen->width,
+ pScrni->pScreen->height,
+ pScrni->pScreen->rootDepth,
+ pScrni->bitsPerPixel,
+ PixmapBytePad(pScrni->displayWidth, pScrni->pScreen->rootDepth),
+ (pointer) (pGeode->FBBase + pScrni->fbOffset));
+
+ /* Don't use XAA pixmap cache or offscreen pixmaps when rotated */
+
+ if (pGeode->AccelInfoRec) {
+ if (pGeode->rotation == RR_Rotate_0) {
+ pGeode->AccelInfoRec->Flags = LINEAR_FRAMEBUFFER | OFFSCREEN_PIXMAPS | PIXMAP_CACHE;
+ pGeode->AccelInfoRec->UsingPixmapCache = TRUE;
+ pGeode->AccelInfoRec->maxOffPixWidth = 0;
+ pGeode->AccelInfoRec->maxOffPixHeight = 0;
+ }
+ else {
+ pGeode->AccelInfoRec->Flags = LINEAR_FRAMEBUFFER;
+ pGeode->AccelInfoRec->UsingPixmapCache = FALSE;
+ pGeode->AccelInfoRec->maxOffPixWidth = 1;
+ pGeode->AccelInfoRec->maxOffPixHeight = 1;
+ }
+ }
+
+ return TRUE;
+
+error:
+ /* Restore the old rotation */
+ pScrni->displayWidth = curdw;
+
+ if (curr & (RR_Rotate_0 | RR_Rotate_180)) {
+ pScrni->pScreen->width = pScrni->virtualX;
+ pScrni->pScreen->height = pScrni->virtualY;
+ } else {
+ pScrni->pScreen->width = pScrni->virtualY;
+ pScrni->pScreen->height = pScrni->virtualX;
+ }
+
+ pGeode->rotation = curr;
+ return FALSE;
+}