diff options
Diffstat (limited to 'xorg-server/hw/kdrive/mga/g400_composite.c')
-rw-r--r-- | xorg-server/hw/kdrive/mga/g400_composite.c | 510 |
1 files changed, 510 insertions, 0 deletions
diff --git a/xorg-server/hw/kdrive/mga/g400_composite.c b/xorg-server/hw/kdrive/mga/g400_composite.c new file mode 100644 index 000000000..dda9d9347 --- /dev/null +++ b/xorg-server/hw/kdrive/mga/g400_composite.c @@ -0,0 +1,510 @@ +/* + * Copyright © 2004 Damien Ciabrini + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of Anders Carlsson not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. Anders Carlsson makes no + * representations about the suitability of this software for any purpose. It + * is provided "as is" without express or implied warranty. + * + * DAMIEN CIABRINI DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL ANDERS CARLSSON BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifdef HAVE_CONFIG_H +#include <kdrive-config.h> +#endif + +#include "mga.h" +#include "g400_common.h" + + +static PicturePtr currentSrcPicture; +static PicturePtr currentMaskPicture; +static PixmapPtr currentSrc; +static PixmapPtr currentMask; +static int src_w2; +static int src_h2; +static int mask_w2; +static int mask_h2; + +struct blendinfo { + Bool dst_alpha; + Bool src_alpha; + CARD32 blend_cntl; +}; + +static struct blendinfo mgaBlendOP[] = { + /* Clear */ + {0, 0, MGA_SRC_ZERO | MGA_DST_ZERO}, + /* Src */ + {0, 0, MGA_SRC_ONE | MGA_DST_ZERO}, + /* Dst */ + {0, 0, MGA_SRC_ZERO | MGA_DST_ONE}, + /* Over */ + {0, 1, MGA_SRC_ONE | MGA_DST_ONE_MINUS_SRC_ALPHA}, + /* OverReverse */ + {1, 0, MGA_SRC_ONE_MINUS_DST_ALPHA | MGA_DST_ONE}, + /* In */ + {1, 0, MGA_SRC_DST_ALPHA | MGA_DST_ZERO}, + /* InReverse */ + {0, 1, MGA_SRC_ZERO | MGA_DST_SRC_ALPHA}, + /* Out */ + {1, 0, MGA_SRC_ONE_MINUS_DST_ALPHA | MGA_DST_ZERO}, + /* OutReverse */ + {0, 1, MGA_SRC_ZERO | MGA_DST_ONE_MINUS_SRC_ALPHA}, + /* Atop */ + {1, 1, MGA_SRC_DST_ALPHA | MGA_DST_ONE_MINUS_SRC_ALPHA}, + /* AtopReverse */ + {1, 1, MGA_SRC_ONE_MINUS_DST_ALPHA | MGA_DST_SRC_ALPHA}, + /* Xor */ + {1, 1, MGA_SRC_ONE_MINUS_DST_ALPHA | MGA_DST_ONE_MINUS_SRC_ALPHA}, + /* Add */ + {0, 0, MGA_SRC_ONE | MGA_DST_ONE}, +}; + +struct formatinfo { + int fmt; + CARD32 card_fmt; +}; + +static struct formatinfo texformats[] = { + {PICT_a8r8g8b8, MGA_TW32}, + {PICT_x8r8g8b8, MGA_TW32}, + {PICT_r5g6b5, MGA_TW16}, + {PICT_a1r5g5b5, MGA_TW15}, + {PICT_x1r5g5b5, MGA_TW15}, + {PICT_a4r4g4b4, MGA_TW12}, + {PICT_x4r4g4b4, MGA_TW12}, + {PICT_a8, MGA_TW8A}, +}; + +static int +MGA_LOG2( int val ) +{ + int ret = 0; + if (val==1) return 0; + while (val >> ret) + ret++; + + return ((1 << (ret-1)) == val) ? (ret-1) : ret; +} + + +static Bool +mgaCheckSourceTexture (int tmu, + PicturePtr pPict) +{ + int w = pPict->pDrawable->width; + int h = pPict->pDrawable->height; + int i; + CARD32 texctl = 0; + + if ((w > 2047) || (h > 2047)) + MGA_FALLBACK(("Picture w/h too large (%dx%d)\n", w, h)); + + for (i = 0; i < sizeof(texformats) / sizeof(texformats[0]); i++) { + if (texformats[i].fmt == pPict->format) { + texctl = texformats[i].card_fmt; + break; + } + } + if (texctl == 0) { + MGA_FALLBACK(("Unsupported picture format 0x%x\n", pPict->format)); + } + + if (pPict->repeat && ((w & (w - 1)) != 0 || (h & (h - 1)) != 0)) + MGA_FALLBACK(("NPOT repeat unsupported (%dx%d)\n", w, h)); + + if (pPict->filter != PictFilterNearest && + pPict->filter != PictFilterBilinear) + MGA_FALLBACK(("Unsupported filter 0x%x\n", pPict->filter)); + + return TRUE; +} + +static Bool +PrepareSourceTexture (int tmu, + PicturePtr pSrcPicture, + PixmapPtr pSrc) +{ + KdScreenPriv (pSrc->drawable.pScreen); + int mem_base=(int)pScreenPriv->screen->memory_base; + int pitch = pSrc->devKind / (pSrc->drawable.bitsPerPixel >> 3); + int i; + + int w = pSrc->drawable.width; + int h = pSrc->drawable.height; + int w_log2 = MGA_LOG2(w); + int h_log2 = MGA_LOG2(h); + + int texctl = MGA_PITCHLIN | ((pitch & (2048 - 1)) << 9) | + MGA_CLAMPUV | MGA_NOPERSPECTIVE; + int flags = 0; + int texctl2 = MGA_G400_TC2_MAGIC | flags; + + for (i = 0; i < sizeof(texformats) / sizeof(texformats[0]); i++) { + if (texformats[i].fmt == pSrcPicture->format) { + texctl |= texformats[i].card_fmt; + break; + } + } + + if (PICT_FORMAT_A(pSrcPicture->format) != 0) { + texctl |= MGA_TAKEY; + } else { + texctl |= MGA_TAMASK | MGA_TAKEY; + } + + if (pSrcPicture->repeat) { + texctl &= ~MGA_CLAMPUV; + } + + if (tmu == 1) + texctl2 |= MGA_TC2_DUALTEX | MGA_TC2_SELECT_TMU1 | flags; + + mgaWaitAvail (6); + MGA_OUT32 (mmio, MGA_REG_TEXCTL2, texctl2); + MGA_OUT32 (mmio, MGA_REG_TEXCTL, texctl); + /* Source (texture) address + pitch */ + MGA_OUT32 (mmio, MGA_REG_TEXORG, ((int)pSrc->devPrivate.ptr - mem_base)); + MGA_OUT32 (mmio, MGA_REG_TEXWIDTH, (w-1)<<18 | ((8-w_log2)&63)<<9 | w_log2); + MGA_OUT32 (mmio, MGA_REG_TEXHEIGHT, (h-1)<<18 | ((8-h_log2)&63)<<9 | h_log2); + /* Set blit filtering flags */ + if (pSrcPicture->filter == PictFilterBilinear) { + MGA_OUT32 (mmio, MGA_REG_TEXFILTER, + (0x10<<21) | MGA_MAG_BILIN | MGA_MIN_BILIN); + } else { + MGA_OUT32 (mmio, MGA_REG_TEXFILTER, + (0x10<<21) | MGA_MAG_NRST | MGA_MIN_NRST); + } + + if (tmu == 1) { + mgaWaitAvail (1); + MGA_OUT32 (mmio, MGA_REG_TEXCTL2, MGA_G400_TC2_MAGIC | MGA_TC2_DUALTEX | flags); + } + + return TRUE; +} + + +/* + * The formals params are the elements of the following matrix: + * + * Dest Transform Src + * coords coords + * / Xdst \ / X_incx X_incy X_init \ / Xsrc \ + * | Ydst | = | Y_incx Y_incy Y_init | x | Ysrc | + * \ 1 / \ H_incx H_incy H_init / \ 1 / + * + * matrix elements are 32bits fixed points (16.16) + * mga_fx_* is the size of the fixed point for the TMU + */ +static void +setTMIncrementsRegs(int X_incx, + int X_incy, + int X_init, + int Y_incx, + int Y_incy, + int Y_init, + int H_incx, + int H_incy, + int H_init, + int mga_fx_width_size, + int mga_fx_height_size) { + int decalw = mga_fx_width_size - 16; + int decalh = mga_fx_height_size - 16; + + /* Convert 16 bits fixpoint -> MGA variable size fixpoint */ + if (decalw >= 0) { + X_incx = X_incx << decalw; + X_incy = X_incy << decalw; + X_init = X_init << decalw; + } else { + decalw =- decalw; + X_incx = X_incx >> decalw; + X_incy = X_incy >> decalw; + X_init = X_init >> decalw; + } + + /* Convert 16 bits fixpoint -> MGA variable size fixpoint */ + if (decalh >= 0) { + Y_incx = Y_incx << decalh; + Y_incy = Y_incy << decalh; + Y_init = Y_init << decalh; + } else { + decalh =- decalh; + Y_incx = Y_incx >> decalh; + Y_incy = Y_incy >> decalh; + Y_init = Y_init >> decalh; + } + + /* Set TM registers */ + mgaWaitAvail (9); + MGA_OUT32 (mmio, MGA_REG_TMR0, X_incx); + MGA_OUT32 (mmio, MGA_REG_TMR1, Y_incx); + MGA_OUT32 (mmio, MGA_REG_TMR2, X_incy); + MGA_OUT32 (mmio, MGA_REG_TMR3, Y_incy); + MGA_OUT32 (mmio, MGA_REG_TMR4, H_incx); + MGA_OUT32 (mmio, MGA_REG_TMR5, H_incy); + MGA_OUT32 (mmio, MGA_REG_TMR6, X_init); + MGA_OUT32 (mmio, MGA_REG_TMR7, Y_init); + MGA_OUT32 (mmio, MGA_REG_TMR8, H_init); +} + + + + +Bool +mgaCheckComposite(int op, PicturePtr pSrcPicture, PicturePtr pMaskPicture, + PicturePtr pDstPicture) +{ + if (op >= sizeof(mgaBlendOP) / sizeof(mgaBlendOP[0])) + MGA_FALLBACK(("unsupported op %x", op)); + if (!mgaCheckSourceTexture (0, pSrcPicture)) + return FALSE; + + if (pMaskPicture != NULL) { + if (PICT_FORMAT_A(pMaskPicture->format) == 0) + MGA_FALLBACK(("Mask without alpha unsupported")); + if (!mgaCheckSourceTexture (1, pMaskPicture)) + return FALSE; + } + + if (pMaskPicture->componentAlpha) + MGA_FALLBACK(("Component alpha unsupported")); + + if (pDstPicture->format == PICT_a8) + MGA_FALLBACK(("render to A8 unsupported")); + + return TRUE; +} + +#define C_ARG1_CUR 0x0 +#define C_ARG1_ALPHA MGA_TDS_COLOR_ARG1_REPLICATEALPHA +#define C_ARG2_DIFFUSE MGA_TDS_COLOR_ARG2_DIFFUSE +#define C_ARG2_FCOL MGA_TDS_COLOR_ARG2_FCOL +#define C_ARG2_PREV MGA_TDS_COLOR_ARG2_PREVSTAGE +#define C_ARG1_INV MGA_TDS_COLOR_ARG1_INV +#define C_ARG2_INV MGA_TDS_COLOR_ARG2_INV +#define COLOR_MUL MGA_TDS_COLOR_SEL_MUL +#define COLOR_ARG1 MGA_TDS_COLOR_SEL_ARG1 +#define COLOR_ARG2 MGA_TDS_COLOR_SEL_ARG2 +#define A_ARG1_CUR 0x0 +#define A_ARG2_IGN A_ARG2_DIFFUSE +#define A_ARG2_FCOL MGA_TDS_ALPHA_ARG2_FCOL +#define A_ARG2_DIFFUSE MGA_TDS_ALPHA_ARG2_DIFFUSE +#define A_ARG2_PREV MGA_TDS_ALPHA_ARG2_PREVSTAGE +#define ALPHA_MUL MGA_TDS_ALPHA_SEL_MUL +#define ALPHA_ARG1 MGA_TDS_ALPHA_SEL_ARG1 +#define ALPHA_ARG2 MGA_TDS_ALPHA_SEL_ARG2 + + +Bool +mgaPrepareComposite (int op, + PicturePtr pSrcPicture, + PicturePtr pMaskPicture, + PicturePtr pDstPicture, + PixmapPtr pSrc, + PixmapPtr pMask, + PixmapPtr pDst) +{ + KdScreenPriv (pSrc->drawable.pScreen); + int mem_base=(int)pScreenPriv->screen->memory_base; + int cmd, blendcntl; + int ds0, ds1; + + /* Init MGA (clipping) */ + mgaSetup (pSrc->drawable.pScreen, pDst->drawable.bitsPerPixel, 1); + + /* Initialize fg color to 0, used in the src = A8 case */ + MGA_OUT32 (mmio, MGA_REG_FCOL, 0xff000000); + + /* Destination flags */ + mgaWaitAvail (2); + MGA_OUT32 (mmio, MGA_REG_DSTORG, ((int)pDst->devPrivate.ptr - mem_base)); + MGA_OUT32 (mmio, MGA_REG_PITCH, + pDst->devKind / (pDst->drawable.bitsPerPixel >> 3)); + + + /* Source(s) flags */ + if (!PrepareSourceTexture (0, pSrcPicture, pSrc)) return FALSE; + if (pMask != NULL) { + if (!PrepareSourceTexture (1, pMaskPicture, pMask)) return FALSE; + } + + /* Prepare multi-texture registers */ + ds0=ds1=0; + + if (pSrcPicture->format == PICT_a8) { + /* C = 0 A = As */ + /* MGA HW: A8 format makes RGB white. We use FCOL for the black + * If FCOL was not 0, it would have been be premultiplied (RENDER) + * color component would have been: + * C_ARG1_ALPHA | C_ARG2_FCOL | COLOR_MUL + */ + ds0=C_ARG2_FCOL | COLOR_ARG2 | + A_ARG1_CUR | ALPHA_ARG1; + /* MGA HW: TMU1 must be enabled when DUALSTAGE0 contains something */ + if (pMask == NULL) { + if (!PrepareSourceTexture (1, pSrcPicture, pSrc)) return FALSE; + ds1=C_ARG2_PREV | COLOR_ARG2 | + A_ARG2_PREV | ALPHA_ARG2; + } + } else { + /* C = Cs A = As */ + ds0=C_ARG1_CUR | COLOR_ARG1 | + A_ARG1_CUR | ALPHA_ARG1; + } + + if (pMask != NULL) { + /* As or Am might be NULL. in this case we don't multiply because, + * the alpha component holds garbage. + */ + int color,alpha; + if (PICT_FORMAT_A (pMaskPicture->format) == 0) { + /* C = Cs */ + color = C_ARG2_PREV | COLOR_ARG2; + } else { + /* C = Am * Cs */ + color = C_ARG1_ALPHA | C_ARG2_PREV | COLOR_MUL; + } + + if (PICT_FORMAT_A (pMaskPicture->format) == 0) { + /* A = As */ + alpha = A_ARG2_PREV | ALPHA_ARG2; + } else if (PICT_FORMAT_A (pSrcPicture->format) == 0) { + /* A = Am */ + alpha = A_ARG1_CUR | ALPHA_ARG1; + } else { + /* A = Am * As */ + alpha = A_ARG1_CUR | A_ARG2_PREV | ALPHA_MUL; + } + + ds1 = color | alpha; + } + + /* MultiTexture modulation */ + mgaWaitAvail (2); + MGA_OUT32 (mmio, MGA_REG_TDUALSTAGE0, ds0); + MGA_OUT32 (mmio, MGA_REG_TDUALSTAGE1, ds1); + + + cmd = MGA_OPCOD_TEXTURE_TRAP | MGA_ATYPE_RSTR | 0x000c0000 | + MGA_DWGCTL_SHIFTZERO | MGA_DWGCTL_SGNZERO | MGA_DWGCTL_ARZERO | + MGA_ATYPE_I; + + blendcntl = mgaBlendOP[op].blend_cntl; + if (PICT_FORMAT_A(pDstPicture->format) == 0 && mgaBlendOP[op].dst_alpha) { + if ((blendcntl & MGA_SRC_BLEND_MASK) == MGA_SRC_DST_ALPHA) + blendcntl = (blendcntl & ~MGA_SRC_BLEND_MASK) | MGA_SRC_ONE; + else if ((blendcntl & MGA_SRC_BLEND_MASK) == MGA_SRC_ONE_MINUS_DST_ALPHA) + blendcntl = (blendcntl & ~MGA_SRC_BLEND_MASK) | MGA_SRC_ZERO; + } + + mgaWaitAvail (2); + MGA_OUT32 (mmio, MGA_REG_DWGCTL, cmd); + MGA_OUT32 (mmio, MGA_REG_ALPHACTRL, MGA_ALPHACHANNEL | blendcntl); + + currentSrcPicture = pSrcPicture; + currentMaskPicture = pMaskPicture; + currentSrc = pSrc; + currentMask = pMask; + src_w2 = MGA_LOG2 (currentSrc->drawable.width); + src_h2 = MGA_LOG2 (currentSrc->drawable.height); + mask_w2 = MGA_LOG2 (currentMask->drawable.width); + mask_h2 = MGA_LOG2 (currentMask->drawable.height); + + return TRUE; +} + + +void +mgaComposite (int srcX, + int srcY, + int maskX, + int maskY, + int dstX, + int dstY, + int width, + int height) +{ + /* Source positions can be outside source textures' boundaries. + * We clamp the values here to avoid rendering glitches. + */ + srcX=srcX % currentSrc->drawable.width; + srcY=srcY % currentSrc->drawable.height; + maskX=maskX % currentMask->drawable.width; + maskY=maskY % currentMask->drawable.height; + + if (currentSrcPicture->transform) { + setTMIncrementsRegs (currentSrcPicture->transform->matrix[0][0], + currentSrcPicture->transform->matrix[0][1], + currentSrcPicture->transform->matrix[0][2] + + (srcX << 16), + currentSrcPicture->transform->matrix[1][0], + currentSrcPicture->transform->matrix[1][1], + currentSrcPicture->transform->matrix[1][2] + + (srcY << 16), + currentSrcPicture->transform->matrix[2][0], + currentSrcPicture->transform->matrix[2][1], + currentSrcPicture->transform->matrix[2][2], + 20-src_w2, 20-src_h2); + } else { + setTMIncrementsRegs (1 << 16, 0, srcX << 16, + 0, 1 << 16, srcY << 16, + 0, 0, 0x10000, + 20-src_w2, 20-src_h2); + } + + if (currentMask != NULL) { + mgaWaitAvail (1); + MGA_OUT32 (mmio, MGA_REG_TEXCTL2, + MGA_G400_TC2_MAGIC | MGA_TC2_DUALTEX | MGA_TC2_SELECT_TMU1); + if (currentMaskPicture->transform) { + setTMIncrementsRegs (currentMaskPicture->transform->matrix[0][0], + currentMaskPicture->transform->matrix[0][1], + currentMaskPicture->transform->matrix[0][2] + + (maskX << 16), + currentMaskPicture->transform->matrix[1][0], + currentMaskPicture->transform->matrix[1][1], + currentMaskPicture->transform->matrix[1][2] + + (maskY << 16), + currentMaskPicture->transform->matrix[2][0], + currentMaskPicture->transform->matrix[2][1], + currentMaskPicture->transform->matrix[2][2], + 20-mask_w2, 20-mask_h2); + } else { + setTMIncrementsRegs (1 << 16, 0, maskX << 16, + 0, 1 << 16, maskY << 16, + 0, 0, 0x10000, + 20-mask_w2, 20-mask_h2); + } + + mgaWaitAvail (1); + MGA_OUT32 (mmio, MGA_REG_TEXCTL2, MGA_G400_TC2_MAGIC | MGA_TC2_DUALTEX); + } + + /* Destination Bounding Box + * (Boundary Right | Boundary Left, Y dest | Height) + */ + mgaWaitAvail (2); + MGA_OUT32 (mmio, MGA_REG_FXBNDRY, + ((dstX + width) << 16) | (dstX & 0xffff)); + MGA_OUT32 (mmio, MGA_REG_YDSTLEN | MGA_REG_EXEC, + (dstY << 16) | (height & 0xffff)); +} + +void +mgaDoneComposite (void) +{ +} |