summaryrefslogtreecommitdiff
path: root/src/radeon_exa_funcs.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/radeon_exa_funcs.c')
-rw-r--r--src/radeon_exa_funcs.c408
1 files changed, 408 insertions, 0 deletions
diff --git a/src/radeon_exa_funcs.c b/src/radeon_exa_funcs.c
new file mode 100644
index 00000000..b6012839
--- /dev/null
+++ b/src/radeon_exa_funcs.c
@@ -0,0 +1,408 @@
+/*
+ * Copyright 2005 Eric Anholt
+ * Copyright 2005 Benjamin Herrenschmidt
+ * All Rights Reserved.
+ *
+ * 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 (including the next
+ * paragraph) 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.
+ *
+ * Authors:
+ * Eric Anholt <anholt@FreeBSD.org>
+ * Zack Rusin <zrusin@trolltech.com>
+ * Benjamin Herrenschmidt <benh@kernel.crashing.org>
+ *
+ */
+
+#if defined(ACCEL_MMIO) && defined(ACCEL_CP)
+#error Cannot define both MMIO and CP acceleration!
+#endif
+
+#if !defined(UNIXCPP) || defined(ANSICPP)
+#define FUNC_NAME_CAT(prefix,suffix) prefix##suffix
+#else
+#define FUNC_NAME_CAT(prefix,suffix) prefix/**/suffix
+#endif
+
+#ifdef ACCEL_MMIO
+#define FUNC_NAME(prefix) FUNC_NAME_CAT(prefix,MMIO)
+#else
+#ifdef ACCEL_CP
+#define FUNC_NAME(prefix) FUNC_NAME_CAT(prefix,CP)
+#else
+#error No accel type defined!
+#endif
+#endif
+
+#include "radeon.h"
+#include "atidri.h"
+
+#include "exa.h"
+
+#include "fbdevhw.h"
+
+static void
+FUNC_NAME(RADEONSync)(ScreenPtr pScreen, int marker)
+{
+ TRACE;
+
+ FUNC_NAME(RADEONWaitForIdle)(xf86Screens[pScreen->myNum]);
+}
+
+static Bool
+FUNC_NAME(RADEONPrepareSolid)(PixmapPtr pPix, int alu, Pixel pm, Pixel fg)
+{
+ RINFO_FROM_SCREEN(pPix->drawable.pScreen);
+ CARD32 datatype, dst_pitch_offset;
+ ACCEL_PREAMBLE();
+
+ TRACE;
+
+ if (pPix->drawable.bitsPerPixel == 24)
+ RADEON_FALLBACK(("24bpp unsupported\n"));
+ if (!RADEONGetDatatypeBpp(pPix->drawable.bitsPerPixel, &datatype))
+ RADEON_FALLBACK(("RADEONGetDatatypeBpp failed\n"));
+ if (!RADEONGetPixmapOffsetPitch(pPix, &dst_pitch_offset))
+ RADEON_FALLBACK(("RADEONGetPixmapOffsetPitch failed\n"));
+
+ RADEON_SWITCH_TO_2D();
+
+ BEGIN_ACCEL(5);
+ OUT_ACCEL_REG(RADEON_DP_GUI_MASTER_CNTL,
+ RADEON_GMC_DST_PITCH_OFFSET_CNTL |
+ RADEON_GMC_BRUSH_SOLID_COLOR |
+ (datatype << 8) |
+ RADEON_GMC_SRC_DATATYPE_COLOR |
+ RADEON_ROP[alu].pattern |
+ RADEON_GMC_CLR_CMP_CNTL_DIS);
+ OUT_ACCEL_REG(RADEON_DP_BRUSH_FRGD_CLR, fg);
+ OUT_ACCEL_REG(RADEON_DP_WRITE_MASK, pm);
+ OUT_ACCEL_REG(RADEON_DP_CNTL,
+ (RADEON_DST_X_LEFT_TO_RIGHT | RADEON_DST_Y_TOP_TO_BOTTOM));
+ OUT_ACCEL_REG(RADEON_DST_PITCH_OFFSET, dst_pitch_offset);
+ FINISH_ACCEL();
+
+ return TRUE;
+}
+
+
+static void
+FUNC_NAME(RADEONSolid)(PixmapPtr pPix, int x1, int y1, int x2, int y2)
+{
+
+ RINFO_FROM_SCREEN(pPix->drawable.pScreen);
+ ACCEL_PREAMBLE();
+
+ TRACE;
+
+ BEGIN_ACCEL(2);
+ OUT_ACCEL_REG(RADEON_DST_Y_X, (y1 << 16) | x1);
+ OUT_ACCEL_REG(RADEON_DST_HEIGHT_WIDTH, ((y2 - y1) << 16) | (x2 - x1));
+ FINISH_ACCEL();
+}
+
+static void
+FUNC_NAME(RADEONDoneSolid)(PixmapPtr pPix)
+{
+ TRACE;
+}
+
+static Bool
+FUNC_NAME(RADEONPrepareCopy)(PixmapPtr pSrc, PixmapPtr pDst,
+ int xdir, int ydir,
+ int rop,
+ Pixel planemask)
+{
+ RINFO_FROM_SCREEN(pDst->drawable.pScreen);
+ CARD32 datatype, src_pitch_offset, dst_pitch_offset;
+ ACCEL_PREAMBLE();
+
+ TRACE;
+
+ info->xdir = xdir;
+ info->ydir = ydir;
+
+ if (pDst->drawable.bitsPerPixel == 24)
+ RADEON_FALLBACK(("24bpp unsupported"));
+ if (!RADEONGetDatatypeBpp(pDst->drawable.bitsPerPixel, &datatype))
+ RADEON_FALLBACK(("RADEONGetDatatypeBpp failed\n"));
+ if (!RADEONGetPixmapOffsetPitch(pSrc, &src_pitch_offset))
+ RADEON_FALLBACK(("RADEONGetPixmapOffsetPitch source failed\n"));
+ if (!RADEONGetPixmapOffsetPitch(pDst, &dst_pitch_offset))
+ RADEON_FALLBACK(("RADEONGetPixmapOffsetPitch dest failed\n"));
+
+ RADEON_SWITCH_TO_2D();
+
+ BEGIN_ACCEL(5);
+ OUT_ACCEL_REG(RADEON_DP_GUI_MASTER_CNTL,
+ RADEON_GMC_DST_PITCH_OFFSET_CNTL |
+ RADEON_GMC_SRC_PITCH_OFFSET_CNTL |
+ RADEON_GMC_BRUSH_NONE |
+ (datatype << 8) |
+ RADEON_GMC_SRC_DATATYPE_COLOR |
+ RADEON_ROP[rop].rop |
+ RADEON_DP_SRC_SOURCE_MEMORY |
+ RADEON_GMC_CLR_CMP_CNTL_DIS);
+ OUT_ACCEL_REG(RADEON_DP_WRITE_MASK, planemask);
+ OUT_ACCEL_REG(RADEON_DP_CNTL,
+ ((xdir >= 0 ? RADEON_DST_X_LEFT_TO_RIGHT : 0) |
+ (ydir >= 0 ? RADEON_DST_Y_TOP_TO_BOTTOM : 0)));
+ OUT_ACCEL_REG(RADEON_DST_PITCH_OFFSET, dst_pitch_offset);
+ OUT_ACCEL_REG(RADEON_SRC_PITCH_OFFSET, src_pitch_offset);
+ FINISH_ACCEL();
+
+ return TRUE;
+}
+
+static void
+FUNC_NAME(RADEONCopy)(PixmapPtr pDst,
+ int srcX, int srcY,
+ int dstX, int dstY,
+ int w, int h)
+{
+
+ RINFO_FROM_SCREEN(pDst->drawable.pScreen);
+ ACCEL_PREAMBLE();
+
+ TRACE;
+
+ if (info->xdir < 0) {
+ srcX += w - 1;
+ dstX += w - 1;
+ }
+ if (info->ydir < 0) {
+ srcY += h - 1;
+ dstY += h - 1;
+ }
+
+ BEGIN_ACCEL(3);
+
+ OUT_ACCEL_REG(RADEON_SRC_Y_X, (srcY << 16) | srcX);
+ OUT_ACCEL_REG(RADEON_DST_Y_X, (dstY << 16) | dstX);
+ OUT_ACCEL_REG(RADEON_DST_HEIGHT_WIDTH, (h << 16) | w);
+
+ FINISH_ACCEL();
+}
+
+static void
+FUNC_NAME(RADEONDoneCopy)(PixmapPtr pDst)
+{
+ TRACE;
+}
+
+static Bool
+FUNC_NAME(RADEONUploadToScreen)(PixmapPtr pDst, char *src, int src_pitch)
+{
+#if X_BYTE_ORDER == X_BIG_ENDIAN || defined(ACCEL_CP)
+ RINFO_FROM_SCREEN(pDst->drawable.pScreen);
+#endif
+ CARD8 *dst = pDst->devPrivate.ptr;
+ unsigned int dst_pitch = exaGetPixmapPitch(pDst);
+ unsigned int w = pDst->drawable.width;
+ unsigned int h = pDst->drawable.height;
+ unsigned int bpp = pDst->drawable.bitsPerPixel;
+#ifdef ACCEL_CP
+ unsigned int hpass;
+ CARD32 buf_pitch;
+#endif
+#if X_BYTE_ORDER == X_BIG_ENDIAN
+ unsigned char *RADEONMMIO = info->MMIO;
+ unsigned int swapper = info->ModeReg.surface_cntl &
+ ~(RADEON_NONSURF_AP0_SWP_32BPP | RADEON_NONSURF_AP1_SWP_32BPP |
+ RADEON_NONSURF_AP0_SWP_16BPP | RADEON_NONSURF_AP1_SWP_16BPP);
+#endif
+
+ TRACE;
+
+#ifdef ACCEL_CP
+ if (info->directRenderingEnabled) {
+ CARD8 *buf;
+ int cpp = bpp / 8;
+ ACCEL_PREAMBLE();
+
+ RADEON_SWITCH_TO_2D();
+ while ((buf = RADEONHostDataBlit(pScrn,
+ cpp, w, dst_pitch, &buf_pitch,
+ &dst, &h, &hpass)) != 0) {
+ RADEONHostDataBlitCopyPass(pScrn, cpp, buf, (unsigned char *)src,
+ hpass, buf_pitch, src_pitch);
+ src += hpass * src_pitch;
+ }
+
+ exaMarkSync(pDst->drawable.pScreen);
+ return TRUE;
+ }
+#endif
+
+ /* Do we need that sync here ? probably not .... */
+ exaWaitSync(pDst->drawable.pScreen);
+
+#if X_BYTE_ORDER == X_BIG_ENDIAN
+ switch(bpp) {
+ case 15:
+ case 16:
+ swapper |= RADEON_NONSURF_AP0_SWP_16BPP
+ | RADEON_NONSURF_AP1_SWP_16BPP;
+ break;
+ case 24:
+ case 32:
+ swapper |= RADEON_NONSURF_AP0_SWP_32BPP
+ | RADEON_NONSURF_AP1_SWP_32BPP;
+ break;
+ }
+ OUTREG(RADEON_SURFACE_CNTL, swapper);
+#endif
+ w *= bpp / 8;
+
+ while (h--) {
+ memcpy(dst, src, w);
+ src += src_pitch;
+ dst += dst_pitch;
+ }
+
+#if X_BYTE_ORDER == X_BIG_ENDIAN
+ /* restore byte swapping */
+ OUTREG(RADEON_SURFACE_CNTL, info->ModeReg.surface_cntl);
+#endif
+
+ return TRUE;
+}
+
+static Bool
+FUNC_NAME(RADEONDownloadFromScreen)(PixmapPtr pSrc, int x, int y, int w, int h,
+ char *dst, int dst_pitch)
+{
+#if X_BYTE_ORDER == X_BIG_ENDIAN
+ RINFO_FROM_SCREEN(pSrc->drawable.pScreen);
+ unsigned char *RADEONMMIO = info->MMIO;
+ unsigned int swapper = info->ModeReg.surface_cntl &
+ ~(RADEON_NONSURF_AP0_SWP_32BPP | RADEON_NONSURF_AP1_SWP_32BPP |
+ RADEON_NONSURF_AP0_SWP_16BPP | RADEON_NONSURF_AP1_SWP_16BPP);
+#endif
+ unsigned char *src = pSrc->devPrivate.ptr;
+ int src_pitch = exaGetPixmapPitch(pSrc);
+ int bpp = pSrc->drawable.bitsPerPixel;
+
+ TRACE;
+
+ /*
+ * This is currently done without DMA until I have ironed out the
+ * various endian issues with R300 among others
+ */
+ exaWaitSync(pSrc->drawable.pScreen);
+
+#if X_BYTE_ORDER == X_BIG_ENDIAN
+ switch(bpp) {
+ case 15:
+ case 16:
+ swapper |= RADEON_NONSURF_AP0_SWP_16BPP
+ | RADEON_NONSURF_AP1_SWP_16BPP;
+ break;
+ case 24:
+ case 32:
+ swapper |= RADEON_NONSURF_AP0_SWP_32BPP
+ | RADEON_NONSURF_AP1_SWP_32BPP;
+ break;
+ }
+ OUTREG(RADEON_SURFACE_CNTL, swapper);
+#endif
+
+ src += (x * bpp / 8) + (y * src_pitch);
+ w *= bpp / 8;
+
+ while (h--) {
+ memcpy(dst, src, w);
+ src += src_pitch;
+ dst += dst_pitch;
+ }
+
+#if X_BYTE_ORDER == X_BIG_ENDIAN
+ /* restore byte swapping */
+ OUTREG(RADEON_SURFACE_CNTL, info->ModeReg.surface_cntl);
+#endif
+
+ return TRUE;
+}
+
+Bool FUNC_NAME(RADEONDrawInit)(ScreenPtr pScreen)
+{
+ RINFO_FROM_SCREEN(pScreen);
+
+ memset(&info->exa.accel, 0, sizeof(ExaAccelInfoRec));
+
+ info->exa.accel.PrepareSolid = FUNC_NAME(RADEONPrepareSolid);
+ info->exa.accel.Solid = FUNC_NAME(RADEONSolid);
+ info->exa.accel.DoneSolid = FUNC_NAME(RADEONDoneSolid);
+
+ info->exa.accel.PrepareCopy = FUNC_NAME(RADEONPrepareCopy);
+ info->exa.accel.Copy = FUNC_NAME(RADEONCopy);
+ info->exa.accel.DoneCopy = FUNC_NAME(RADEONDoneCopy);
+
+ info->exa.accel.WaitMarker = FUNC_NAME(RADEONSync);
+ info->exa.accel.UploadToScreen = FUNC_NAME(RADEONUploadToScreen);
+ info->exa.accel.DownloadFromScreen = FUNC_NAME(RADEONDownloadFromScreen);
+
+#if X_BYTE_ORDER == X_BIG_ENDIAN
+ info->exa.accel.PrepareAccess = RADEONPrepareAccess;
+ info->exa.accel.FinishAccess = RADEONFinishAccess;
+#endif /* X_BYTE_ORDER == X_BIG_ENDIAN */
+
+ info->exa.card.flags = EXA_OFFSCREEN_PIXMAPS;
+ info->exa.card.pixmapOffsetAlign = RADEON_BUFFER_ALIGN + 1;
+ info->exa.card.pixmapPitchAlign = 64;
+
+ info->exa.card.maxX = 2047;
+ info->exa.card.maxY = 2047;
+
+ if (info->RenderAccel) {
+ if (info->ChipFamily >= CHIP_FAMILY_R300) {
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Render acceleration "
+ "unsupported on R300 type cards and newer.\n");
+ } else if ((info->ChipFamily == CHIP_FAMILY_RV250) ||
+ (info->ChipFamily == CHIP_FAMILY_RV280) ||
+ (info->ChipFamily == CHIP_FAMILY_RS300) ||
+ (info->ChipFamily == CHIP_FAMILY_R200)) {
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Render acceleration "
+ "enabled for R200 type cards.\n");
+ info->exa.accel.CheckComposite = R200CheckComposite;
+ info->exa.accel.PrepareComposite =
+ FUNC_NAME(R200PrepareComposite);
+ info->exa.accel.Composite = FUNC_NAME(RadeonComposite);
+ info->exa.accel.DoneComposite = RadeonDoneComposite;
+ } else {
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Render acceleration "
+ "enabled for R100 type cards.\n");
+ info->exa.accel.CheckComposite = R100CheckComposite;
+ info->exa.accel.PrepareComposite =
+ FUNC_NAME(R100PrepareComposite);
+ info->exa.accel.Composite = FUNC_NAME(RadeonComposite);
+ info->exa.accel.DoneComposite = RadeonDoneComposite;
+ }
+ }
+
+ RADEONEngineInit(pScrn);
+
+ if (!exaDriverInit(pScreen, &info->exa)) {
+ return FALSE;
+ }
+ exaMarkSync(pScreen);
+
+ return TRUE;
+}
+
+#undef FUNC_NAME