/* * Copyright 2006 George Sapountzis * All Rights Reserved. * * Based on the mach64 DRI and DRM drivers: * Copyright 2000 Gareth Hughes * Copyright 2002-2003 Leif Delgass * All Rights Reserved. * * Based on the ati hw/kdrive driver: * Copyright 2003 Eric Anholt, Anders Carlsson * * Based on the via hw/xfree86 driver: * Copyright 2006 Thomas Hellstrom. 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: * George Sapountzis */ /* * Interesting cases for RENDER acceleration: * * cursor : ARGB8888 (24x24) Over * RGB565 * * glyph : A8 (9x10) Add * A8 (420x13) * glyph set : ARGB8888 (1x1 R) In * A8 (420x13) Over * RGB565 * * shadow : ARGB8888 (1x1 R) In * A8 (670x362) Over * RGB565 * translucent : RGB565 (652x344) In * A8 (1x1 R) Over * RGB565 * * In all interesting cases one of src/mask is "1x1 R". */ /* * Assumptions and limitations of mach64 RENDER acceleration: * * RENDER acceleration is supported for GTPRO and later chips using the 3D * triangle setup, i.e. the VERTEX_? registers (see the dri driver). According * to atiregs.h, SCALE_3D_CNTL and TEX_?_OFF appear in GT, thus chips as old * as GT should be capable of RENDER acceleration, using the S_?_INC, T_?_INC * registers for texture mapping (see the directfb driver). * * GTPRO added a triangle setup engine and multitexturing. However, it seems * that none of the 8bpp mach64 formats expands the 8bit value to the alpha * channel in texture mapping, RGB8 appears to expand to (I,I,I,0). This makes * GTPRO multitexturing unsuitable for emulating the IN operation. Moreover, * it seems that GT/GTPRO has a muxltiplexer instead of a blender for computing * the final alpha channel which forbids destinations with an alpha channel and * generic two-pass compositing. * * A texture unit combines the fragment color (VERTEX_?_ARGB) coming in from * triangle rasterization with the texel from the texture according to the * texture environment (TEX_LIGHT_FCN_). "1x1 R" textures may come in as frag- * ment colors, eliminating the need for multitexturing in all interesting * cases (via also uses this optimization). * * Texture registers are saved/restored and cached (see atimach64.c). TEX_CNTL * cannot be cached because it flushes the texture cache. TEX_?_OFF are also * not cached because I am not sure whether writing at some offset register * affects the value at another offset. * * Vertex registers are not saved/restored. This shouldn't be a problem though * either for DRI or VT switch because vertex registers are set and used within * a signle acceleration hook. Synchronization between the DDX and DRI is based * on calling ATIDRISync() at the beginning of each DDX acceleration hook, * which suggests the assumption that individual acceleration hooks are not * interrupted. */ #include #include /* * Helper functions copied from exa and via. */ #if 0 static void Mach64ExaCompositePictDesc(PicturePtr pict, char *string, int n) { char format[20]; char size[20]; if (!pict) { snprintf(string, n, "None"); return; } switch (pict->format) { case PICT_x8r8g8b8: snprintf(format, 20, "RGB8888 "); break; case PICT_x8b8g8r8: snprintf(format, 20, "BGR8888 "); break; case PICT_a8r8g8b8: snprintf(format, 20, "ARGB8888"); break; case PICT_a8b8g8r8: snprintf(format, 20, "ABGR8888"); break; case PICT_r5g6b5: snprintf(format, 20, "RGB565 "); break; case PICT_x1r5g5b5: snprintf(format, 20, "RGB555 "); break; case PICT_a8: snprintf(format, 20, "A8 "); break; case PICT_a1: snprintf(format, 20, "A1 "); break; default: snprintf(format, 20, "0x%x", (int)pict->format); break; } snprintf(size, 20, "%dx%d%s%s", pict->pDrawable->width, pict->pDrawable->height, pict->repeat ? " R" : "", pict->componentAlpha ? " C" : "" ); snprintf(string, n, "%-10p: fmt %s (%s)", (void *)pict->pDrawable, format, size); } static void Mach64ExaPrintComposite(CARD8 op, PicturePtr pSrc, PicturePtr pMask, PicturePtr pDst, char *string) { char sop[20]; char srcdesc[40], maskdesc[40], dstdesc[40]; switch (op) { case PictOpSrc: sprintf(sop, "Src"); break; case PictOpOver: sprintf(sop, "Over"); break; case PictOpInReverse: sprintf(sop, "InR"); break; case PictOpOutReverse: sprintf(sop, "OutR"); break; case PictOpAdd: sprintf(sop, "Add"); break; default: sprintf(sop, "0x%x", (int)op); break; } Mach64ExaCompositePictDesc(pSrc, srcdesc, 40); Mach64ExaCompositePictDesc(pMask, maskdesc, 40); Mach64ExaCompositePictDesc(pDst, dstdesc, 40); sprintf(string, "op %s, \n" " src %s\n" " mask %s\n" " dst %s\n", sop, srcdesc, maskdesc, dstdesc); } #endif static __inline__ CARD32 viaBitExpandHelper(CARD32 component, CARD32 bits) { CARD32 tmp, mask; mask = (1 << (8 - bits)) - 1; tmp = component << (8 - bits); return ((component & 1) ? tmp | mask : tmp); } static __inline__ void Mach64PixelARGB(PixmapPtr pPixmap, CARD32 format, CARD32 *argb) { CARD32 pixel; CARD8 comp; int bits, shift; /* Ensure that texture drawing has completed. */ exaWaitSync(pPixmap->drawable.pScreen); /* exaGetPixmapFirstPixel() */ switch (pPixmap->drawable.bitsPerPixel) { case 32: pixel = *(CARD32 *)(pPixmap->devPrivate.ptr); break; case 16: pixel = *(CARD16 *)(pPixmap->devPrivate.ptr); break; default: pixel = *(CARD8 *)(pPixmap->devPrivate.ptr); break; } /* exaGetRGBAFromPixel()/viaPixelARGB8888() */ switch (PICT_FORMAT_TYPE(format)) { case PICT_TYPE_A: shift = 0; bits = PICT_FORMAT_A(format); comp = (pixel >> shift) & ((1 << bits) - 1); comp = viaBitExpandHelper(comp, bits); *argb = comp << 24; break; case PICT_TYPE_ARGB: shift = 0; bits = PICT_FORMAT_B(format); comp = (pixel >> shift) & ((1 << bits) - 1); comp = viaBitExpandHelper(comp, bits); *argb = comp; shift += bits; bits = PICT_FORMAT_G(format); comp = (pixel >> shift) & ((1 << bits) - 1); comp = viaBitExpandHelper(comp, bits); *argb |= comp << 8; shift += bits; bits = PICT_FORMAT_R(format); comp = (pixel >> shift) & ((1 << bits) - 1); comp = viaBitExpandHelper(comp, bits); *argb |= comp << 16; shift += bits; bits = PICT_FORMAT_A(format); if (bits) { comp = (pixel >> shift) & ((1 << bits) - 1); comp = viaBitExpandHelper(comp, bits); } else { comp = 0xff; } *argb |= comp << 24; break; case PICT_TYPE_ABGR: break; default: break; } } /* * RENDER acceleration for mach64 */ typedef struct { Bool supported; CARD32 scale_3d_cntl; } Mach64BlendOp; static Mach64BlendOp Mach64BlendOps[] = { /* Clear */ {1, MACH64_ALPHA_BLEND_SRC_ZERO | MACH64_ALPHA_BLEND_DST_ZERO}, /* Src */ {1, MACH64_ALPHA_BLEND_SRC_ONE | MACH64_ALPHA_BLEND_DST_ZERO}, /* Dst */ {1, MACH64_ALPHA_BLEND_SRC_ZERO | MACH64_ALPHA_BLEND_DST_ONE}, /* Over */ {1, MACH64_ALPHA_BLEND_SRC_ONE | MACH64_ALPHA_BLEND_DST_INVSRCALPHA}, /* OverReverse */ {1, MACH64_ALPHA_BLEND_SRC_INVDSTALPHA | MACH64_ALPHA_BLEND_DST_ONE}, /* In */ {1, MACH64_ALPHA_BLEND_SRC_DSTALPHA | MACH64_ALPHA_BLEND_DST_ZERO}, /* InReverse */ {1, MACH64_ALPHA_BLEND_SRC_ZERO | MACH64_ALPHA_BLEND_DST_SRCALPHA}, /* Out */ {1, MACH64_ALPHA_BLEND_SRC_INVDSTALPHA | MACH64_ALPHA_BLEND_DST_ZERO}, /* OutReverse */ {1, MACH64_ALPHA_BLEND_SRC_ZERO | MACH64_ALPHA_BLEND_DST_INVSRCALPHA}, /* Atop */ {0, MACH64_ALPHA_BLEND_SRC_DSTALPHA | MACH64_ALPHA_BLEND_DST_INVSRCALPHA}, /* AtopReverse */ {0, MACH64_ALPHA_BLEND_SRC_INVDSTALPHA | MACH64_ALPHA_BLEND_DST_SRCALPHA}, /* Xor */ {1, MACH64_ALPHA_BLEND_SRC_INVDSTALPHA | MACH64_ALPHA_BLEND_DST_INVSRCALPHA}, /* Add */ {1, MACH64_ALPHA_BLEND_SRC_ONE | MACH64_ALPHA_BLEND_DST_ONE} }; #define MACH64_NR_BLEND_OPS \ (sizeof(Mach64BlendOps) / sizeof(Mach64BlendOps[0])) typedef struct { CARD32 pictFormat; CARD32 dstFormat; CARD32 texFormat; } Mach64TexFormat; static Mach64TexFormat Mach64TexFormats[] = { {PICT_a8r8g8b8, -1, MACH64_DATATYPE_ARGB8888}, {PICT_x8r8g8b8, MACH64_DATATYPE_ARGB8888, MACH64_DATATYPE_ARGB8888}, {PICT_a1r5g5b5, -1, MACH64_DATATYPE_ARGB1555}, {PICT_x1r5g5b5, MACH64_DATATYPE_ARGB1555, MACH64_DATATYPE_ARGB1555}, {PICT_r5g6b5, MACH64_DATATYPE_RGB565, MACH64_DATATYPE_RGB565 }, {PICT_a8, MACH64_DATATYPE_RGB8, MACH64_DATATYPE_RGB8 } }; #define MACH64_NR_TEX_FORMATS \ (sizeof(Mach64TexFormats) / sizeof(Mach64TexFormats[0])) #define MACH64_PICT_IS_1x1R(_pPict) \ ((_pPict) && \ (_pPict)->pDrawable->width == 1 && \ (_pPict)->pDrawable->height == 1 && \ (_pPict)->repeat) /* * CheckComposite hook helper functions. */ static __inline__ Bool Mach64GetOrder(int val, int *shift) { *shift = 0; while (val > (1 << *shift)) (*shift)++; return (val == (1 << *shift)); } static Bool Mach64CheckTexture(PicturePtr pPict) { int w = pPict->pDrawable->width; int h = pPict->pDrawable->height; int l2w, l2h, level, i; for (i = 0; i < MACH64_NR_TEX_FORMATS; i++) { if (Mach64TexFormats[i].pictFormat == pPict->format) break; } if (i == MACH64_NR_TEX_FORMATS) MACH64_FALLBACK(("Unsupported picture format 0x%x\n", (int)pPict->format)); /* l2w equals l2p (pitch) for all interesting cases (w >= 64) */ Mach64GetOrder(w, &l2w); Mach64GetOrder(h, &l2h); level = (l2w > l2h) ? l2w : l2h; if (level > 10) MACH64_FALLBACK(("Picture w/h too large (%dx%d)\n", w, h)); return TRUE; } /* * CheckComposite acceleration hook. */ Bool Mach64CheckComposite ( int op, PicturePtr pSrcPicture, PicturePtr pMaskPicture, PicturePtr pDstPicture ) { Bool src_solid, mask_solid, mask_comp, op_comp; int i; if (op >= MACH64_NR_BLEND_OPS || !Mach64BlendOps[op].supported) return FALSE; if (!Mach64CheckTexture(pSrcPicture)) return FALSE; if (pMaskPicture && !Mach64CheckTexture(pMaskPicture)) return FALSE; /* Check destination format */ for (i = 0; i < MACH64_NR_TEX_FORMATS; i++) { if (Mach64TexFormats[i].pictFormat == pDstPicture->format) break; } if (i == MACH64_NR_TEX_FORMATS || Mach64TexFormats[i].dstFormat == -1) MACH64_FALLBACK(("Unsupported dst format 0x%x\n", (int)pDstPicture->format)); /* Check that A8 src/dst appears only as "A8 ADD A8" */ if (pDstPicture->format == PICT_a8) { if (pMaskPicture || pSrcPicture->format != PICT_a8 || op != PictOpAdd) MACH64_FALLBACK(("A8 dst with mask or non-A8 src.\n")); } if (pDstPicture->format != PICT_a8) { if (pSrcPicture->format == PICT_a8) MACH64_FALLBACK(("A8 src with non-A8 dst.\n")); } /* Check that one of src/mask can come in as the fragment color. */ src_solid = MACH64_PICT_IS_1x1R(pSrcPicture); mask_solid = MACH64_PICT_IS_1x1R(pMaskPicture); mask_comp = pMaskPicture && pMaskPicture->componentAlpha; op_comp = op == PictOpAdd || op == PictOpInReverse || op == PictOpOutReverse; if (mask_solid && src_solid) MACH64_FALLBACK(("Bad one-pixel IN composite operation.\n")); if (pMaskPicture) { if (!mask_solid && !src_solid) MACH64_FALLBACK(("Multitexturing required.\n")); if (!mask_solid && !op_comp) MACH64_FALLBACK(("Non-solid mask.\n")); if (mask_comp && !src_solid) MACH64_FALLBACK(("Component-alpha mask.\n")); if (!mask_comp && pMaskPicture->format != PICT_a8) MACH64_FALLBACK(("Non-A8 mask.\n")); if (mask_comp && pMaskPicture->format != PICT_a8r8g8b8) MACH64_FALLBACK(("Non-ARGB mask.\n")); } return TRUE; } /* * This function setups the fragment color from a solid pixmap in the presence * of a mask. */ static __inline__ Bool Mach64PrepareMask ( Mach64ContextRegs3D *m3d, int op, PicturePtr pSrcPicture, PicturePtr pMaskPicture, PixmapPtr pSrc, PixmapPtr pMask ) { Bool mask_solid, src_solid; CARD32 argb = 0; mask_solid = MACH64_PICT_IS_1x1R(pMaskPicture); src_solid = MACH64_PICT_IS_1x1R(pSrcPicture); if (mask_solid) { Mach64PixelARGB(pMask, pMaskPicture->format, &argb); argb >>= 24; argb &= 0xff; m3d->frag_mask = TRUE; m3d->frag_color = (argb << 24) | (argb << 16) | (argb << 8) | argb; return TRUE; } if (src_solid) { /* We can only handle cases where either the src color (e.g. ADD) or * the src alpha (e.g. IN_REV, OUT_REV) is used but not both. * * (ARGB8888 IN A8) OVER RGB565 is implemented as: * (ARGB8888 IN A8) ADD ((ARGB8888 IN A8) OUT_REV RGB565). */ if (op == PictOpInReverse || op == PictOpOutReverse) { Mach64PixelARGB(pSrc, pSrcPicture->format, &argb); argb >>= 24; argb &= 0xff; m3d->frag_src = TRUE; m3d->frag_color = (argb << 24) | (argb << 16) | (argb << 8) | argb; m3d->color_alpha = TRUE; return TRUE; } if (op == PictOpAdd) { Mach64PixelARGB(pSrc, pSrcPicture->format, &argb); m3d->frag_src = TRUE; m3d->frag_color = argb; return TRUE; } } return FALSE; } /* * This function setups the texturing and blending environments. It also * manipulates blend control for non-solid masks. */ static void __inline__ Mach64BlendCntl(Mach64ContextRegs3D *m3d, int op) { m3d->scale_3d_cntl |= MACH64_SCALE_PIX_EXPAND_DYNAMIC_RANGE | MACH64_SCALE_DITHER_2D_TABLE | MACH64_DITHER_INIT_RESET; m3d->scale_3d_cntl |= Mach64BlendOps[op].scale_3d_cntl; if (m3d->color_alpha) { /* A8 uses RGB8 which expands to (I,I,I,0). Thus, we use the color * channels instead of the alpha channel as the alpha factor. We also * use the color channels for ARGB8888 masks with component-alpha. */ CARD32 Ad = m3d->scale_3d_cntl & MACH64_ALPHA_BLEND_DST_MASK; /* InReverse */ if (Ad == MACH64_ALPHA_BLEND_DST_SRCALPHA) { m3d->scale_3d_cntl &= ~MACH64_ALPHA_BLEND_DST_MASK; m3d->scale_3d_cntl |= MACH64_ALPHA_BLEND_DST_SRCCOLOR; } /* OutReverse */ if (Ad == MACH64_ALPHA_BLEND_DST_INVSRCALPHA) { m3d->scale_3d_cntl &= ~MACH64_ALPHA_BLEND_DST_MASK; m3d->scale_3d_cntl |= MACH64_ALPHA_BLEND_DST_INVSRCCOLOR; } } /* Can't color mask and blend at the same time */ m3d->dp_write_mask = 0xffffffff; /* Can't fog and blend at the same time */ m3d->scale_3d_cntl |= MACH64_ALPHA_FOG_EN_ALPHA; /* Enable texture mapping mode */ m3d->scale_3d_cntl |= MACH64_SCALE_3D_FCN_TEXTURE; m3d->scale_3d_cntl |= MACH64_MIP_MAP_DISABLE; /* Setup the texture environment */ m3d->scale_3d_cntl |= MACH64_TEX_LIGHT_FCN_MODULATE; /* Initialize texture unit */ m3d->tex_cntl |= MACH64_TEX_ST_DIRECT | MACH64_TEX_SRC_LOCAL | MACH64_TEX_UNCOMPRESSED | MACH64_TEX_CACHE_FLUSH | MACH64_TEX_CACHE_SIZE_4K; } /* * This function setups the texture unit. */ static Bool Mach64PrepareTexture(PicturePtr pPict, PixmapPtr pPix) { ScrnInfoPtr pScreenInfo = xf86Screens[pPix->drawable.pScreen->myNum]; ATIPtr pATI = ATIPTR(pScreenInfo); Mach64ContextRegs3D *m3d = &pATI->m3d; CARD32 texFormat; int w = pPict->pDrawable->width; int h = pPict->pDrawable->height; int l2w, l2h, l2p, level, pitch, cpp, i; /* Prepare picture format */ for (i = 0; i < MACH64_NR_TEX_FORMATS; i++) { if (Mach64TexFormats[i].pictFormat == pPict->format) break; } texFormat = Mach64TexFormats[i].texFormat; /* Prepare picture size */ cpp = PICT_FORMAT_BPP(pPict->format) / 8; pitch = exaGetPixmapPitch(pPix) / cpp; Mach64GetOrder(w, &l2w); Mach64GetOrder(h, &l2h); Mach64GetOrder(pitch, &l2p); if (pPict->repeat && w == 1 && h == 1) l2p = 0; else if (pPict->repeat) MACH64_FALLBACK(("Repeat not supported for w,h != 1,1\n")); l2w = l2p; level = (l2w > l2h) ? l2w : l2h; m3d->tex_width = (1 << l2w); m3d->tex_height = (1 << l2h); /* Update hw state */ m3d->dp_pix_width |= SetBits(texFormat, DP_SCALE_PIX_WIDTH); m3d->tex_size_pitch = (l2w << 0) | (level << 4) | (l2h << 8); m3d->tex_offset = exaGetPixmapOffset(pPix); if (PICT_FORMAT_A(pPict->format)) m3d->scale_3d_cntl |= MACH64_TEX_MAP_AEN; switch (pPict->filter) { case PictFilterNearest: m3d->scale_3d_cntl |= MACH64_TEX_BLEND_FCN_NEAREST; break; case PictFilterBilinear: /* FIXME */ #if 0 m3d->scale_3d_cntl |= MACH64_TEX_BLEND_FCN_LINEAR; m3d->scale_3d_cntl |= MACH64_BILINEAR_TEX_EN; #endif MACH64_FALLBACK(("Bilinear filter 0x%x\n", pPict->filter)); break; default: MACH64_FALLBACK(("Bad filter 0x%x\n", pPict->filter)); } m3d->transform = pPict->transform; return TRUE; } /* * PrepareComposite acceleration hook. */ Bool Mach64PrepareComposite ( int op, PicturePtr pSrcPicture, PicturePtr pMaskPicture, PicturePtr pDstPicture, PixmapPtr pSrc, PixmapPtr pMask, PixmapPtr pDst ) { ScrnInfoPtr pScreenInfo = xf86Screens[pDst->drawable.pScreen->myNum]; ATIPtr pATI = ATIPTR(pScreenInfo); Mach64ContextRegs3D *m3d = &pATI->m3d; CARD32 dstFormat; int offset, i; ATIDRISync(pScreenInfo); /* Initialize state */ m3d->dp_mix = SetBits(MIX_SRC, DP_BKGD_MIX) | SetBits(MIX_SRC, DP_FRGD_MIX); m3d->dp_src = SetBits(SRC_SCALER_3D, DP_BKGD_SRC) | SetBits(SRC_SCALER_3D, DP_FRGD_SRC) | DP_MONO_SRC_ALLONES; Mach64GetPixmapOffsetPitch(pDst, &m3d->dst_pitch_offset); m3d->scale_3d_cntl = 0; m3d->tex_cntl = 0; m3d->frag_src = FALSE; m3d->frag_mask = FALSE; m3d->frag_color = 0xffffffff; m3d->color_alpha = FALSE; m3d->transform = NULL; /* Compute state */ if (pMaskPicture && !Mach64PrepareMask(m3d, op, pSrcPicture, pMaskPicture, pSrc, pMask)) return FALSE; Mach64BlendCntl(m3d, op); for (i = 0; i < MACH64_NR_TEX_FORMATS; i++) { if (Mach64TexFormats[i].pictFormat == pDstPicture->format) break; } dstFormat = Mach64TexFormats[i].dstFormat; m3d->dp_pix_width = SetBits(dstFormat, DP_DST_PIX_WIDTH) | SetBits(dstFormat, DP_SRC_PIX_WIDTH) | SetBits(dstFormat, DP_HOST_PIX_WIDTH); if (!m3d->frag_src) { if (!Mach64PrepareTexture(pSrcPicture, pSrc)) return FALSE; } if (pMaskPicture && !m3d->frag_mask) { if (!Mach64PrepareTexture(pMaskPicture, pMask)) return FALSE; } offset = TEX_LEVEL(m3d->tex_size_pitch); /* Emit state */ ATIMach64WaitForFIFO(pATI, 12); outf(DP_SRC, m3d->dp_src); outf(DP_MIX, m3d->dp_mix); outf(CLR_CMP_CNTL, CLR_CMP_FN_FALSE); outf(DST_CNTL, DST_X_DIR | DST_Y_DIR); outf(DST_OFF_PITCH, m3d->dst_pitch_offset); outf(SCALE_3D_CNTL, m3d->scale_3d_cntl); outf(DP_WRITE_MASK, m3d->dp_write_mask); outf(DP_PIX_WIDTH, m3d->dp_pix_width); outf(SETUP_CNTL, 0); outf(TEX_SIZE_PITCH, m3d->tex_size_pitch); outf(TEX_CNTL, m3d->tex_cntl); outf(TEX_0_OFF + offset, m3d->tex_offset); return TRUE; } /* * Vertex format, setup and emission. */ typedef struct { float s0; /* normalized texture coords */ float t0; float x; /* quarter-pixels */ float y; CARD32 argb; /* fragment color */ } Mach64Vertex; #define VTX_SET(_v, _col, _dstX, _dstY, _srcX, _dx, _srcY, _dy) \ do { \ _v.s0 = ((float)(_srcX) + _dx) / m3d->tex_width; \ _v.t0 = ((float)(_srcY) + _dy) / m3d->tex_height; \ _v.x = ((float)(_dstX) * 4.0); \ _v.y = ((float)(_dstY) * 4.0); \ _v.argb = _col; \ } while (0) #define FVAL(_fval) (*(CARD32 *)&(_fval)) #define VTX_OUT(_v, n) \ do { \ float w = 1.0; \ CARD32 z = 0xffff << 15; \ CARD32 x_y = ((CARD16)_v.x << 16) | \ ((CARD16)_v.y & 0xffff); \ \ ATIMach64WaitForFIFO(pATI, 6); \ outf(VERTEX_##n##_S, FVAL(_v.s0)); \ outf(VERTEX_##n##_T, FVAL(_v.t0)); \ outf(VERTEX_##n##_W, FVAL(w)); \ \ outf(VERTEX_##n##_Z, z); \ outf(VERTEX_##n##_ARGB, _v.argb); \ outf(VERTEX_##n##_X_Y, x_y); \ } while (0) /* * Composite acceleration hook. */ void Mach64Composite ( PixmapPtr pDst, int srcX, int srcY, int maskX, int maskY, int dstX, int dstY, int w, int h ) { ScrnInfoPtr pScreenInfo = xf86Screens[pDst->drawable.pScreen->myNum]; ATIPtr pATI = ATIPTR(pScreenInfo); Mach64ContextRegs3D *m3d = &pATI->m3d; Mach64Vertex v0, v1, v2, v3; float ooa; CARD32 col; PictVector v; int srcXend, srcYend; float dxy = 0.0, dwh = 0.0; ATIDRISync(pScreenInfo); /* Disable clipping if it gets in the way */ ATIMach64ValidateClip(pATI, dstX, dstX + w - 1, dstY, dstY + h - 1); /* Handle solid textures which come in as fragment color */ col = m3d->frag_color; if (m3d->frag_src) { srcX = maskX; srcY = maskY; } /* Handle transform */ srcXend = srcX + w; srcYend = srcY + h; if (m3d->transform) { v.vector[0] = IntToxFixed(srcX); v.vector[1] = IntToxFixed(srcY); v.vector[2] = xFixed1; PictureTransformPoint(m3d->transform, &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(m3d->transform, &v); srcXend = xFixedToInt(v.vector[0]); srcYend = xFixedToInt(v.vector[1]); #if 0 /* Bilinear needs manipulation of texture coordinates */ if (m3d->scale_3d_cntl & MACH64_BILINEAR_TEX_EN) { dxy = 0.5; dwh = -1.0; } #endif } /* Create vertices in clock-wise order */ VTX_SET(v0, col, dstX, dstY, srcX, dxy, srcY, dxy); VTX_SET(v1, col, dstX + w, dstY, srcXend, dwh, srcY, dxy); VTX_SET(v2, col, dstX + w, dstY + h, srcXend, dwh, srcYend, dwh); VTX_SET(v3, col, dstX, dstY + h, srcX, dxy, srcYend, dwh); /* Setup upper triangle (v0, v1, v3) */ VTX_OUT(v0, 1); VTX_OUT(v1, 2); VTX_OUT(v3, 3); ooa = 1.0 / (w * h); outf(ONE_OVER_AREA, FVAL(ooa)); /* Setup lower triangle (v2, v1, v3) */ VTX_OUT(v2, 1); ooa = -ooa; outf(ONE_OVER_AREA, FVAL(ooa)); } /* * DoneComposite acceleration hook. */ void Mach64DoneComposite(PixmapPtr pDst) { ScrnInfoPtr pScreenInfo = xf86Screens[pDst->drawable.pScreen->myNum]; ATIPtr pATI = ATIPTR(pScreenInfo); ATIDRISync(pScreenInfo); outf(SCALE_3D_CNTL, 0); }