From f025c7333aeb06674021bbdfc92061385bc9ba80 Mon Sep 17 00:00:00 2001 From: Connor Behan Date: Sun, 22 Apr 2012 23:38:50 -0700 Subject: [PATCH] Add EXA support This should allow the r128 driver to continue having 2D acceleration when XAA is removed. Implemented hooks are Solid, Copy and Composite. They appear to pass all rendercheck tests, except the gradient test which XAA also fails. Tested on multiple color depths, with and without DRI, with and without the composite extension. Hardware cursor and Xvideo are supported but page flipping may need work later on. Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=47866 --- configure.ac | 38 ++ src/Makefile.am | 6 +- src/r128.h | 35 ++ src/r128_accel.c | 67 ++- src/r128_cursor.c | 52 ++- src/r128_dri.c | 59 ++- src/r128_driver.c | 370 ++++++++++------ src/r128_exa.c | 1246 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/r128_reg.h | 27 ++ src/r128_video.c | 114 +++-- 10 files changed, 1838 insertions(+), 176 deletions(-) create mode 100644 src/r128_exa.c diff --git a/configure.ac b/configure.ac index ecbe3d3..3183946 100644 --- a/configure.ac +++ b/configure.ac @@ -63,6 +63,11 @@ AC_ARG_ENABLE(dri, AS_HELP_STRING([--disable-dri], [DRI="$enableval"], [DRI=auto]) +AC_ARG_ENABLE(exa, AS_HELP_STRING([--disable-exa], + [Disable EXA support [[default=enabled]]]), + [EXA="$enableval"], + [EXA=yes]) + # Store the list of server defined optional extensions in REQUIRED_MODULES XORG_DRIVER_CHECK_EXT(RANDR, randrproto) XORG_DRIVER_CHECK_EXT(RENDER, renderproto) @@ -112,6 +117,39 @@ fi SAVE_CPPFLAGS="$CPPFLAGS" CPPFLAGS="$CPPFLAGS $XORG_CFLAGS" +# Properly handle EXA. +AC_MSG_CHECKING([whether to enable EXA support]) +if test "x$EXA" = xyes; then + AC_MSG_RESULT(yes) + + SAVE_CPPFLAGS="$CPPFLAGS" + CPPFLAGS="$CPPFLAGS $XORG_CFLAGS" + AC_CHECK_HEADER(exa.h, + [have_exa_h="yes"], [have_exa_h="no"]) + CPPFLAGS="$SAVE_CPPFLAGS" +else + AC_MSG_RESULT(no) +fi + +SAVE_CPPFLAGS="$CPPFLAGS" +CPPFLAGS="$CPPFLAGS $XORG_CFLAGS" +if test "x$have_exa_h" = xyes; then + AC_MSG_CHECKING([whether EXA version is at least 2.0.0]) + AC_PREPROC_IFELSE([AC_LANG_PROGRAM([[ +#include "exa.h" +#if EXA_VERSION_MAJOR < 2 +#error OLD EXA! +#endif + ]])], + [USE_EXA=yes], + [USE_EXA=no]) + AC_MSG_RESULT($USE_EXA) + + if test "x$USE_EXA" = xyes; then + AC_DEFINE(USE_EXA, 1, [Build support for Exa]) + fi +fi + AC_CHECK_DECL(XSERVER_LIBPCIACCESS, [XSERVER_LIBPCIACCESS=yes],[XSERVER_LIBPCIACCESS=no], [#include "xorg-server.h"]) diff --git a/src/Makefile.am b/src/Makefile.am index df7c65c..017b6d6 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -30,6 +30,10 @@ if DRI R128_DRI_SRCS = r128_dri.c endif +if USE_EXA +R128_EXA_SRCS = r128_exa.c +endif + AM_CFLAGS = @XORG_CFLAGS@ @DRI_CFLAGS@ r128_drv_la_LTLIBRARIES = r128_drv.la @@ -37,7 +41,7 @@ r128_drv_la_LDFLAGS = -module -avoid-version r128_drv_ladir = @moduledir@/drivers r128_drv_la_SOURCES = \ r128_accel.c r128_cursor.c r128_dga.c r128_driver.c \ - r128_video.c r128_misc.c r128_probe.c $(R128_DRI_SRCS) + r128_video.c r128_misc.c r128_probe.c $(R128_EXA_SRCS) $(R128_DRI_SRCS) EXTRA_DIST = \ r128_common.h \ diff --git a/src/r128.h b/src/r128.h index fcef00c..a733a38 100644 --- a/src/r128.h +++ b/src/r128.h @@ -43,6 +43,9 @@ /* PCI support */ #include "xf86Pci.h" + /* EXA support */ +#include "exa.h" + /* XAA and Cursor Support */ #include "xaa.h" #include "xf86Cursor.h" @@ -77,6 +80,8 @@ #define R128_VBIOS_SIZE 0x00010000 #if R128_DEBUG +#include "r128_version.h" + #define R128TRACE(x) \ do { \ ErrorF("(**) %s(%d): ", R128_NAME, pScrn->scrnIndex); \ @@ -227,6 +232,22 @@ typedef enum MT_STV } R128MonitorType; +#ifdef USE_EXA +struct r128_2d_state { + Bool in_use; + uint32_t dst_pitch_offset; + uint32_t src_pitch_offset; + uint32_t dp_gui_master_cntl; + uint32_t dp_cntl; + uint32_t dp_write_mask; + uint32_t dp_brush_frgd_clr; + uint32_t dp_brush_bkgd_clr; + uint32_t dp_src_frgd_clr; + uint32_t dp_src_bkgd_clr; + uint32_t default_sc_bottom_right; +}; +#endif + typedef struct { EntityInfoPtr pEnt; pciVideoPtr PciInfo; @@ -277,6 +298,14 @@ typedef struct { XAAInfoRecPtr accel; Bool accelOn; + + Bool useEXA; +#ifdef USE_EXA + ExaDriverPtr ExaDriver; + XF86ModReqInfo exaReq; + struct r128_2d_state state_2d; +#endif + xf86CursorInfoPtr cursor; unsigned long cursor_start; unsigned long cursor_end; @@ -470,6 +499,7 @@ extern unsigned R128INPLL(ScrnInfoPtr pScrn, int addr); extern void R128WaitForVerticalSync(ScrnInfoPtr pScrn); extern Bool R128AccelInit(ScreenPtr pScreen); +extern Bool R128ExaInit(ScreenPtr pScreen); extern void R128EngineInit(ScrnInfoPtr pScrn); extern Bool R128CursorInit(ScreenPtr pScreen); extern Bool R128DGAInit(ScreenPtr pScreen); @@ -521,6 +551,11 @@ extern void R128CCEReleaseIndirect(ScrnInfoPtr pScrn); extern void R128CCEWaitForIdle(ScrnInfoPtr pScrn); extern int R128CCEStop(ScrnInfoPtr pScrn); +extern Bool R128GetDatatypeBpp(int bpp, uint32_t *type); +extern Bool R128GetPixmapOffsetPitch(PixmapPtr pPix, uint32_t *pitch_offset); +extern void R128DoPrepareCopy(ScrnInfoPtr pScrn, uint32_t src_pitch_offset, + uint32_t dst_pitch_offset, uint32_t datatype, int alu, Pixel planemask); + #define CCE_PACKET0( reg, n ) \ (R128_CCE_PACKET0 | ((n) << 16) | ((reg) >> 2)) diff --git a/src/r128_accel.c b/src/r128_accel.c index 056b0b3..6f653ae 100644 --- a/src/r128_accel.c +++ b/src/r128_accel.c @@ -1045,6 +1045,44 @@ void R128EngineInit(ScrnInfoPtr pScrn) OUTREG(R128_SC_BOTTOM_RIGHT, (R128_DEFAULT_SC_RIGHT_MAX | R128_DEFAULT_SC_BOTTOM_MAX)); +#ifdef RENDER +#ifdef USE_EXA + if (info->useEXA) { + R128TRACE(("Preparing for compositing\n")); + R128WaitForFifo(pScrn, 6); + OUTREG(R128_SCALE_3D_CNTL, + R128_SCALE_3D_TEXMAP_SHADE | + R128_SCALE_PIX_REPLICATE | + R128_TEX_CACHE_SPLIT | + R128_TEX_MAP_ALPHA_IN_TEXTURE | + R128_TEX_CACHE_LINE_SIZE_4QW); + OUTREG(R128_SETUP_CNTL, + R128_COLOR_SOLID_COLOR | + R128_PRIM_TYPE_TRI | + R128_TEXTURE_ST_MULT_W | + R128_STARTING_VERTEX_1 | + R128_ENDING_VERTEX_3 | + R128_SUB_PIX_4BITS); + OUTREG(R128_PM4_VC_FPU_SETUP, + R128_FRONT_DIR_CCW | + R128_BACKFACE_CULL | + R128_FRONTFACE_SOLID | + R128_FPU_COLOR_SOLID | + R128_FPU_SUB_PIX_4BITS | + R128_FPU_MODE_3D | + R128_TRAP_BITS_DISABLE | + R128_XFACTOR_2 | + R128_YFACTOR_2 | + R128_FLAT_SHADE_VERTEX_OGL | + R128_FPU_ROUND_TRUNCATE | + R128_WM_SEL_8DW); + OUTREG(R128_PLANE_3D_MASK_C, 0xffffffff); + OUTREG(R128_CONSTANT_COLOR_C, 0xff000000); + OUTREG(R128_WINDOW_XY_OFFSET, 0x00000000); + } +#endif +#endif + info->dp_gui_master_cntl = ((info->datatype << R128_GMC_DST_DATATYPE_SHIFT) | R128_GMC_CLR_CMP_CNTL_DIS | R128_GMC_AUX_CLIP_DIS); @@ -1866,8 +1904,33 @@ Bool R128AccelInit(ScreenPtr pScreen) R128InfoPtr info = R128PTR(pScrn); XAAInfoRecPtr a; - if (!xf86LoadSubModule(pScrn, "xaa")) - return FALSE; +#ifdef USE_EXA + if (info->useEXA) { + int errmaj = 0, errmin = 0; + + info->exaReq.majorversion = EXA_VERSION_MAJOR; + info->exaReq.minorversion = EXA_VERSION_MINOR; + + xf86DrvMsg(pScrn->scrnIndex,X_INFO,"Loading EXA module...\n"); + if (!LoadSubModule(pScrn->module, "exa", NULL, NULL, NULL, &info->exaReq, &errmaj, &errmin)) { + LoaderErrorMsg(NULL, "exa", errmaj, errmin); + return FALSE; + } + + /* Don't init EXA here because it'll be taken care of in mm init */ + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Allocating EXA driver...\n"); + info->ExaDriver = exaDriverAlloc(); + if (!info->ExaDriver) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Could not allocate EXA driver...\n"); + info->accel = FALSE; + } + + return TRUE; + } else +#endif + { + if (!xf86LoadSubModule(pScrn, "xaa")) return FALSE; + } if (!(a = info->accel = XAACreateInfoRec())) return FALSE; diff --git a/src/r128_cursor.c b/src/r128_cursor.c index 8321284..50e90ba 100644 --- a/src/r128_cursor.c +++ b/src/r128_cursor.c @@ -54,6 +54,9 @@ /* X and server generic header files */ #include "xf86.h" + /* Because for EXA we need to use a different allocator */ +#include "exa.h" + #if X_BYTE_ORDER == X_BIG_ENDIAN #define P_SWAP32( a , b ) \ ((char *)a)[0] = ((char *)b)[3]; \ @@ -253,10 +256,15 @@ Bool R128CursorInit(ScreenPtr pScreen) ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; R128InfoPtr info = R128PTR(pScrn); xf86CursorInfoPtr cursor; - FBAreaPtr fbarea; + FBAreaPtr fbarea = NULL; + ExaOffscreenArea* osArea = NULL; int width; int height; int size; + int cpp = info->CurrentLayout.pixel_bytes; + int width_bytes = (pScrn->displayWidth * + info->CurrentLayout.pixel_bytes); + int x1, x2, y1, y2; if (!(cursor = info->cursor = xf86CreateCursorInfoRec())) return FALSE; @@ -284,24 +292,40 @@ Bool R128CursorInit(ScreenPtr pScreen) size = (cursor->MaxWidth/4) * cursor->MaxHeight; width = pScrn->displayWidth; height = (size*2 + 1023) / pScrn->displayWidth; - fbarea = xf86AllocateOffscreenArea(pScreen, - width, - height, - 16, - NULL, - NULL, - NULL); - - if (!fbarea) { + + if(!info->useEXA) { + fbarea = xf86AllocateOffscreenArea(pScreen, width, height, + 16, NULL, NULL, NULL); + + if (fbarea) { + x1 = fbarea->box.x1; + x2 = fbarea->box.x2; + y1 = fbarea->box.y1; + y2 = fbarea->box.y2; + } + } +#ifdef USE_EXA + else { + osArea = exaOffscreenAlloc(pScreen, width * height, 16, + TRUE, NULL, NULL); + + if (osArea) { + x1 = osArea->offset % width_bytes; + x2 = (osArea->offset + osArea->size) % width_bytes; + y1 = osArea->offset / width_bytes; + y2 = (osArea->offset + osArea->size) / width_bytes; + } + } +#endif + + if ((!info->useEXA && !fbarea) || (info->useEXA && !osArea)) { info->cursor_start = 0; xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Hardware cursor disabled" " due to insufficient offscreen memory\n"); } else { - info->cursor_start = R128_ALIGN((fbarea->box.x1 - + width * fbarea->box.y1) - * info->CurrentLayout.pixel_bytes, 16); - info->cursor_end = info->cursor_start + size; + info->cursor_start = x1 * cpp + y1 * pScrn->virtualX * cpp; + info->cursor_end = x2 * cpp + y2 * pScrn->virtualX * cpp; } R128TRACE(("R128CursorInit (0x%08x-0x%08x)\n", diff --git a/src/r128_dri.c b/src/r128_dri.c index 624e3a5..0260b55 100644 --- a/src/r128_dri.c +++ b/src/r128_dri.c @@ -305,6 +305,9 @@ static void R128EnterServer(ScreenPtr pScreen) R128InfoPtr info = R128PTR(pScrn); if (info->accel) info->accel->NeedToSync = TRUE; +#ifdef USE_EXA + if (info->ExaDriver) exaMarkSync(pScreen); +#endif } /* Called when the X server goes to sleep to allow the X server's @@ -1389,6 +1392,7 @@ static void R128DRIRefreshArea(ScrnInfoPtr pScrn, int num, BoxPtr pbox) R128InfoPtr info = R128PTR(pScrn); int i; R128SAREAPrivPtr pSAREAPriv = DRIGetSAREAPrivate(pScrn->pScreen); + PixmapPtr pPix = pScrn->pScreen->GetScreenPixmap(pScrn->pScreen); /* Don't want to do this when no 3d is active and pages are * right-way-round @@ -1396,20 +1400,41 @@ static void R128DRIRefreshArea(ScrnInfoPtr pScrn, int num, BoxPtr pbox) if (!pSAREAPriv->pfAllowPageFlip && pSAREAPriv->pfCurrentPage == 0) return; - (*info->accel->SetupForScreenToScreenCopy)(pScrn, + if (!info->useEXA) { + (*info->accel->SetupForScreenToScreenCopy)(pScrn, 1, 1, GXcopy, (CARD32)(-1), -1); + } +#ifdef USE_EXA + else { + CARD32 src_pitch_offset, dst_pitch_offset, datatype; + + R128GetPixmapOffsetPitch(pPix, &src_pitch_offset); + dst_pitch_offset = src_pitch_offset + (info->backOffset >> 5); + R128GetDatatypeBpp(pScrn->bitsPerPixel, &datatype); + info->xdir = info->ydir = 1; + + R128DoPrepareCopy(pScrn, src_pitch_offset, dst_pitch_offset, datatype, GXcopy, ~0); + } +#endif for (i = 0 ; i < num ; i++, pbox++) { int xa = max(pbox->x1, 0), xb = min(pbox->x2, pScrn->virtualX-1); int ya = max(pbox->y1, 0), yb = min(pbox->y2, pScrn->virtualY-1); if (xa <= xb && ya <= yb) { - (*info->accel->SubsequentScreenToScreenCopy)(pScrn, xa, ya, + if (!info->useEXA) { + (*info->accel->SubsequentScreenToScreenCopy)(pScrn, xa, ya, xa + info->backX, ya + info->backY, xb - xa + 1, yb - ya + 1); + } +#ifdef USE_EXA + else { + (*info->ExaDriver->Copy)(pPix, xa, ya, xa, ya, xb - xa + 1, yb - ya + 1); + } +#endif } } } @@ -1419,20 +1444,40 @@ static void R128EnablePageFlip(ScreenPtr pScreen) ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; R128InfoPtr info = R128PTR(pScrn); R128SAREAPrivPtr pSAREAPriv = DRIGetSAREAPrivate(pScreen); - + PixmapPtr pPix = pScreen->GetScreenPixmap(pScreen); + + /* XXX: The page flip support below is buggy so this is best left to another patch */ + if (info->useEXA) return; + if (info->allowPageFlip) { /* Duplicate the frontbuffer to the backbuffer */ - (*info->accel->SetupForScreenToScreenCopy)(pScrn, + if (!info->useEXA) { + (*info->accel->SetupForScreenToScreenCopy)(pScrn, 1, 1, GXcopy, (CARD32)(-1), -1); - (*info->accel->SubsequentScreenToScreenCopy)(pScrn, + (*info->accel->SubsequentScreenToScreenCopy)(pScrn, 0, 0, info->backX, info->backY, pScrn->virtualX, pScrn->virtualY); + } +#ifdef USE_EXA + else { + CARD32 src_pitch_offset, dst_pitch_offset, datatype; + + R128GetPixmapOffsetPitch(pPix, &src_pitch_offset); + dst_pitch_offset = src_pitch_offset + (info->backOffset >> 5); + R128GetDatatypeBpp(pScrn->bitsPerPixel, &datatype); + info->xdir = info->ydir = 1; + + R128DoPrepareCopy(pScrn, src_pitch_offset, dst_pitch_offset, datatype, GXcopy, ~0); + + (*info->ExaDriver->Copy)(pPix, 0, 0, 0, 0, pScrn->virtualX, pScrn->virtualY); + } +#endif pSAREAPriv->pfAllowPageFlip = 1; } @@ -1471,6 +1516,10 @@ static void R128DRITransitionTo3d(ScreenPtr pScreen) if (info->cursor_start) xf86ForceHWCursor(pScreen, TRUE); + +#ifdef USE_EXA + if (info->ExaDriver) exaMarkSync(pScreen); +#endif } static void R128DRITransitionTo2d(ScreenPtr pScreen) diff --git a/src/r128_driver.c b/src/r128_driver.c index dc83076..7876f45 100644 --- a/src/r128_driver.c +++ b/src/r128_driver.c @@ -156,7 +156,8 @@ typedef enum { OPTION_FBDEV, OPTION_VIDEO_KEY, OPTION_SHOW_CACHE, - OPTION_VGA_ACCESS + OPTION_VGA_ACCESS, + OPTION_ACCELMETHOD } R128Opts; static const OptionInfoRec R128Options[] = { @@ -184,6 +185,7 @@ static const OptionInfoRec R128Options[] = { { OPTION_VIDEO_KEY, "VideoKey", OPTV_INTEGER, {0}, FALSE }, { OPTION_SHOW_CACHE, "ShowCache", OPTV_BOOLEAN, {0}, FALSE }, { OPTION_VGA_ACCESS, "VGAAccess", OPTV_BOOLEAN, {0}, TRUE }, + { OPTION_ACCELMETHOD, "AccelMethod", OPTV_STRING, {0}, FALSE }, { -1, NULL, OPTV_NONE, {0}, FALSE } }; @@ -2185,6 +2187,49 @@ R128BlockHandler(int i, pointer blockData, pointer pTimeout, pointer pReadmask) } } +#ifdef USE_EXA +Bool R128VerboseInitEXA(int scrnIndex, ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + R128InfoPtr info = R128PTR(pScrn); + + xf86DrvMsg(scrnIndex, X_INFO, "Going to init EXA...\n"); + + if (R128EXAInit(pScreen)) { + xf86DrvMsg(scrnIndex, X_INFO, "EXA Acceleration enabled\n"); + info->accelOn = TRUE; + } else { + xf86DrvMsg(scrnIndex, X_ERROR, + "EXA Acceleration initialization failed\n"); + xf86DrvMsg(scrnIndex, X_INFO, "EXA Acceleration disabled\n"); + info->accelOn = FALSE; + + return FALSE; + } +} +#endif + +void R128VerboseInitAccel(Bool noAccel, int scrnIndex, ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + R128InfoPtr info = R128PTR(pScrn); + + if (!noAccel) { + if (R128AccelInit(pScreen)) { + xf86DrvMsg(scrnIndex, X_INFO, "Acceleration enabled\n"); + info->accelOn = TRUE; + } else { + xf86DrvMsg(scrnIndex, X_ERROR, + "Acceleration initialization failed\n"); + xf86DrvMsg(scrnIndex, X_INFO, "Acceleration disabled\n"); + info->accelOn = FALSE; + } + } else { + xf86DrvMsg(scrnIndex, X_INFO, "Acceleration disabled\n"); + info->accelOn = FALSE; + } +} + /* Called at the start of each server generation. */ Bool R128ScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv) @@ -2192,8 +2237,25 @@ Bool R128ScreenInit(int scrnIndex, ScreenPtr pScreen, ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; R128InfoPtr info = R128PTR(pScrn); BoxRec MemBox; - int y2; + int width_bytes = (pScrn->displayWidth * + info->CurrentLayout.pixel_bytes); + int x1, x2, y1, y2; Bool noAccel; + ExaOffscreenArea* osArea; + char *optstr; + + info->useEXA = FALSE; + +#ifdef USE_EXA + optstr = (char *)xf86GetOptValString(info->Options, OPTION_ACCELMETHOD); + if (optstr != NULL) { + xf86DrvMsg(pScrn->scrnIndex,X_INFO,"AccelMethod option found\n"); + if (xf86NameCmp(optstr, "EXA") == 0) { + xf86DrvMsg(pScrn->scrnIndex,X_INFO,"AccelMethod is set to EXA, turning EXA on\n"); + info->useEXA = TRUE; + } + } +#endif R128TRACE(("R128ScreenInit %x %d\n", pScrn->memPhysBase, pScrn->fbOffset)); @@ -2221,7 +2283,7 @@ Bool R128ScreenInit(int scrnIndex, ScreenPtr pScreen, } else { if (!R128ModeInit(pScrn, pScrn->currentMode)) return FALSE; } - + R128SaveScreen(pScreen, SCREEN_SAVER_ON); pScrn->AdjustFrame(scrnIndex, pScrn->frameX0, pScrn->frameY0, 0); @@ -2245,8 +2307,6 @@ Bool R128ScreenInit(int scrnIndex, ScreenPtr pScreen, /* FIXME: When we move to dynamic allocation of back and depth buffers, we will want to revisit the following check for 3 times the virtual size of the screen below. */ - int width_bytes = (pScrn->displayWidth * - info->CurrentLayout.pixel_bytes); int maxy = info->FbMapSize / width_bytes; if (noAccel) { @@ -2323,8 +2383,6 @@ Bool R128ScreenInit(int scrnIndex, ScreenPtr pScreen, #ifdef R128DRI if (info->directRenderingEnabled) { FBAreaPtr fbarea; - int width_bytes = (pScrn->displayWidth * - info->CurrentLayout.pixel_bytes); int cpp = info->CurrentLayout.pixel_bytes; int bufferSize = pScrn->virtualY * width_bytes; int l, total; @@ -2387,7 +2445,7 @@ Bool R128ScreenInit(int scrnIndex, ScreenPtr pScreen, info->textureOffset = 0; info->textureSize = 0; } - + total = info->FbMapSize - info->textureSize; scanlines = total / width_bytes; if (scanlines > 8191) scanlines = 8191; @@ -2402,50 +2460,101 @@ Bool R128ScreenInit(int scrnIndex, ScreenPtr pScreen, MemBox.x2 = pScrn->displayWidth; MemBox.y2 = scanlines; - if (!xf86InitFBManager(pScreen, &MemBox)) { - xf86DrvMsg(scrnIndex, X_ERROR, - "Memory manager initialization to (%d,%d) (%d,%d) failed\n", - MemBox.x1, MemBox.y1, MemBox.x2, MemBox.y2); - return FALSE; - } else { - int width, height; - - xf86DrvMsg(scrnIndex, X_INFO, - "Memory manager initialized to (%d,%d) (%d,%d)\n", - MemBox.x1, MemBox.y1, MemBox.x2, MemBox.y2); - if ((fbarea = xf86AllocateOffscreenArea(pScreen, - pScrn->displayWidth, - 2, 0, NULL, NULL, NULL))) { - xf86DrvMsg(scrnIndex, X_INFO, - "Reserved area from (%d,%d) to (%d,%d)\n", - fbarea->box.x1, fbarea->box.y1, - fbarea->box.x2, fbarea->box.y2); + if (!info->useEXA) { + if (!xf86InitFBManager(pScreen, &MemBox)) { + xf86DrvMsg(scrnIndex, X_ERROR, + "Memory manager initialization to (%d,%d) (%d,%d) failed\n", + MemBox.x1, MemBox.y1, MemBox.x2, MemBox.y2); + return FALSE; } else { - xf86DrvMsg(scrnIndex, X_ERROR, "Unable to reserve area\n"); + int width, height; + + xf86DrvMsg(scrnIndex, X_INFO, + "Memory manager initialized to (%d,%d) (%d,%d)\n", + MemBox.x1, MemBox.y1, MemBox.x2, MemBox.y2); + if ((fbarea = xf86AllocateOffscreenArea(pScreen, + pScrn->displayWidth, + 2, 0, NULL, NULL, NULL))) { + xf86DrvMsg(scrnIndex, X_INFO, + "Reserved area from (%d,%d) to (%d,%d)\n", + fbarea->box.x1, fbarea->box.y1, + fbarea->box.x2, fbarea->box.y2); + } else { + xf86DrvMsg(scrnIndex, X_ERROR, "Unable to reserve area\n"); + } + if (xf86QueryLargestOffscreenArea(pScreen, &width, + &height, 0, 0, 0)) { + xf86DrvMsg(scrnIndex, X_INFO, + "Largest offscreen area available: %d x %d\n", + width, height); + } + + R128VerboseInitAccel(noAccel, scrnIndex, pScreen); } - if (xf86QueryLargestOffscreenArea(pScreen, &width, - &height, 0, 0, 0)) { - xf86DrvMsg(scrnIndex, X_INFO, - "Largest offscreen area available: %d x %d\n", - width, height); + } +#ifdef USE_EXA + else { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Filling in EXA memory info\n"); + + R128VerboseInitAccel(noAccel, scrnIndex, pScreen); + info->ExaDriver->offScreenBase = pScrn->virtualY * width_bytes; + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Filled in offs\n"); + + /* Don't give EXA the true full memory size, because the + textureSize sized chunk on the end is handled by DRI */ + info->ExaDriver->memorySize = total; + + R128VerboseInitEXA(scrnIndex, pScreen); + } +#endif + + /* Allocate the shared back buffer */ + if(!info->useEXA) { + fbarea = xf86AllocateOffscreenArea(pScreen, + pScrn->virtualX, + pScrn->virtualY, + 32, NULL, NULL, NULL); + + if (fbarea) { + x1 = fbarea->box.x1; + x2 = fbarea->box.x2; + y1 = fbarea->box.y1; + y2 = fbarea->box.y2; + } + } +#ifdef USE_EXA + else { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Actually trying an EXA allocation...\n"); + osArea = exaOffscreenAlloc(pScreen, + pScrn->virtualX * pScrn->virtualY, + 32, TRUE, NULL, NULL); + + if (osArea) { + x1 = osArea->offset % width_bytes; + x2 = (osArea->offset + osArea->size) % width_bytes; + y1 = osArea->offset / width_bytes; + y2 = (osArea->offset + osArea->size) / width_bytes; + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Went swimmingly...\n"); } } +#endif + + if ((!info->useEXA && fbarea) || (info->useEXA && osArea)) { + /* info->backOffset = y1 * width_bytes + x1 * cpp; */ + info->backOffset = R128_ALIGN(y1 * width_bytes + x1 * cpp, 16); + info->backX = info->backOffset % width_bytes; + info->backY = info->backOffset / width_bytes; + info->backPitch = pScrn->displayWidth; - /* Allocate the shared back buffer */ - if ((fbarea = xf86AllocateOffscreenArea(pScreen, - pScrn->virtualX, - pScrn->virtualY, - 32, NULL, NULL, NULL))) { xf86DrvMsg(scrnIndex, X_INFO, - "Reserved back buffer from (%d,%d) to (%d,%d)\n", - fbarea->box.x1, fbarea->box.y1, - fbarea->box.x2, fbarea->box.y2); - - info->backX = fbarea->box.x1; - info->backY = fbarea->box.y1; - info->backOffset = (fbarea->box.y1 * width_bytes + - fbarea->box.x1 * cpp); - info->backPitch = pScrn->displayWidth; + "Reserved back buffer from (%d,%d) to (%d,%d) offset: %x\n", + x1, y1, + x2, y2, info->backOffset); } else { xf86DrvMsg(scrnIndex, X_ERROR, "Unable to reserve back buffer\n"); info->backX = -1; @@ -2455,25 +2564,49 @@ Bool R128ScreenInit(int scrnIndex, ScreenPtr pScreen, } /* Allocate the shared depth buffer */ - if ((fbarea = xf86AllocateOffscreenArea(pScreen, - pScrn->virtualX, - pScrn->virtualY + 1, - 32, NULL, NULL, NULL))) { - xf86DrvMsg(scrnIndex, X_INFO, - "Reserved depth buffer from (%d,%d) to (%d,%d)\n", - fbarea->box.x1, fbarea->box.y1, - fbarea->box.x2, fbarea->box.y2); - - info->depthX = fbarea->box.x1; - info->depthY = fbarea->box.y1; - info->depthOffset = (fbarea->box.y1 * width_bytes + - fbarea->box.x1 * cpp); + if(!info->useEXA) { + fbarea = xf86AllocateOffscreenArea(pScreen, + pScrn->virtualX, + pScrn->virtualY + 1, + 32, NULL, NULL, NULL); + if (fbarea) { + x1 = fbarea->box.x1; + x2 = fbarea->box.x2; + y1 = fbarea->box.y1; + y2 = fbarea->box.y2; + } + } +#ifdef USE_EXA + else { + osArea = exaOffscreenAlloc(pScreen, + pScrn->virtualX * (pScrn->virtualY+1), + 32, TRUE, NULL, NULL); + + if (osArea) { + x1 = osArea->offset % width_bytes; + x2 = (osArea->offset + osArea->size) % width_bytes; + y1 = osArea->offset / width_bytes; + y2 = (osArea->offset + osArea->size) / width_bytes; + } + } +#endif + + if ((!info->useEXA && fbarea) || (info->useEXA && osArea)) { + /* info->depthOffset = y1 * width_bytes + x1 * cpp; */ + info->depthOffset = R128_ALIGN(y1 * width_bytes + x1 * cpp, 16); + info->depthX = info->depthOffset % width_bytes; + info->depthY = info->depthOffset / width_bytes; info->depthPitch = pScrn->displayWidth; - info->spanOffset = ((fbarea->box.y2 - 1) * width_bytes + - fbarea->box.x1 * cpp); + info->spanOffset = (y2 - 1) * width_bytes + x1 * cpp; + + xf86DrvMsg(scrnIndex, X_INFO, + "Reserved depth buffer from (%d,%d) to (%d,%d) offset: %x\n", + x1, y1, + x2, y2, info->depthOffset); + xf86DrvMsg(scrnIndex, X_INFO, "Reserved depth span from (%d,%d) offset 0x%x\n", - fbarea->box.x1, fbarea->box.y2 - 1, info->spanOffset); + x1, y2 - 1, info->spanOffset); } else { xf86DrvMsg(scrnIndex, X_ERROR, "Unable to reserve depth buffer\n"); info->depthX = -1; @@ -2488,7 +2621,7 @@ Bool R128ScreenInit(int scrnIndex, ScreenPtr pScreen, info->textureSize/1024, info->textureOffset); } else -#endif +#endif /* R128DRI */ { MemBox.x1 = 0; MemBox.y1 = 0; @@ -2502,50 +2635,51 @@ Bool R128ScreenInit(int scrnIndex, ScreenPtr pScreen, if (y2 > 8191) y2 = 8191; MemBox.y2 = y2; - if (!xf86InitFBManager(pScreen, &MemBox)) { - xf86DrvMsg(scrnIndex, X_ERROR, - "Memory manager initialization to (%d,%d) (%d,%d) failed\n", - MemBox.x1, MemBox.y1, MemBox.x2, MemBox.y2); - return FALSE; - } else { - int width, height; - FBAreaPtr fbarea; - - xf86DrvMsg(scrnIndex, X_INFO, - "Memory manager initialized to (%d,%d) (%d,%d)\n", - MemBox.x1, MemBox.y1, MemBox.x2, MemBox.y2); - if ((fbarea = xf86AllocateOffscreenArea(pScreen, pScrn->displayWidth, - 2, 0, NULL, NULL, NULL))) { - xf86DrvMsg(scrnIndex, X_INFO, - "Reserved area from (%d,%d) to (%d,%d)\n", - fbarea->box.x1, fbarea->box.y1, - fbarea->box.x2, fbarea->box.y2); + if (!info->useEXA) { + if (!xf86InitFBManager(pScreen, &MemBox)) { + xf86DrvMsg(scrnIndex, X_ERROR, + "Memory manager initialization to (%d,%d) (%d,%d) failed\n", + MemBox.x1, MemBox.y1, MemBox.x2, MemBox.y2); + return FALSE; } else { - xf86DrvMsg(scrnIndex, X_ERROR, "Unable to reserve area\n"); - } - if (xf86QueryLargestOffscreenArea(pScreen, &width, &height, - 0, 0, 0)) { - xf86DrvMsg(scrnIndex, X_INFO, - "Largest offscreen area available: %d x %d\n", - width, height); + int width, height; + FBAreaPtr fbarea; + + xf86DrvMsg(scrnIndex, X_INFO, + "Memory manager initialized to (%d,%d) (%d,%d)\n", + MemBox.x1, MemBox.y1, MemBox.x2, MemBox.y2); + if ((fbarea = xf86AllocateOffscreenArea(pScreen, pScrn->displayWidth, 2, 0, NULL, NULL, NULL))) { + xf86DrvMsg(scrnIndex, X_INFO, + "Reserved area from (%d,%d) to (%d,%d)\n", + fbarea->box.x1, fbarea->box.y1, + fbarea->box.x2, fbarea->box.y2); + } else { + xf86DrvMsg(scrnIndex, X_ERROR, "Unable to reserve area\n"); + } + if (xf86QueryLargestOffscreenArea(pScreen, &width, &height, 0, 0, 0)) { + xf86DrvMsg(scrnIndex, X_INFO, + "Largest offscreen area available: %d x %d\n", + width, height); + } + + R128VerboseInitAccel(noAccel, scrnIndex, pScreen); } } - } - - /* Acceleration setup */ - if (!noAccel) { - if (R128AccelInit(pScreen)) { - xf86DrvMsg(scrnIndex, X_INFO, "Acceleration enabled\n"); - info->accelOn = TRUE; - } else { - xf86DrvMsg(scrnIndex, X_ERROR, - "Acceleration initialization failed\n"); - xf86DrvMsg(scrnIndex, X_INFO, "Acceleration disabled\n"); - info->accelOn = FALSE; +#ifdef USE_EXA + else { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Filling in EXA memory info\n"); + + R128VerboseInitAccel(noAccel, scrnIndex, pScreen); + info->ExaDriver->offScreenBase = width_bytes * pScrn->virtualY; + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Filled in offs\n"); + + info->ExaDriver->memorySize = info->FbMapSize; + R128VerboseInitEXA(scrnIndex, pScreen); } - } else { - xf86DrvMsg(scrnIndex, X_INFO, "Acceleration disabled\n"); - info->accelOn = FALSE; +#endif } /* DGA setup */ @@ -2897,16 +3031,6 @@ static void R128RestorePLL2Registers(ScrnInfoPtr pScrn, R128SavePtr restore) | R128_P2PLL_ATOMIC_UPDATE_EN | R128_P2PLL_VGA_ATOMIC_UPDATE_EN)); - R128TRACE(("Wrote: 0x%08x 0x%08x 0x%08x (0x%08x)\n", - restore->p2pll_ref_div, - restore->p2pll_div_0, - restore->htotal_cntl2, - INPLL(pScrn, RADEON_P2PLL_CNTL))); - R128TRACE(("Wrote: rd=%d, fd=%d, pd=%d\n", - restore->p2pll_ref_div & RADEON_P2PLL_REF_DIV_MASK, - restore->p2pll_div_0 & RADEON_P2PLL_FB3_DIV_MASK, - (restore->p2pll_div_0 & RADEON_P2PLL_POST3_DIV_MASK) >>16)); - usleep(5000); /* Let the clock to lock */ OUTPLLP(pScrn, R128_V2CLK_VCLKTV_CNTL, @@ -3793,12 +3917,6 @@ static void R128InitPLL2Registers(R128SavePtr save, R128PLLPtr pll, pll->reference_freq); save->post_div_2 = post_div->divider; - R128TRACE(("dc=%d, of=%d, fd=%d, pd=%d\n", - save->dot_clock_freq_2, - save->pll_output_freq_2, - save->feedback_div_2, - save->post_div_2)); - save->p2pll_ref_div = pll->reference_div; save->p2pll_div_0 = (save->feedback_div_2 | (post_div->bitvalue<<16)); save->htotal_cntl2 = 0; @@ -4299,8 +4417,18 @@ static Bool R128CloseScreen(int scrnIndex, ScreenPtr pScreen) R128UnmapMem(pScrn); } - if (info->accel) XAADestroyInfoRec(info->accel); - info->accel = NULL; + if (info->accel) { +#ifdef USE_EXA + if (info->useEXA) { + exaDriverFini(pScreen); + free(info->ExaDriver); + } else +#endif + { + XAADestroyInfoRec(info->accel); + } + info->accel = NULL; + } if (info->scratch_save) free(info->scratch_save); info->scratch_save = NULL; diff --git a/src/r128_exa.c b/src/r128_exa.c new file mode 100644 index 0000000..074199d --- /dev/null +++ b/src/r128_exa.c @@ -0,0 +1,1246 @@ +/* + * Copyright 2003 Eric Anholt + * Copyright 2003 Anders Carlsson + * Copyright 2006 Joseph Garvin + * Copyright 2012 Connor Behan + * 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 + * Anders Carlsson + * Joseph Garvin + * Connor Behan + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "r128.h" +#include "exa.h" + +#include "r128_reg.h" + +#include "xf86.h" + +static struct { + int rop; + int pattern; +} R128_ROP[] = { + { R128_ROP3_ZERO, R128_ROP3_ZERO }, /* GXclear */ + { R128_ROP3_DSa, R128_ROP3_DPa }, /* Gxand */ + { R128_ROP3_SDna, R128_ROP3_PDna }, /* GXandReverse */ + { R128_ROP3_S, R128_ROP3_P }, /* GXcopy */ + { R128_ROP3_DSna, R128_ROP3_DPna }, /* GXandInverted */ + { R128_ROP3_D, R128_ROP3_D }, /* GXnoop */ + { R128_ROP3_DSx, R128_ROP3_DPx }, /* GXxor */ + { R128_ROP3_DSo, R128_ROP3_DPo }, /* GXor */ + { R128_ROP3_DSon, R128_ROP3_DPon }, /* GXnor */ + { R128_ROP3_DSxn, R128_ROP3_PDxn }, /* GXequiv */ + { R128_ROP3_Dn, R128_ROP3_Dn }, /* GXinvert */ + { R128_ROP3_SDno, R128_ROP3_PDno }, /* GXorReverse */ + { R128_ROP3_Sn, R128_ROP3_Pn }, /* GXcopyInverted */ + { R128_ROP3_DSno, R128_ROP3_DPno }, /* GXorInverted */ + { R128_ROP3_DSan, R128_ROP3_DPan }, /* GXnand */ + { R128_ROP3_ONE, R128_ROP3_ONE } /* GXset */ +}; + +#ifdef RENDER +static struct { + Bool dst_alpha; + Bool src_alpha; + CARD32 blendctl; +} R128BlendOp[] = { + /* Clear */ + {0, 0, R128_SBLEND_ZERO | R128_DBLEND_ZERO}, + /* Src */ + {0, 0, R128_SBLEND_ONE | R128_DBLEND_ZERO}, + /* Dst */ + {0, 0, R128_SBLEND_ZERO | R128_DBLEND_ONE}, + /* Over */ + {0, 1, R128_SBLEND_ONE | R128_DBLEND_INV_SRC_ALPHA}, + /* OverReverse */ + {1, 0, R128_SBLEND_INV_DST_ALPHA | R128_DBLEND_ONE}, + /* In */ + {1, 0, R128_SBLEND_DST_ALPHA | R128_DBLEND_ZERO}, + /* InReverse */ + {0, 1, R128_SBLEND_ZERO | R128_DBLEND_SRC_ALPHA}, + /* Out */ + {1, 0, R128_SBLEND_INV_DST_ALPHA | R128_DBLEND_ZERO}, + /* OutReverse */ + {0, 1, R128_SBLEND_ZERO | R128_DBLEND_INV_SRC_ALPHA}, + /* Atop */ + {1, 1, R128_SBLEND_DST_ALPHA | R128_DBLEND_INV_SRC_ALPHA}, + /* AtopReverse */ + {1, 1, R128_SBLEND_INV_DST_ALPHA | R128_DBLEND_SRC_ALPHA}, + /* Xor */ + {1, 1, R128_SBLEND_INV_DST_ALPHA | R128_DBLEND_INV_SRC_ALPHA}, + /* Add */ + {0, 0, R128_SBLEND_ONE | R128_DBLEND_ONE}, +}; + +static int widths[2] = {1,1}; +static int heights[2] = {1,1}; +static Bool is_transform[2]; +static PictTransform *transform[2]; + +typedef union { float f; CARD32 i; } fi_type; + +/* If it was okay to not be paranoid about a simple cast, I guess they wouldn't have made this. */ +static inline CARD32 +R128FloatAsInt(float val) +{ + fi_type fi; + + fi.f = val; + return fi.i; +} + +#define VTX_RING_COUNT 8 + +#define VTX_OUT(_dstX, _dstY, _srcX, _srcY, _maskX, _maskY) \ +do { \ + OUTREG(0, R128FloatAsInt(_dstX)); \ + OUTREG(0, R128FloatAsInt(((float)(_dstY)) + 0.125)); \ + OUTREG(0, R128FloatAsInt(0.0)); \ + OUTREG(0, R128FloatAsInt(1.0)); \ + OUTREG(0, R128FloatAsInt((((float)(_srcX)) + 0.5) / (widths[0]))); \ + OUTREG(0, R128FloatAsInt((((float)(_srcY)) + 0.5) / (heights[0]))); \ + OUTREG(0, R128FloatAsInt((((float)(_maskX)) + 0.5) / (widths[1]))); \ + OUTREG(0, R128FloatAsInt((((float)(_maskY)) + 0.5) / (heights[1])));\ +} while (0) + +#define VTX_CCE_OUT(_dstX, _dstY, _srcX, _srcY, _maskX, _maskY) \ +do { \ + OUT_RING(R128FloatAsInt(_dstX)); \ + OUT_RING(R128FloatAsInt(((float)(_dstY)) + 0.125)); \ + OUT_RING(R128FloatAsInt(0.0)); \ + OUT_RING(R128FloatAsInt(1.0)); \ + OUT_RING(R128FloatAsInt((((float)(_srcX)) + 0.5) / (widths[0]))); \ + OUT_RING(R128FloatAsInt((((float)(_srcY)) + 0.5) / (heights[0]))); \ + OUT_RING(R128FloatAsInt((((float)(_maskX)) + 0.5) / (widths[1]))); \ + OUT_RING(R128FloatAsInt((((float)(_maskY)) + 0.5) / (heights[1]))); \ +} while (0) + +static Bool +R128TransformAffineOrScaled(PictTransformPtr t) +{ + if (t == NULL) return TRUE; + + /* the shaders don't handle scaling either */ + return t->matrix[2][0] == 0 && t->matrix[2][1] == 0 && t->matrix[2][2] == IntToxFixed(1); +} + +static PixmapPtr +R128GetDrawablePixmap(DrawablePtr pDrawable) +{ + if (pDrawable->type == DRAWABLE_WINDOW) + return pDrawable->pScreen->GetWindowPixmap((WindowPtr)pDrawable); + else + return (PixmapPtr)pDrawable; +} + +/* XXX: Extra rejection criteria to make tests pass -- possibly card specific! */ +static Bool +R128Quirks(PicturePtr pMaskPicture, PicturePtr pSrcPicture, int op) +{ + if (pMaskPicture->format == PICT_r5g6b5 && pSrcPicture->format == PICT_r5g6b5) { + switch (op) { + case PictOpClear: + case PictOpSrc: + case PictOpIn: + case PictOpOut: + case PictOpOutReverse: + case PictOpOver: + case PictOpAtop: + case PictOpAdd: + case PictOpXor: + return FALSE; + default: + return TRUE; + } + } + + return TRUE; +} + +/* Sometimes one list is supported, sometimes the other list is */ +static Bool +R128GetDatatypePict1(uint32_t format, uint32_t *type) +{ + switch(format) { + case PICT_r5g6b5: + *type = R128_DATATYPE_RGB565; + return TRUE; + case PICT_a1r5g5b5: + case PICT_x1r5g5b5: + *type = R128_DATATYPE_ARGB1555; + return TRUE; + case PICT_x8r8g8b8: + *type = R128_DATATYPE_ARGB8888; + return TRUE; + default: + return FALSE; + } +} + +static Bool +R128GetDatatypePict2(uint32_t format, uint32_t *type) +{ + switch(format) { + case PICT_r5g6b5: + *type = R128_DATATYPE_RGB565; + return TRUE; + case PICT_a1r5g5b5: + *type = R128_DATATYPE_ARGB1555; + return TRUE; + case PICT_a4r4g4b4: + *type = R128_DATATYPE_ARGB4444; + return TRUE; + default: + return FALSE; + } +} +#endif + +/* Assumes that depth 15 and 16 can be used as depth 16, which is okay since we + * require src and dest datatypes to be equal. + */ +Bool R128GetDatatypeBpp(int bpp, uint32_t *type) +{ + switch (bpp) { + case 8: + *type = R128_DATATYPE_CI8; + return TRUE; + case 16: + *type = R128_DATATYPE_RGB565; + return TRUE; + case 24: + *type = R128_DATATYPE_CI8; + return TRUE; + case 32: + *type = R128_DATATYPE_ARGB8888; + return TRUE; + default: + return FALSE; + } +} + +static Bool R128GetOffsetPitch(PixmapPtr pPix, int bpp, uint32_t *pitch_offset, + unsigned int offset, unsigned int pitch) +{ + ScreenPtr pScreen = pPix->drawable.pScreen; + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + R128InfoPtr info = R128PTR(pScrn); + + if (pitch > 16320 || pitch % info->ExaDriver->pixmapPitchAlign != 0) { + R128TRACE(("Bad pitch 0x%08x\n", pitch)); + return FALSE; + } + + if (offset % info->ExaDriver->pixmapOffsetAlign != 0) { + R128TRACE(("Bad offset 0x%08x\n", offset)); + return FALSE; + } + + *pitch_offset = ((pitch / bpp) << 21) | (offset >> 5); + + return TRUE; +} + +Bool R128GetPixmapOffsetPitch(PixmapPtr pPix, uint32_t *pitch_offset) +{ + uint32_t pitch, offset; + int bpp; + + bpp = pPix->drawable.bitsPerPixel; + if (bpp == 24) + bpp = 8; + + offset = exaGetPixmapOffset(pPix); + pitch = exaGetPixmapPitch(pPix); + + return R128GetOffsetPitch(pPix, bpp, pitch_offset, offset, pitch); +} + +static void Emit2DState(ScrnInfoPtr pScrn) +{ + R128InfoPtr info = R128PTR(pScrn); + int has_src = info->state_2d.src_pitch_offset; + unsigned char *R128MMIO = info->MMIO; + + R128WaitForFifo(pScrn, (has_src ? 10 : 9)); + + OUTREG(R128_DEFAULT_SC_BOTTOM_RIGHT, info->state_2d.default_sc_bottom_right); + OUTREG(R128_DP_GUI_MASTER_CNTL, info->state_2d.dp_gui_master_cntl); + OUTREG(R128_DP_BRUSH_FRGD_CLR, info->state_2d.dp_brush_frgd_clr); + OUTREG(R128_DP_BRUSH_BKGD_CLR, info->state_2d.dp_brush_bkgd_clr); + OUTREG(R128_DP_SRC_FRGD_CLR, info->state_2d.dp_src_frgd_clr); + OUTREG(R128_DP_SRC_BKGD_CLR, info->state_2d.dp_src_bkgd_clr); + OUTREG(R128_DP_WRITE_MASK, info->state_2d.dp_write_mask); + OUTREG(R128_DP_CNTL, info->state_2d.dp_cntl); + + OUTREG(R128_DST_PITCH_OFFSET, info->state_2d.dst_pitch_offset); + if (has_src) OUTREG(R128_SRC_PITCH_OFFSET, info->state_2d.src_pitch_offset); +} + +static void EmitCCE2DState(ScrnInfoPtr pScrn) +{ + R128InfoPtr info = R128PTR(pScrn); + int has_src = info->state_2d.src_pitch_offset; + RING_LOCALS; + + R128CCE_REFRESH( pScrn, info ); + + BEGIN_RING( (has_src ? 20 : 18) ); + + OUT_RING_REG( R128_DEFAULT_SC_BOTTOM_RIGHT, info->state_2d.default_sc_bottom_right ); + OUT_RING_REG( R128_DP_GUI_MASTER_CNTL, info->state_2d.dp_gui_master_cntl ); + OUT_RING_REG( R128_DP_BRUSH_FRGD_CLR, info->state_2d.dp_brush_frgd_clr ); + OUT_RING_REG( R128_DP_BRUSH_BKGD_CLR, info->state_2d.dp_brush_bkgd_clr ); + OUT_RING_REG( R128_DP_SRC_FRGD_CLR, info->state_2d.dp_src_frgd_clr ); + OUT_RING_REG( R128_DP_SRC_BKGD_CLR, info->state_2d.dp_src_bkgd_clr ); + OUT_RING_REG( R128_DP_WRITE_MASK, info->state_2d.dp_write_mask ); + OUT_RING_REG( R128_DP_CNTL, info->state_2d.dp_cntl ); + + OUT_RING_REG( R128_DST_PITCH_OFFSET, info->state_2d.dst_pitch_offset ); + if (has_src) OUT_RING_REG( R128_SRC_PITCH_OFFSET, info->state_2d.src_pitch_offset ); + + ADVANCE_RING(); +} + +/* EXA Callbacks */ + +static Bool +R128PrepareSolid(PixmapPtr pPixmap, int alu, Pixel planemask, Pixel fg) +{ + ScreenPtr pScreen = pPixmap->drawable.pScreen; + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + R128InfoPtr info = R128PTR(pScrn); + + int bpp = pPixmap->drawable.bitsPerPixel; + uint32_t datatype, dst_pitch_offset; + + if (!R128GetDatatypeBpp(bpp, &datatype)) { + R128TRACE(("R128GetDatatypeBpp failed\n")); + return FALSE; + } + if (!R128GetPixmapOffsetPitch(pPixmap, &dst_pitch_offset)) { + R128TRACE(("R128GetPixmapOffsetPitch failed\n")); + return FALSE; + } + if (info->state_2d.in_use) return FALSE; + + info->state_2d.in_use = TRUE; + info->state_2d.default_sc_bottom_right = (R128_DEFAULT_SC_RIGHT_MAX | R128_DEFAULT_SC_BOTTOM_MAX); + info->state_2d.dp_brush_bkgd_clr = 0x00000000; + info->state_2d.dp_src_frgd_clr = 0xffffffff; + info->state_2d.dp_src_bkgd_clr = 0x00000000; + info->state_2d.dp_gui_master_cntl = (R128_GMC_DST_PITCH_OFFSET_CNTL | + R128_GMC_BRUSH_SOLID_COLOR | + (datatype >> 8) | + R128_GMC_SRC_DATATYPE_COLOR | + R128_ROP[alu].pattern | + R128_GMC_CLR_CMP_CNTL_DIS); + info->state_2d.dp_brush_frgd_clr = fg; + info->state_2d.dp_cntl = (R128_DST_X_LEFT_TO_RIGHT | R128_DST_Y_TOP_TO_BOTTOM); + info->state_2d.dp_write_mask = planemask; + info->state_2d.dst_pitch_offset = dst_pitch_offset; + info->state_2d.src_pitch_offset = 0; + +#ifdef R128DRI + if (info->directRenderingEnabled) { + EmitCCE2DState(pScrn); + } else +#endif + { + Emit2DState(pScrn); + } + return TRUE; +} + +static void +R128Solid(PixmapPtr pPixmap, int x1, int y1, int x2, int y2) +{ + ScreenPtr pScreen = pPixmap->drawable.pScreen; + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + R128InfoPtr info = R128PTR(pScrn); + unsigned char *R128MMIO = info->MMIO; + + R128WaitForFifo(pScrn, 2); + OUTREG(R128_DST_Y_X, (y1 << 16) | x1); + OUTREG(R128_DST_WIDTH_HEIGHT, ((x2-x1) << 16) | (y2-y1)); +} + +#define R128DoneSolid R128Done + +void +R128DoPrepareCopy(ScrnInfoPtr pScrn, uint32_t src_pitch_offset, + uint32_t dst_pitch_offset, uint32_t datatype, int alu, Pixel planemask) +{ + R128InfoPtr info = R128PTR(pScrn); + + info->state_2d.in_use = TRUE; + info->state_2d.dp_gui_master_cntl = (R128_GMC_DST_PITCH_OFFSET_CNTL | + R128_GMC_SRC_PITCH_OFFSET_CNTL | + R128_GMC_BRUSH_NONE | + (datatype >> 8) | + R128_GMC_SRC_DATATYPE_COLOR | + R128_ROP[alu].rop | + R128_DP_SRC_SOURCE_MEMORY | + R128_GMC_CLR_CMP_CNTL_DIS); + info->state_2d.dp_cntl = ((info->xdir >= 0 ? R128_DST_X_LEFT_TO_RIGHT : 0) | + (info->ydir >= 0 ? R128_DST_Y_TOP_TO_BOTTOM : 0)); + info->state_2d.dp_brush_frgd_clr = 0xffffffff; + info->state_2d.dp_brush_bkgd_clr = 0x00000000; + info->state_2d.dp_src_frgd_clr = 0xffffffff; + info->state_2d.dp_src_bkgd_clr = 0x00000000; + info->state_2d.dp_write_mask = planemask; + info->state_2d.dst_pitch_offset = dst_pitch_offset; + info->state_2d.src_pitch_offset = src_pitch_offset; + info->state_2d.default_sc_bottom_right = (R128_DEFAULT_SC_RIGHT_MAX | R128_DEFAULT_SC_BOTTOM_MAX); + +#ifdef R128DRI + if (info->directRenderingEnabled) { + EmitCCE2DState(pScrn); + } else +#endif + { + Emit2DState(pScrn); + } +} + +static Bool +R128PrepareCopy(PixmapPtr pSrcPixmap, PixmapPtr pDstPixmap, int xdir, int ydir, int alu, Pixel planemask) +{ + ScreenPtr pScreen = pSrcPixmap->drawable.pScreen; + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + R128InfoPtr info = R128PTR(pScrn); + + int bpp = pDstPixmap->drawable.bitsPerPixel; + uint32_t datatype, src_pitch_offset, dst_pitch_offset; + + if (!R128GetDatatypeBpp(bpp, &datatype)) { + R128TRACE(("R128GetDatatypeBpp failed\n")); + return FALSE; + } + if (!R128GetPixmapOffsetPitch(pSrcPixmap, &src_pitch_offset)) { + R128TRACE(("R128GetPixmapOffsetPitch source failed\n")); + return FALSE; + } + if (!R128GetPixmapOffsetPitch(pDstPixmap, &dst_pitch_offset)) { + R128TRACE(("R128GetPixmapOffsetPitch dest failed\n")); + return FALSE; + } + if (info->state_2d.in_use) return FALSE; + + info->xdir = xdir; + info->ydir = ydir; + + R128DoPrepareCopy(pScrn, src_pitch_offset, dst_pitch_offset, datatype, alu, planemask); + + return TRUE; +} + +static void +R128Copy(PixmapPtr pDstPixmap, int srcX, int srcY, int dstX, int dstY, int width, int height) +{ + ScreenPtr pScreen = pDstPixmap->drawable.pScreen; + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + R128InfoPtr info = R128PTR(pScrn); + unsigned char *R128MMIO = info->MMIO; + + if (info->xdir < 0) srcX += width - 1, dstX += width - 1; + if (info->ydir < 0) srcY += height - 1, dstY += height - 1; + + R128WaitForFifo(pScrn, 3); + OUTREG(R128_SRC_Y_X, (srcY << 16) | srcX); + OUTREG(R128_DST_Y_X, (dstY << 16) | dstX); + OUTREG(R128_DST_HEIGHT_WIDTH, (height << 16) | width); +} + +#define R128DoneCopy R128Done + +#ifdef RENDER +static Bool +R128CheckCompositeTexture(PicturePtr pPict, PicturePtr pDstPict, int op) +{ + ScreenPtr pScreen = pPict->pDrawable->pScreen; + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + R128InfoPtr info = R128PTR(pScrn); + + unsigned int repeatType = pPict->repeat ? pPict->repeatType : RepeatNone; + int w = pPict->pDrawable->width; + int h = pPict->pDrawable->height; + uint32_t tmp1; + + if (!R128GetDatatypePict2(pDstPict->format, &tmp1)) return FALSE; + + if (pPict->repeat && ((w & (w - 1)) != 0 || (h & (h - 1)) != 0)) { + R128TRACE(("NPOT repeat unsupported (%dx%d)\n", w, h)); + return FALSE; + } + if (pPict->filter != PictFilterNearest && pPict->filter != PictFilterBilinear) { + R128TRACE(("Unsupported filter 0x%x\n", pPict->filter)); + return FALSE; + } + + /* The radeon driver has a long explanation about this part that I don't really understand */ + if (pPict->transform != 0 && repeatType == RepeatNone && PICT_FORMAT_A(pPict->format) == 0) { + if (!(((op == PictOpSrc) || (op == PictOpClear)) && (PICT_FORMAT_A(pDstPict->format) == 0))) { + R128TRACE(("REPEAT_NONE unsupported for transformed xRGB source\n")); + return FALSE; + } + } + if (!R128TransformAffineOrScaled(pPict->transform)) { + R128TRACE(("Non-affine transforms not supported\n")); + return FALSE; + } + + return TRUE; +} + +static Bool +R128CheckComposite(int op, PicturePtr pSrcPicture, PicturePtr pMaskPicture, PicturePtr pDstPicture) +{ + ScreenPtr pScreen = pSrcPicture->pDrawable->pScreen; + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + R128InfoPtr info = R128PTR(pScrn); + + PixmapPtr pSrcPixmap, pDstPixmap; + uint32_t tmp1; + + /* Check for unsupported compositing operations. */ + if (op >= sizeof(R128BlendOp) / sizeof(R128BlendOp[0])) { + R128TRACE(("Unsupported Composite op 0x%x\n", op)); + return FALSE; + } + if (!pSrcPicture->pDrawable) { + R128TRACE(("Solid or gradient pictures not supported yet\n")); + return FALSE; + } + + /* The radeon driver says that a bug requires 2047 instead of 2048 and r128 uses 1024 so... */ + pSrcPixmap = R128GetDrawablePixmap(pSrcPicture->pDrawable); + if (pSrcPixmap->drawable.width > 1023 || pSrcPixmap->drawable.height > 1023) { + R128TRACE(("Source w/h too large (%d,%d).\n", pSrcPixmap->drawable.width, pSrcPixmap->drawable.height)); + return FALSE; + } + + pDstPixmap = R128GetDrawablePixmap(pDstPicture->pDrawable); + if (pDstPixmap->drawable.width > 1023 || pDstPixmap->drawable.height > 1023) { + R128TRACE(("Dest w/h too large (%d,%d).\n", pDstPixmap->drawable.width, pDstPixmap->drawable.height)); + return FALSE; + } + + if (pDstPicture->format == PICT_a8) { + if (R128BlendOp[op].src_alpha || R128BlendOp[op].dst_alpha || pMaskPicture != NULL) { + R128TRACE(("Alpha blending unsupported with A8 dst?\n")); + return FALSE; + } + } else { + if (!R128GetDatatypePict1(pDstPicture->format, &tmp1)) return FALSE; + } + + if (pMaskPicture) { + PixmapPtr pMaskPixmap; + + if (!pMaskPicture->pDrawable) { + R128TRACE(("Solid or gradient pictures not supported yet\n")); + return FALSE; + } + + pMaskPixmap = R128GetDrawablePixmap(pMaskPicture->pDrawable); + if (pMaskPixmap->drawable.width > 1023 || pMaskPixmap->drawable.height > 1023) { + R128TRACE(("Mask w/h too large (%d,%d).\n", pMaskPixmap->drawable.width, pMaskPixmap->drawable.height)); + return FALSE; + } + + if (pMaskPicture->componentAlpha && R128BlendOp[op].src_alpha) { + R128TRACE(("Component alpha not supported with source alpha blending\n")); + return FALSE; + } + + if (!R128Quirks(pMaskPicture, pSrcPicture, op)) return FALSE; + if (!R128CheckCompositeTexture(pMaskPicture, pDstPicture, op)) return FALSE; + } + + if (!R128CheckCompositeTexture(pSrcPicture, pDstPicture, op)) return FALSE; + + return TRUE; +} + +static Bool +R128TextureSetup(PicturePtr pPict, PixmapPtr pPix, int unit, uint32_t *txsize, uint32_t *tex_cntl_c) +{ + ScreenPtr pScreen = pPix->drawable.pScreen; + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + R128InfoPtr info = R128PTR(pScrn); + + int w = pPict->pDrawable->width; + int h = pPict->pDrawable->height; + int bytepp, shift, l2w, l2h, l2p, pitch; + + pitch = pPix->devKind; + if ((pitch & (pitch - 1)) != 0) { + R128TRACE(("NPOT pitch 0x%x unsupported\n", pitch)); + return FALSE; + } + + if (!R128GetDatatypePict2(pPict->format, tex_cntl_c)) return FALSE; + + bytepp = PICT_FORMAT_BPP(pPict->format) / 8; + + *tex_cntl_c |= R128_MIP_MAP_DISABLE; + + if (pPict->filter == PictFilterBilinear) { + *tex_cntl_c |= R128_MIN_BLEND_LINEAR | R128_MAG_BLEND_LINEAR; + } else if (pPict->filter == PictFilterNearest) { + *tex_cntl_c |= R128_MIN_BLEND_NEAREST | R128_MAG_BLEND_NEAREST; + } else { + R128TRACE(("Bad filter 0x%x\n", pPict->filter)); + return FALSE; + } + + if (unit == 0) + shift = 0; + else { + shift = 16; + *tex_cntl_c |= R128_SEC_SELECT_SEC_ST; + } + + /* R128MinBits returns -1 for value of 0 */ + l2w = R128MinBits(w - 1) + 1; + l2h = R128MinBits(h - 1) + 1; + l2p = R128MinBits(pPix->devKind / bytepp); + + if (pPict->repeat && w == 1 && h == 1) + l2p = 0; + else if (pPict->repeat && l2p != l2w) { + R128TRACE(("Repeat not supported for pitch != width\n")); + return FALSE; + } + l2w = l2p; + + widths[unit] = 1 << l2w; + heights[unit] = 1 << l2h; + *txsize |= l2p << (R128_TEX_PITCH_SHIFT + shift); + *txsize |= ((l2w > l2h) ? l2w : l2h) << (R128_TEX_SIZE_SHIFT + shift); + *txsize |= l2h << (R128_TEX_HEIGHT_SHIFT + shift); + + if (pPict->transform != 0) { + is_transform[unit] = TRUE; + transform[unit] = pPict->transform; + } else { + is_transform[unit] = FALSE; + } + + return TRUE; +} + +static Bool +R128PrepareComposite(int op, PicturePtr pSrcPicture, PicturePtr pMaskPicture, + PicturePtr pDstPicture, PixmapPtr pSrc, PixmapPtr pMask, PixmapPtr pDst) +{ + ScreenPtr pScreen = pSrc->drawable.pScreen; + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + R128InfoPtr info = R128PTR(pScrn); + unsigned char *R128MMIO = info->MMIO; + + uint32_t txsize = 0, prim_tex_cntl_c, sec_tex_cntl_c = 0, dstDatatype; + uint32_t dst_pitch_offset, color_factor, in_color_factor, alpha_comb; + uint32_t blend_cntl; + int i; + + if (pDstPicture->format == PICT_a8) { + if (R128BlendOp[op].dst_alpha) { + R128TRACE(("Can't dst alpha blend A8\n")); + return FALSE; + } + dstDatatype = R128_DATATYPE_Y8; + } else { + if (!R128GetDatatypePict1(pDstPicture->format, &dstDatatype)) return FALSE; + } + + if (!R128TextureSetup(pSrcPicture, pSrc, 0, &txsize, &prim_tex_cntl_c)) return FALSE; + + if (pMask != NULL) { + if (!R128TextureSetup(pMaskPicture, pMask, 1, &txsize, &sec_tex_cntl_c)) return FALSE; + } else { + is_transform[1] = FALSE; + } + + if (!R128GetPixmapOffsetPitch(pDst, &dst_pitch_offset)) return FALSE; + + info->state_2d.in_use = TRUE; + blend_cntl = R128BlendOp[op].blendctl; + if (PICT_FORMAT_A(pDstPicture->format) == 0 && R128BlendOp[op].dst_alpha) { + if ((blend_cntl & R128_SBLEND_MASK) == R128_SBLEND_DST_ALPHA) + blend_cntl = (blend_cntl & ~R128_SBLEND_MASK) | R128_SBLEND_ONE; + else if ((blend_cntl & R128_SBLEND_MASK) == R128_SBLEND_INV_DST_ALPHA) + blend_cntl = (blend_cntl & ~R128_SBLEND_MASK) | R128_SBLEND_ZERO; + } + + R128WaitForFifo(pScrn, 21); + + OUTREG(R128_SCALE_3D_CNTL, + R128_SCALE_3D_TEXMAP_SHADE | + R128_SCALE_PIX_REPLICATE | + R128_TEX_CACHE_SPLIT | + R128_TEX_MAP_ALPHA_IN_TEXTURE | + R128_TEX_CACHE_LINE_SIZE_4QW); + OUTREG(R128_DST_PITCH_OFFSET, dst_pitch_offset); + OUTREG(R128_DP_GUI_MASTER_CNTL, + R128_GMC_DST_PITCH_OFFSET_CNTL | + R128_GMC_BRUSH_SOLID_COLOR | + (dstDatatype >> 8) | + R128_GMC_SRC_DATATYPE_COLOR | + (R128_ROP[3].rop << 16) | + R128_DP_SRC_SOURCE_MEMORY | + R128_GMC_3D_FCN_EN | + R128_GMC_CLR_CMP_CNTL_DIS | + R128_GMC_AUX_CLIP_DIS | + R128_GMC_WR_MSK_DIS); + OUTREG(R128_MISC_3D_STATE_CNTL_REG, + R128_MISC_SCALE_3D_TEXMAP_SHADE | + R128_MISC_SCALE_PIX_REPLICATE | + R128_ALPHA_COMB_ADD_CLAMP | + blend_cntl); + OUTREG(R128_TEX_CNTL_C, + R128_TEXMAP_ENABLE | + ((pMask != NULL) ? R128_SEC_TEXMAP_ENABLE : 0) | + R128_ALPHA_ENABLE | + R128_TEX_CACHE_FLUSH); + OUTREG(R128_PC_GUI_CTLSTAT, R128_PC_FLUSH_GUI); + + /* IN operator: Without a mask, only the first texture unit is enabled. + * With a mask, we put the source in the first unit and have it pass + * through as input to the 2nd. The 2nd unit takes the incoming source + * pixel and modulates it with either the alpha or each of the channels + * in the mask, depending on componentAlpha. + */ + OUTREG(0, CCE_PACKET0(R128_PRIM_TEX_CNTL_C, 13)); + OUTREG(0, prim_tex_cntl_c); + + /* If this is the only stage and the dest is a8, route the alpha result + * to the color (red channel, in particular), too. Otherwise, be sure + * to zero out color channels of an a8 source. + */ + if (pMaskPicture == NULL && pDstPicture->format == PICT_a8) + color_factor = R128_COLOR_FACTOR_ALPHA; + else if (pSrcPicture->format == PICT_a8) + color_factor = R128_COLOR_FACTOR_CONST_COLOR; + else + color_factor = R128_COLOR_FACTOR_TEX; + + if (PICT_FORMAT_A(pSrcPicture->format) == 0) + alpha_comb = R128_COMB_ALPHA_COPY_INP; + else + alpha_comb = R128_COMB_ALPHA_DIS; + + OUTREG(0, R128_COMB_COPY | + color_factor | + R128_INPUT_FACTOR_INT_COLOR | + alpha_comb | + R128_ALPHA_FACTOR_TEX_ALPHA | + R128_INP_FACTOR_A_CONST_ALPHA); + OUTREG(0, txsize); + /* We could save some output by only writing the offset register that + * will actually be used. On the other hand, this is easy. + */ + for (i = 0; i <= 10; i++) + OUTREG(0, ((CARD8 *)pSrc->devPrivate.ptr - info->ExaDriver->memoryBase)); + + if (pMask != NULL) { + R128WaitForFifo(pScrn, 14); + + OUTREG(0, CCE_PACKET0(R128_SEC_TEX_CNTL_C, 12)); + OUTREG(0, sec_tex_cntl_c); + + if (pDstPicture->format == PICT_a8) { + color_factor = R128_COLOR_FACTOR_ALPHA; + in_color_factor = R128_INPUT_FACTOR_PREV_ALPHA; + } else if (pMaskPicture->componentAlpha) { + color_factor = R128_COLOR_FACTOR_TEX; + in_color_factor = R128_INPUT_FACTOR_PREV_COLOR; + } else { + color_factor = R128_COLOR_FACTOR_ALPHA; + in_color_factor = R128_INPUT_FACTOR_PREV_COLOR; + } + + OUTREG(0, R128_COMB_MODULATE | + color_factor | + in_color_factor | + R128_COMB_ALPHA_MODULATE | + R128_ALPHA_FACTOR_TEX_ALPHA | + R128_INP_FACTOR_A_PREV_ALPHA); + for (i = 0; i <= 10; i++) + OUTREG(0, ((CARD8 *)pMask->devPrivate.ptr - info->ExaDriver->memoryBase)); + } + + return TRUE; +} + +static void +R128Composite(PixmapPtr pDst, int srcX, int srcY, int maskX, int maskY, int dstX, int dstY, int w, int h) +{ + ScreenPtr pScreen = pDst->drawable.pScreen; + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + R128InfoPtr info = R128PTR(pScrn); + unsigned char *R128MMIO = info->MMIO; + + int srcXend, srcYend, maskXend, maskYend; + PictVector v; + + srcXend = srcX + w; + srcYend = srcY + h; + maskXend = maskX + w; + maskYend = maskY + h; + if (is_transform[0]) { + v.vector[0] = IntToxFixed(srcX); + v.vector[1] = IntToxFixed(srcY); + v.vector[2] = xFixed1; + PictureTransformPoint(transform[0], &v); + srcX = xFixedToInt(v.vector[0]); + srcY = xFixedToInt(v.vector[1]); + v.vector[0] = IntToxFixed(srcXend); + v.vector[1] = IntToxFixed(srcYend); + v.vector[2] = xFixed1; + PictureTransformPoint(transform[0], &v); + srcXend = xFixedToInt(v.vector[0]); + srcYend = xFixedToInt(v.vector[1]); + } + if (is_transform[1]) { + v.vector[0] = IntToxFixed(maskX); + v.vector[1] = IntToxFixed(maskY); + v.vector[2] = xFixed1; + PictureTransformPoint(transform[1], &v); + maskX = xFixedToInt(v.vector[0]); + maskY = xFixedToInt(v.vector[1]); + v.vector[0] = IntToxFixed(maskXend); + v.vector[1] = IntToxFixed(maskYend); + v.vector[2] = xFixed1; + PictureTransformPoint(transform[1], &v); + maskXend = xFixedToInt(v.vector[0]); + maskYend = xFixedToInt(v.vector[1]); + } + + R128WaitForFifo(pScrn, 3 + 4 * VTX_RING_COUNT); + + OUTREG(0, CCE_PACKET3(R128_CCE_PACKET3_3D_RNDR_GEN_PRIM, 2 + 4 * VTX_RING_COUNT - 1)); + OUTREG(0, R128_CCE_VC_FRMT_RHW | + R128_CCE_VC_FRMT_S_T | + R128_CCE_VC_FRMT_S2_T2); + OUTREG(0, R128_CCE_VC_CNTL_PRIM_TYPE_TRI_FAN | + R128_CCE_VC_CNTL_PRIM_WALK_RING | + (4 << R128_CCE_VC_CNTL_NUM_SHIFT)); + + VTX_OUT(dstX, dstY, srcX, srcY, maskX, maskY); + VTX_OUT(dstX, dstY + h, srcX, srcYend, maskX, maskYend); + VTX_OUT(dstX + w, dstY + h, srcXend, srcYend, maskXend, maskYend); + VTX_OUT(dstX + w, dstY, srcXend, srcY, maskXend, maskY); +} + +#define R128DoneComposite R128Done +#endif + +static void +R128Sync(ScreenPtr pScreen, int marker) +{ + R128WaitForIdle(xf86Screens[pScreen->myNum]); +} + +static void +R128Done(PixmapPtr pPixmap) +{ + ScreenPtr pScreen = pPixmap->drawable.pScreen; + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + R128InfoPtr info = R128PTR(pScrn); + + info->state_2d.in_use = FALSE; +} + +#ifdef R128DRI + +#define R128CCEPrepareSolid R128PrepareSolid + +static void +R128CCESolid(PixmapPtr pPixmap, int x1, int y1, int x2, int y2) +{ + ScreenPtr pScreen = pPixmap->drawable.pScreen; + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + R128InfoPtr info = R128PTR(pScrn); + RING_LOCALS; + + R128CCE_REFRESH( pScrn, info ); + + BEGIN_RING( 4 ); + + OUT_RING_REG( R128_DST_Y_X, (y1 << 16) | x1 ); + OUT_RING_REG( R128_DST_WIDTH_HEIGHT, ((x2-x1) << 16) | (y2-y1) ); + + ADVANCE_RING(); +} + +#define R128CCEDoneSolid R128Done + +#define R128CCEPrepareCopy R128PrepareCopy + +static void +R128CCECopy(PixmapPtr pDstPixmap, int srcX, int srcY, int dstX, int dstY, + int width, int height) +{ + ScreenPtr pScreen = pDstPixmap->drawable.pScreen; + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + R128InfoPtr info = R128PTR(pScrn); + RING_LOCALS; + + R128CCE_REFRESH( pScrn, info ); + + if (info->xdir < 0) srcX += width - 1, dstX += width - 1; + if (info->ydir < 0) srcY += height - 1, dstY += height - 1; + + BEGIN_RING( 6 ); + + OUT_RING_REG( R128_SRC_Y_X, (srcY << 16) | srcX ); + OUT_RING_REG( R128_DST_Y_X, (dstY << 16) | dstX ); + OUT_RING_REG( R128_DST_HEIGHT_WIDTH, (height << 16) | width ); + + ADVANCE_RING(); +} + +#define R128CCEDoneCopy R128Done + +#ifdef RENDER +#define R128CCECheckComposite R128CheckComposite + +static Bool +R128CCEPrepareComposite(int op, PicturePtr pSrcPicture, PicturePtr pMaskPicture, + PicturePtr pDstPicture, PixmapPtr pSrc, PixmapPtr pMask, PixmapPtr pDst) +{ + ScreenPtr pScreen = pSrc->drawable.pScreen; + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + R128InfoPtr info = R128PTR(pScrn); + RING_LOCALS; + + uint32_t txsize = 0, prim_tex_cntl_c, sec_tex_cntl_c = 0, dstDatatype; + uint32_t dst_pitch_offset, color_factor, in_color_factor, alpha_comb; + uint32_t blend_cntl; + int i; + + if (pDstPicture->format == PICT_a8) { + if (R128BlendOp[op].dst_alpha) { + R128TRACE(("Can't dst alpha blend A8\n")); + return FALSE; + } + dstDatatype = R128_DATATYPE_Y8; + } else { + if (!R128GetDatatypePict1(pDstPicture->format, &dstDatatype)) return FALSE; + } + + if (!R128TextureSetup(pSrcPicture, pSrc, 0, &txsize, &prim_tex_cntl_c)) return FALSE; + + if (pMask != NULL) { + if (!R128TextureSetup(pMaskPicture, pMask, 1, &txsize, &sec_tex_cntl_c)) return FALSE; + } else { + is_transform[1] = FALSE; + } + + if (!R128GetPixmapOffsetPitch(pDst, &dst_pitch_offset)) return FALSE; + + info->state_2d.in_use = TRUE; + blend_cntl = R128BlendOp[op].blendctl; + if (PICT_FORMAT_A(pDstPicture->format) == 0 && R128BlendOp[op].dst_alpha) { + if ((blend_cntl & R128_SBLEND_MASK) == R128_SBLEND_DST_ALPHA) + blend_cntl = (blend_cntl & ~R128_SBLEND_MASK) | R128_SBLEND_ONE; + else if ((blend_cntl & R128_SBLEND_MASK) == R128_SBLEND_INV_DST_ALPHA) + blend_cntl = (blend_cntl & ~R128_SBLEND_MASK) | R128_SBLEND_ZERO; + } + + R128CCE_REFRESH( pScrn, info ); + BEGIN_RING( 12 ); + + OUT_RING_REG(R128_SCALE_3D_CNTL, + R128_SCALE_3D_TEXMAP_SHADE | + R128_SCALE_PIX_REPLICATE | + R128_TEX_CACHE_SPLIT | + R128_TEX_MAP_ALPHA_IN_TEXTURE | + R128_TEX_CACHE_LINE_SIZE_4QW); + OUT_RING_REG(R128_DST_PITCH_OFFSET, dst_pitch_offset); + OUT_RING_REG(R128_DP_GUI_MASTER_CNTL, + R128_GMC_DST_PITCH_OFFSET_CNTL | + R128_GMC_BRUSH_SOLID_COLOR | + (dstDatatype >> 8) | + R128_GMC_SRC_DATATYPE_COLOR | + (R128_ROP[3].rop << 16) | + R128_DP_SRC_SOURCE_MEMORY | + R128_GMC_3D_FCN_EN | + R128_GMC_CLR_CMP_CNTL_DIS | + R128_GMC_AUX_CLIP_DIS | + R128_GMC_WR_MSK_DIS); + OUT_RING_REG(R128_MISC_3D_STATE_CNTL_REG, + R128_MISC_SCALE_3D_TEXMAP_SHADE | + R128_MISC_SCALE_PIX_REPLICATE | + R128_ALPHA_COMB_ADD_CLAMP | + blend_cntl); + OUT_RING_REG(R128_TEX_CNTL_C, + R128_TEXMAP_ENABLE | + ((pMask != NULL) ? R128_SEC_TEXMAP_ENABLE : 0) | + R128_ALPHA_ENABLE | + R128_TEX_CACHE_FLUSH); + OUT_RING_REG(R128_PC_GUI_CTLSTAT, R128_PC_FLUSH_GUI); + ADVANCE_RING(); + + /* IN operator: Without a mask, only the first texture unit is enabled. + * With a mask, we put the source in the first unit and have it pass + * through as input to the 2nd. The 2nd unit takes the incoming source + * pixel and modulates it with either the alpha or each of the channels + * in the mask, depending on componentAlpha. + */ + BEGIN_RING( 15 ); + /* R128_REG_PRIM_TEX_CNTL_C, + * R128_REG_PRIM_TEXTURE_COMBINE_CNTL_C, + * R128_REG_TEX_SIZE_PITCH_C, + * R128_REG_PRIM_TEX_0_OFFSET_C - R128_REG_PRIM_TEX_10_OFFSET_C + */ + OUT_RING(CCE_PACKET0(R128_PRIM_TEX_CNTL_C, 13)); + OUT_RING(prim_tex_cntl_c); + + /* If this is the only stage and the dest is a8, route the alpha result + * to the color (red channel, in particular), too. Otherwise, be sure + * to zero out color channels of an a8 source. + */ + if (pMaskPicture == NULL && pDstPicture->format == PICT_a8) + color_factor = R128_COLOR_FACTOR_ALPHA; + else if (pSrcPicture->format == PICT_a8) + color_factor = R128_COLOR_FACTOR_CONST_COLOR; + else + color_factor = R128_COLOR_FACTOR_TEX; + + if (PICT_FORMAT_A(pSrcPicture->format) == 0) + alpha_comb = R128_COMB_ALPHA_COPY_INP; + else + alpha_comb = R128_COMB_ALPHA_DIS; + + OUT_RING(R128_COMB_COPY | + color_factor | + R128_INPUT_FACTOR_INT_COLOR | + alpha_comb | + R128_ALPHA_FACTOR_TEX_ALPHA | + R128_INP_FACTOR_A_CONST_ALPHA); + OUT_RING(txsize); + /* We could save some output by only writing the offset register that + * will actually be used. On the other hand, this is easy. + */ + for (i = 0; i <= 10; i++) + OUT_RING(((CARD8 *)pSrc->devPrivate.ptr - info->ExaDriver->memoryBase)); + ADVANCE_RING(); + + if (pMask != NULL) { + BEGIN_RING( 14 ); + /* R128_REG_SEC_TEX_CNTL_C, + * R128_REG_SEC_TEXTURE_COMBINE_CNTL_C, + * R128_REG_SEC_TEX_0_OFFSET_C - R128_REG_SEC_TEX_10_OFFSET_C + */ + + OUT_RING(CCE_PACKET0(R128_SEC_TEX_CNTL_C, 12)); + OUT_RING(sec_tex_cntl_c); + + if (pDstPicture->format == PICT_a8) { + color_factor = R128_COLOR_FACTOR_ALPHA; + in_color_factor = R128_INPUT_FACTOR_PREV_ALPHA; + } else if (pMaskPicture->componentAlpha) { + color_factor = R128_COLOR_FACTOR_TEX; + in_color_factor = R128_INPUT_FACTOR_PREV_COLOR; + } else { + color_factor = R128_COLOR_FACTOR_ALPHA; + in_color_factor = R128_INPUT_FACTOR_PREV_COLOR; + } + + OUT_RING(R128_COMB_MODULATE | + color_factor | + in_color_factor | + R128_COMB_ALPHA_MODULATE | + R128_ALPHA_FACTOR_TEX_ALPHA | + R128_INP_FACTOR_A_PREV_ALPHA); + for (i = 0; i <= 10; i++) + OUT_RING(((CARD8 *)pMask->devPrivate.ptr - info->ExaDriver->memoryBase)); + + ADVANCE_RING(); + } + + return TRUE; +} + +static void +R128CCEComposite(PixmapPtr pDst, int srcX, int srcY, int maskX, int maskY, int dstX, int dstY, int w, int h) +{ + ScreenPtr pScreen = pDst->drawable.pScreen; + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + R128InfoPtr info = R128PTR(pScrn); + RING_LOCALS; + + int srcXend, srcYend, maskXend, maskYend; + PictVector v; + + srcXend = srcX + w; + srcYend = srcY + h; + maskXend = maskX + w; + maskYend = maskY + h; + if (is_transform[0]) { + v.vector[0] = IntToxFixed(srcX); + v.vector[1] = IntToxFixed(srcY); + v.vector[2] = xFixed1; + PictureTransformPoint(transform[0], &v); + srcX = xFixedToInt(v.vector[0]); + srcY = xFixedToInt(v.vector[1]); + v.vector[0] = IntToxFixed(srcXend); + v.vector[1] = IntToxFixed(srcYend); + v.vector[2] = xFixed1; + PictureTransformPoint(transform[0], &v); + srcXend = xFixedToInt(v.vector[0]); + srcYend = xFixedToInt(v.vector[1]); + } + if (is_transform[1]) { + v.vector[0] = IntToxFixed(maskX); + v.vector[1] = IntToxFixed(maskY); + v.vector[2] = xFixed1; + PictureTransformPoint(transform[1], &v); + maskX = xFixedToInt(v.vector[0]); + maskY = xFixedToInt(v.vector[1]); + v.vector[0] = IntToxFixed(maskXend); + v.vector[1] = IntToxFixed(maskYend); + v.vector[2] = xFixed1; + PictureTransformPoint(transform[1], &v); + maskXend = xFixedToInt(v.vector[0]); + maskYend = xFixedToInt(v.vector[1]); + } + + R128CCE_REFRESH( pScrn, info ); + BEGIN_RING( 3 + 4 * VTX_RING_COUNT ); + + OUT_RING(CCE_PACKET3(R128_CCE_PACKET3_3D_RNDR_GEN_PRIM, 2 + 4 * VTX_RING_COUNT - 1)); + OUT_RING(R128_CCE_VC_FRMT_RHW | + R128_CCE_VC_FRMT_S_T | + R128_CCE_VC_FRMT_S2_T2); + OUT_RING(R128_CCE_VC_CNTL_PRIM_TYPE_TRI_FAN | + R128_CCE_VC_CNTL_PRIM_WALK_RING | + (4 << R128_CCE_VC_CNTL_NUM_SHIFT)); + + VTX_CCE_OUT(dstX, dstY, srcX, srcY, maskX, maskY); + VTX_CCE_OUT(dstX, dstY + h, srcX, srcYend, maskX, maskYend); + VTX_CCE_OUT(dstX + w, dstY + h, srcXend, srcYend, maskXend, maskYend); + VTX_CCE_OUT(dstX + w, dstY, srcXend, srcY, maskXend, maskY); + + ADVANCE_RING(); +} + +#define R128CCEDoneComposite R128Done +#endif + +static void +R128CCESync(ScreenPtr pScreen, int marker) +{ + R128CCEWaitForIdle(xf86Screens[pScreen->myNum]); +} +#endif + +Bool +R128EXAInit(ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + R128InfoPtr info = R128PTR(pScrn); + + info->ExaDriver->exa_major = EXA_VERSION_MAJOR; + info->ExaDriver->exa_minor = EXA_VERSION_MINOR; + + info->ExaDriver->memoryBase = info->FB + pScrn->fbOffset; + info->ExaDriver->flags = EXA_OFFSCREEN_PIXMAPS | EXA_OFFSCREEN_ALIGN_POT; + +#if EXA_VERSION_MAJOR > 2 || (EXA_VERSION_MAJOR == 2 && EXA_VERSION_MINOR >= 3) + info->ExaDriver->maxPitchBytes = 16320; +#endif + /* Pitch alignment is in sets of 8 pixels, and we need to cover 32bpp, so it's 32 bytes */ + info->ExaDriver->pixmapPitchAlign = 32; + info->ExaDriver->pixmapOffsetAlign = 32; + info->ExaDriver->maxX = 2048; + info->ExaDriver->maxY = 2048; + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Setting up EXA callbacks\n"); + +#ifdef R128DRI + if (info->directRenderingEnabled) { + info->ExaDriver->PrepareSolid = R128CCEPrepareSolid; + info->ExaDriver->Solid = R128CCESolid; + info->ExaDriver->DoneSolid = R128CCEDoneSolid; + + info->ExaDriver->PrepareCopy = R128CCEPrepareCopy; + info->ExaDriver->Copy = R128CCECopy; + info->ExaDriver->DoneCopy = R128CCEDoneCopy; + +#ifdef RENDER + info->ExaDriver->CheckComposite = R128CCECheckComposite; + info->ExaDriver->PrepareComposite = R128CCEPrepareComposite; + info->ExaDriver->Composite = R128CCEComposite; + info->ExaDriver->DoneComposite = R128CCEDoneComposite; +#endif + + info->ExaDriver->WaitMarker = R128CCESync; + } else +#endif + { + info->ExaDriver->PrepareSolid = R128PrepareSolid; + info->ExaDriver->Solid = R128Solid; + info->ExaDriver->DoneSolid = R128DoneSolid; + + info->ExaDriver->PrepareCopy = R128PrepareCopy; + info->ExaDriver->Copy = R128Copy; + info->ExaDriver->DoneCopy = R128DoneCopy; + +#ifdef RENDER + info->ExaDriver->CheckComposite = R128CheckComposite; + info->ExaDriver->PrepareComposite = R128PrepareComposite; + info->ExaDriver->Composite = R128Composite; + info->ExaDriver->DoneComposite = R128DoneComposite; +#endif + + info->ExaDriver->WaitMarker = R128Sync; + } + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Initalizing 2D acceleration engine...\n"); + + R128EngineInit(pScrn); + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Initializing EXA driver...\n"); + + if (!exaDriverInit(pScreen, info->ExaDriver)) { + free(info->ExaDriver); + return FALSE; + } + exaMarkSync(pScreen); + + return TRUE; +} diff --git a/src/r128_reg.h b/src/r128_reg.h index dac22e6..bb964a5 100644 --- a/src/r128_reg.h +++ b/src/r128_reg.h @@ -1522,6 +1522,33 @@ #define R128_CCE_VC_CNTL_PRIM_WALK_RING 0x00000030 #define R128_CCE_VC_CNTL_NUM_SHIFT 16 +# define R128_SBLEND_ZERO (0 << 16) +# define R128_SBLEND_ONE (1 << 16) +# define R128_SBLEND_SRCCOLOR (2 << 16) +# define R128_SBLEND_INVSRCCOLOR (3 << 16) +# define R128_SBLEND_SRC_ALPHA (4 << 16) +# define R128_SBLEND_INV_SRC_ALPHA (5 << 16) +# define R128_SBLEND_DST_ALPHA (6 << 16) +# define R128_SBLEND_INV_DST_ALPHA (7 << 16) +# define R128_SBLEND_DSTCOLOR (8 << 16) +# define R128_SBLEND_INVDSTCOLOR (9 << 16) +# define R128_SBLEND_SRC_ALPHASAT (10 << 16) +# define R128_SBLEND_BOTHSRC_ALPHA (11 << 16) +# define R128_SBLEND_BOTHINV_SRC_ALPHA (12 << 16) +# define R128_SBLEND_MASK (15 << 16) +# define R128_DBLEND_ZERO (0 << 20) +# define R128_DBLEND_ONE (1 << 20) +# define R128_DBLEND_SRCCOLOR (2 << 20) +# define R128_DBLEND_INVSRCCOLOR (3 << 20) +# define R128_DBLEND_SRC_ALPHA (4 << 20) +# define R128_DBLEND_INV_SRC_ALPHA (5 << 20) +# define R128_DBLEND_DST_ALPHA (6 << 20) +# define R128_DBLEND_INV_DST_ALPHA (7 << 20) +# define R128_DBLEND_DSTCOLOR (8 << 20) +# define R128_DBLEND_INVDSTCOLOR (9 << 20) +# define R128_DBLEND_SRC_ALPHASAT (10 << 20) +# define R128_DBLEND_MASK (15 << 20) + /* hmm copyed blindly (no specs) from radeon.h ... */ #define R128_RE_TOP_LEFT 0x26c0 # define R128_RE_LEFT_SHIFT 0 diff --git a/src/r128_video.c b/src/r128_video.c index 11bb9bd..3939d65 100644 --- a/src/r128_video.c +++ b/src/r128_video.c @@ -56,7 +56,8 @@ typedef struct { int saturation; Bool doubleBuffer; unsigned char currentBuffer; - FBLinearPtr linear; + void* BufferHandle; + int videoOffset; RegionRec clip; CARD32 colorKey; CARD32 videoStatus; @@ -270,9 +271,16 @@ R128StopVideo(ScrnInfoPtr pScrn, pointer data, Bool cleanup) if(pPriv->videoStatus & CLIENT_VIDEO_ON) { OUTREG(R128_OV0_SCALE_CNTL, 0); } - if(pPriv->linear) { - xf86FreeOffscreenLinear(pPriv->linear); - pPriv->linear = NULL; + if(pPriv->BufferHandle) { + if (!info->useEXA) { + xf86FreeOffscreenLinear((FBLinearPtr) pPriv->BufferHandle); + } +#ifdef USE_EXA + else { + exaOffscreenFree(pScrn->pScreen, (ExaOffscreenArea *) pPriv->BufferHandle); + } +#endif + pPriv->BufferHandle = NULL; } pPriv->videoStatus = 0; } else { @@ -564,45 +572,78 @@ R128CopyData420( } -static FBLinearPtr +static CARD32 R128AllocateMemory( ScrnInfoPtr pScrn, - FBLinearPtr linear, + void **mem_struct, int size ){ - ScreenPtr pScreen; - FBLinearPtr new_linear; + R128InfoPtr info = R128PTR(pScrn); + ScreenPtr pScreen = screenInfo.screens[pScrn->scrnIndex];; + int offset = 0; - if(linear) { - if(linear->size >= size) - return linear; + if(!info->useEXA) { + FBLinearPtr linear = *mem_struct; + int cpp = info->CurrentLayout.pixel_bytes; + + /* XAA allocates in units of pixels at the screen bpp, so adjust size appropriately. */ + size = (size + cpp - 1) / cpp; + + if(linear) { + if(linear->size >= size) + return linear->offset * cpp; - if(xf86ResizeOffscreenLinear(linear, size)) - return linear; + if(xf86ResizeOffscreenLinear(linear, size)) + return linear->offset * cpp; - xf86FreeOffscreenLinear(linear); - } + xf86FreeOffscreenLinear(linear); + } - pScreen = screenInfo.screens[pScrn->scrnIndex]; - new_linear = xf86AllocateOffscreenLinear(pScreen, size, 8, + linear = xf86AllocateOffscreenLinear(pScreen, size, 8, NULL, NULL, NULL); + *mem_struct = linear; - if(!new_linear) { - int max_size; + if(!linear) { + int max_size; - xf86QueryLargestOffscreenLinear(pScreen, &max_size, 8, + xf86QueryLargestOffscreenLinear(pScreen, &max_size, 8, PRIORITY_EXTREME); - if(max_size < size) - return NULL; + if(max_size < size) + return NULL; - xf86PurgeUnlockedOffscreenAreas(pScreen); - new_linear = xf86AllocateOffscreenLinear(pScreen, size, 8, + xf86PurgeUnlockedOffscreenAreas(pScreen); + linear = xf86AllocateOffscreenLinear(pScreen, size, 8, NULL, NULL, NULL); + + if(!linear) return 0; + } + + offset = linear->offset * cpp; + } +#ifdef USE_EXA + else { + /* EXA support based on mga driver */ + ExaOffscreenArea *area = *mem_struct; + + if(area) { + if(area->size >= size) + return area->offset; + + exaOffscreenFree(pScrn->pScreen, area); + } + + area = exaOffscreenAlloc(pScrn->pScreen, size, 64, TRUE, NULL, NULL); + *mem_struct = area; + + if(!area) return 0; + + offset = area->offset; } +#endif - return new_linear; + return offset; } static void @@ -841,7 +882,7 @@ R128PutImage( srcPitch = (width + 3) & ~3; srcPitch2 = ((width >> 1) + 3) & ~3; dstPitch = (width + 31) & ~31; /* of luma */ - new_size = ((dstPitch * (height + (height >> 1))) + bpp - 1) / bpp; + new_size = dstPitch * (height + (height >> 1)); s1offset = 0; s2offset = srcPitch * height; s3offset = (srcPitch2 * (height >> 1)) + s2offset; @@ -852,14 +893,14 @@ R128PutImage( srcPitch = width << 1; srcPitch2 = 0; dstPitch = ((width << 1) + 15) & ~15; - new_size = ((dstPitch * height) + bpp - 1) / bpp; + new_size = dstPitch * height; s1offset = 0; s2offset = 0; s3offset = 0; break; } - if(!(pPriv->linear = R128AllocateMemory(pScrn, pPriv->linear, + if(!(pPriv->videoOffset = R128AllocateMemory(pScrn, &(pPriv->BufferHandle), pPriv->doubleBuffer ? (new_size << 1) : new_size))) { return BadAlloc; @@ -872,9 +913,9 @@ R128PutImage( left = (xa >> 16) & ~1; npixels = ((((xb + 0xffff) >> 16) + 1) & ~1) - left; - offset = pPriv->linear->offset * bpp; + offset = pPriv->videoOffset; if(pPriv->doubleBuffer) - offset += pPriv->currentBuffer * new_size * bpp; + offset += pPriv->currentBuffer * new_size; switch(id) { case FOURCC_YV12: @@ -1015,9 +1056,16 @@ R128VideoTimerCallback(ScrnInfoPtr pScrn, Time now) } } else { /* FREE_TIMER */ if(pPriv->freeTime < now) { - if(pPriv->linear) { - xf86FreeOffscreenLinear(pPriv->linear); - pPriv->linear = NULL; + if(pPriv->BufferHandle) { + if (!info->useEXA) { + xf86FreeOffscreenLinear((FBLinearPtr) pPriv->BufferHandle); + } +#ifdef USE_EXA + else { + exaOffscreenAreaFree(pScrn->pScreen, (ExaOffscreenArea *) pPriv->BufferHandle); + } +#endif + pPriv->BufferHandle = NULL; } pPriv->videoStatus = 0; info->VideoTimerCallback = NULL; -- 1.7.10