diff options
Diffstat (limited to 'xorg-server/hw/kdrive/ati/r128_composite.c')
-rw-r--r-- | xorg-server/hw/kdrive/ati/r128_composite.c | 564 |
1 files changed, 564 insertions, 0 deletions
diff --git a/xorg-server/hw/kdrive/ati/r128_composite.c b/xorg-server/hw/kdrive/ati/r128_composite.c new file mode 100644 index 000000000..0d18ebff7 --- /dev/null +++ b/xorg-server/hw/kdrive/ati/r128_composite.c @@ -0,0 +1,564 @@ +/* + * Copyright © 2003 Eric Anholt, Anders Carlsson + * + * 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 Eric Anholt not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. Eric Anholt makes no + * representations about the suitability of this software for any purpose. It + * is provided "as is" without express or implied warranty. + * + * ERIC ANHOLT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL ERIC ANHOLT 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. + */ + +#include "ati.h" +#include "ati_reg.h" +#include "ati_dma.h" +#include "ati_draw.h" + +extern ATIScreenInfo *accel_atis; +extern int sample_count; +extern float sample_offsets_x[255]; +extern float sample_offsets_y[255]; +extern CARD8 ATIBltRop[16]; + +static int widths[2] = {1,1}; +static int heights[2] = {1,1}; +static Bool is_transform[2]; +static PictTransform *transform[2]; + +struct blendinfo { + Bool dst_alpha; + Bool src_alpha; + CARD32 blendctl; +}; + +static struct blendinfo 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 Bool +R128GetDatatypePict(CARD32 format, CARD32 *type) +{ + switch (format) { + case PICT_a1r5g5b5: + case PICT_x1r5g5b5: + *type = R128_DATATYPE_ARGB1555; + return TRUE; + case PICT_r5g6b5: + *type = R128_DATATYPE_RGB565; + return TRUE; + case PICT_a8r8g8b8: + case PICT_x8r8g8b8: + *type = R128_DATATYPE_ARGB8888; + return TRUE; + default: + return FALSE; + } + +} + +static Bool +R128CheckCompositeTexture(PicturePtr pPict) +{ + int w = pPict->pDrawable->width; + int h = pPict->pDrawable->height; + + if (w > (1 << 10) || h > (1 << 10)) + ATI_FALLBACK(("Picture w/h too large (%dx%d)\n", w, h)); + if (pPict->repeat && ((w & (w - 1)) != 0 || (h & (h - 1)) != 0)) + ATI_FALLBACK(("NPOT repeat unsupported (%dx%d)\n", w, h)); + + switch (pPict->format) { + case PICT_a8: + case PICT_a1r5g5b5: + case PICT_a4r4g4b4: + case PICT_r5g6b5: + case PICT_a8r8g8b8: + break; + default: + ATI_FALLBACK(("Unsupported picture format 0x%x\n", + pPict->format)); + } + + return TRUE; +} + +Bool +R128CheckComposite(int op, PicturePtr pSrcPicture, PicturePtr pMaskPicture, + PicturePtr pDstPicture) +{ + CARD32 dstDatatype; + + if (op >= sizeof(R128BlendOp)/sizeof(R128BlendOp[0])) + ATI_FALLBACK(("Unsupported op 0x%x\n", op)); + if (pDstPicture->format == PICT_a8) { + if (R128BlendOp[op].src_alpha || R128BlendOp[op].dst_alpha || + pMaskPicture != NULL) + ATI_FALLBACK(("alpha blending unsupported with " + "A8 dst?\n")); + } else if (!R128GetDatatypePict(pDstPicture->format, &dstDatatype)) { + ATI_FALLBACK(("Unsupported dest format 0x%x\n", + pDstPicture->format)); + } + if (pMaskPicture != NULL && pMaskPicture->componentAlpha && + R128BlendOp[op].src_alpha) + ATI_FALLBACK(("Component alpha not supported with source alpha " + "blending.\n")); + + if (!R128CheckCompositeTexture(pSrcPicture)) + return FALSE; + if (pMaskPicture != NULL && !R128CheckCompositeTexture(pMaskPicture)) + return FALSE; + + return TRUE; +} + +static Bool +R128TextureSetup(PicturePtr pPict, PixmapPtr pPix, int unit, CARD32 *txsize, + CARD32 *tex_cntl_c) +{ + int w = pPict->pDrawable->width; + int h = pPict->pDrawable->height; + int bytepp, shift, l2w, l2h, l2p; + int pitch; + + pitch = pPix->devKind; + if ((pitch & (pitch - 1)) != 0) + ATI_FALLBACK(("NPOT pitch 0x%x unsupported\n", pitch)); + + switch (pPict->format) { + case PICT_a8: + /* DATATYPE_RGB8 appears to expand the value into the alpha + * channel like we want. We then blank out the R,G,B channels + * as necessary using the combiners. + */ + *tex_cntl_c = R128_DATATYPE_RGB8 << R128_TEX_DATATYPE_SHIFT; + break; + case PICT_a1r5g5b5: + *tex_cntl_c = R128_DATATYPE_ARGB1555 << R128_TEX_DATATYPE_SHIFT; + break; + case PICT_a4r4g4b4: + *tex_cntl_c = R128_DATATYPE_ARGB4444 << R128_TEX_DATATYPE_SHIFT; + break; + case PICT_r5g6b5: + *tex_cntl_c = R128_DATATYPE_RGB565 << R128_TEX_DATATYPE_SHIFT; + break; + case PICT_a8r8g8b8: + *tex_cntl_c = R128_DATATYPE_ARGB8888 << R128_TEX_DATATYPE_SHIFT; + break; + default: + 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; + + if (unit == 0) + shift = 0; + else { + shift = 16; + *tex_cntl_c |= R128_SEC_SELECT_SEC_ST; + } + + /* ATILog2 returns -1 for value of 0 */ + l2w = ATILog2(w - 1) + 1; + l2h = ATILog2(h - 1) + 1; + l2p = ATILog2(pPix->devKind / bytepp); + + if (pPict->repeat && w == 1 && h == 1) + l2p = 0; + else if (pPict->repeat && l2p != l2w) + ATI_FALLBACK(("Repeat not supported for pitch != width\n")); + 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; +} + +Bool +R128PrepareComposite(int op, PicturePtr pSrcPicture, PicturePtr pMaskPicture, + PicturePtr pDstPicture, PixmapPtr pSrc, PixmapPtr pMask, PixmapPtr pDst) +{ + KdScreenPriv(pDst->drawable.pScreen); + ATIScreenInfo(pScreenPriv); + CARD32 txsize = 0, prim_tex_cntl_c, sec_tex_cntl_c = 0, dstDatatype; + CARD32 dst_pitch_offset, color_factor, in_color_factor, alpha_comb; + CARD32 blend_cntl; + int i; + RING_LOCALS; + + accel_atis = atis; + + if (pDstPicture->format == PICT_a8) + dstDatatype = R128_DATATYPE_Y8; + else + R128GetDatatypePict(pDstPicture->format, &dstDatatype); + + if (!R128TextureSetup(pSrcPicture, pSrc, 0, &txsize, &prim_tex_cntl_c)) + return FALSE; + if (pMask != NULL && !R128TextureSetup(pMaskPicture, pMask, 1, &txsize, + &sec_tex_cntl_c)) + return FALSE; + else if (pMask == NULL) + is_transform[1] = FALSE; + + if (!ATIGetPixmapOffsetPitch(pDst, &dst_pitch_offset)) + return FALSE; + + 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; + } + + BEGIN_DMA(12); + OUT_REG(R128_REG_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_REG(ATI_REG_DST_PITCH_OFFSET, dst_pitch_offset); + OUT_REG(ATI_REG_DP_GUI_MASTER_CNTL, + ATI_GMC_DST_PITCH_OFFSET_CNTL | + ATI_GMC_BRUSH_SOLID_COLOR | + (dstDatatype << 8) | + ATI_GMC_SRC_DATATYPE_COLOR | + (ATIBltRop[GXcopy] << 16) | + ATI_DP_SRC_SOURCE_MEMORY | + R128_GMC_3D_FCN_EN | + ATI_GMC_CLR_CMP_CNTL_DIS | + R128_GMC_AUX_CLIP_DIS | + ATI_GMC_WR_MSK_DIS); + OUT_REG(R128_REG_MISC_3D_STATE_CNTL, + R128_MISC_SCALE_3D_TEXMAP_SHADE | + R128_MISC_SCALE_PIX_REPLICATE | + R128_ALPHA_COMB_ADD_CLAMP | + blend_cntl); + OUT_REG(R128_REG_TEX_CNTL_C, + R128_TEXMAP_ENABLE | + ((pMask != NULL) ? R128_SEC_TEXMAP_ENABLE : 0) | + R128_ALPHA_ENABLE | + R128_TEX_CACHE_FLUSH); + OUT_REG(R128_REG_PC_GUI_CTLSTAT, R128_PC_FLUSH_GUI); + END_DMA(); + + /* 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_DMA(15); + OUT_RING(DMA_PACKET0(R128_REG_PRIM_TEX_CNTL_C, 14)); + OUT_RING_REG(R128_REG_PRIM_TEX_CNTL_C, 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_REG(R128_REG_PRIM_TEXTURE_COMBINE_CNTL_C, + 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_REG(R128_REG_TEX_SIZE_PITCH_C, 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_REG(R128_REG_PRIM_TEX_0_OFFSET_C + 4 * i, + ((CARD8 *)pSrc->devPrivate.ptr - + pScreenPriv->screen->memory_base)); + } + END_DMA(); + + if (pMask != NULL) { + BEGIN_DMA(14); + OUT_RING(DMA_PACKET0(R128_REG_SEC_TEX_CNTL_C, 13)); + OUT_RING_REG(R128_REG_SEC_TEX_CNTL_C, 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_REG(R128_REG_SEC_TEXTURE_COMBINE_CNTL_C, + 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_REG(R128_REG_SEC_TEX_0_OFFSET_C + 4 * i, + ((CARD8 *)pMask->devPrivate.ptr - + pScreenPriv->screen->memory_base)); + } + END_DMA(); + } + + return TRUE; +} +#define VTX_RING_COUNT 8 + +#define VTX_OUT(_dstX, _dstY, _srcX, _srcY, _maskX, _maskY) \ +do { \ + OUT_RING_F((_dstX)); \ + OUT_RING_F(((float)(_dstY)) + .125); \ + OUT_RING_F(0.0); \ + OUT_RING_F(1.0); \ + OUT_RING_F((((float)(_srcX)) + 0.5) / (widths[0])); \ + OUT_RING_F((((float)(_srcY)) + 0.5) / (heights[0])); \ + OUT_RING_F((((float)(_maskX)) + 0.5) / (widths[1])); \ + OUT_RING_F((((float)(_maskY)) + 0.5) / (heights[1])); \ +} while (0) + +void +R128Composite(int srcX, int srcY, int maskX, int maskY, int dstX, int dstY, + int w, int h) +{ + ATIScreenInfo *atis = accel_atis; + int srcXend, srcYend, maskXend, maskYend; + PictVector v; + RING_LOCALS; + + /*ErrorF("R128Composite (%d,%d) (%d,%d) (%d,%d) (%d,%d)\n", + srcX, srcY, maskX, maskY,dstX, dstY, w, h);*/ + + 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]); + } + + BEGIN_DMA(3 + 4 * VTX_RING_COUNT); + OUT_RING(DMA_PACKET3(ATI_CCE_PACKET3_3D_RNDR_GEN_PRIM, + 2 + 4 * VTX_RING_COUNT)); + 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_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); + + END_DMA(); +} + +void +R128DoneComposite(void) +{ +} + +Bool +R128PrepareTrapezoids(PicturePtr pDstPicture, PixmapPtr pDst) +{ + KdScreenPriv(pDst->drawable.pScreen); + ATIScreenInfo(pScreenPriv); + CARD32 dst_pitch_offset; + RING_LOCALS; + + accel_atis = atis; + + if (!ATIGetPixmapOffsetPitch(pDst, &dst_pitch_offset)) + return FALSE; + + BEGIN_DMA(18); + OUT_REG(R128_REG_SCALE_3D_CNTL, + R128_SCALE_3D_TEXMAP_SHADE | + R128_SCALE_PIX_REPLICATE | + R128_TEX_CACHE_SPLIT | + R128_TEX_CACHE_LINE_SIZE_4QW); + OUT_REG(ATI_REG_DST_PITCH_OFFSET, dst_pitch_offset); + OUT_REG(ATI_REG_DP_GUI_MASTER_CNTL, + ATI_GMC_DST_PITCH_OFFSET_CNTL | + ATI_GMC_BRUSH_SOLID_COLOR | + (R128_DATATYPE_RGB8 << 8) | + ATI_GMC_SRC_DATATYPE_COLOR | + (ATIBltRop[GXcopy] << 16) | + ATI_DP_SRC_SOURCE_MEMORY | + R128_GMC_3D_FCN_EN | + ATI_GMC_CLR_CMP_CNTL_DIS | + ATI_GMC_WR_MSK_DIS); + OUT_REG(R128_REG_MISC_3D_STATE_CNTL, + R128_MISC_SCALE_3D_TEXMAP_SHADE | + R128_MISC_SCALE_PIX_REPLICATE | + R128_ALPHA_COMB_ADD_CLAMP | + R128BlendOp[PictOpAdd].blendctl); + OUT_REG(R128_REG_TEX_CNTL_C, + R128_ALPHA_ENABLE); + OUT_REG(R128_REG_PC_GUI_CTLSTAT, R128_PC_FLUSH_GUI); + + OUT_RING(DMA_PACKET0(R128_REG_AUX_SC_CNTL, 5)); + OUT_RING_REG(R128_REG_AUX_SC_CNTL, R128_AUX1_SC_ENB); + OUT_RING_REG(R128_REG_AUX1_SC_LEFT, 0); + OUT_RING_REG(R128_REG_AUX1_SC_RIGHT, pDst->drawable.width); + OUT_RING_REG(R128_REG_AUX1_SC_TOP, 0); + OUT_RING_REG(R128_REG_AUX1_SC_BOTTOM, pDst->drawable.height); + END_DMA(); + + return TRUE; +} + +#define TRAP_VERT_RING_COUNT 4 + +#define TRAP_VERT(_x, _y) \ +do { \ + OUT_RING_F((_x) + sample_x); \ + OUT_RING_F((_y) + 0.125 + sample_y); \ + OUT_RING_F(0.0); \ + OUT_RING(0x01010101); \ +} while (0) + +void +R128Trapezoids(KaaTrapezoid *traps, int ntraps) +{ + ATIScreenInfo *atis = accel_atis; + RING_LOCALS; + + while (ntraps > 0) { + int i, sample, count, vertcount; + + count = 0xffff / 4 / sample_count; + if (count > ntraps) + count = ntraps; + vertcount = count * sample_count * 4; + + BEGIN_DMA(3 + vertcount * TRAP_VERT_RING_COUNT); + OUT_RING(DMA_PACKET3(ATI_CCE_PACKET3_3D_RNDR_GEN_PRIM, + 2 + vertcount * TRAP_VERT_RING_COUNT)); + OUT_RING(R128_CCE_VC_FRMT_DIFFUSE_ARGB); + OUT_RING(R128_CCE_VC_CNTL_PRIM_TYPE_TRI_FAN | + R128_CCE_VC_CNTL_PRIM_WALK_RING | + (vertcount << R128_CCE_VC_CNTL_NUM_SHIFT)); + + for (i = 0; i < count; i++) { + for (sample = 0; sample < sample_count; sample++) { + float sample_x = sample_offsets_x[sample]; + float sample_y = sample_offsets_y[sample]; + TRAP_VERT(traps[i].tl, traps[i].ty); + TRAP_VERT(traps[i].bl, traps[i].by); + TRAP_VERT(traps[i].br, traps[i].by); + TRAP_VERT(traps[i].tr, traps[i].ty); + } + } + END_DMA(); + + ntraps -= count; + traps += count; + } +} + +void +R128DoneTrapezoids(void) +{ +} |