From 249a111620e50ec8f533c64cec1e221ab921c8ef Mon Sep 17 00:00:00 2001 From: Owen W. Taylor Date: Sat, 5 Apr 2008 16:51:20 -0400 Subject: [PATCH] Draw untransformed repeating NPOT sources with tiles. When we have a repeating source that's non-power-of-two in a dimension, we can't turn on wrap for that dimension, but if we aren't transforming then we can break the destination area up into tiles, each tile contained completely within a single copy of the source, and render the tiles one-by-one. --- src/radeon_exa_render.c | 166 ++++++++++++++++++++++++++++++++++++++++------- 1 files changed, 141 insertions(+), 25 deletions(-) diff --git a/src/radeon_exa_render.c b/src/radeon_exa_render.c index 7fa177c..e1e9f0d 100644 --- a/src/radeon_exa_render.c +++ b/src/radeon_exa_render.c @@ -57,6 +57,8 @@ #ifdef ONLY_ONCE static Bool is_transform[2]; static PictTransform *transform[2]; +static Bool need_src_tile_x; +static Bool need_src_tile_y; struct blendinfo { Bool dst_alpha; @@ -220,9 +222,45 @@ union intfloat { CARD32 i; }; +static Bool RADEONCheckTexturePOT(PicturePtr pPict, Bool canTile) +{ + int w = pPict->pDrawable->width; + int h = pPict->pDrawable->height; + + if (pPict->repeat && ((w & (w - 1)) != 0 || (h & (h - 1)) != 0) && + !(!pPict->transform && canTile)) + RADEON_FALLBACK(("NPOT repeating %s unsupported (%dx%d), transform=%d\n", + canTile ? "source" : "mask", w, h, pPict->transform != 0)); + + return TRUE; +} + +/* We can't turn on repeats normally for a non-power-of-two dimension, + * but if the source isn't transformed, we can get the same effect + * by drawing the image in multiple tiles. (A common case that it's + * important to get right is drawing a strip of a NPOTxPOT texture + * repeating in the POT direction. With tiling, this ends up as a + * a single tile, which is perfect.) + */ +static Bool RADEONSetupSourceTile(PicturePtr pPict) +{ + if (pPict->repeat && !pPict->transform) { + int w = pPict->pDrawable->width; + int h = pPict->pDrawable->height; + + need_src_tile_x = (w & (w - 1)) != 0; + need_src_tile_y = (h & (h - 1)) != 0; + } else { + need_src_tile_x = FALSE; + need_src_tile_y = FALSE; + } + + return TRUE; +} + /* R100-specific code */ -static Bool R100CheckCompositeTexture(PicturePtr pPict, int unit) +static Bool R100CheckCompositeTexture(PicturePtr pPict, int unit, Bool canTile) { int w = pPict->pDrawable->width; int h = pPict->pDrawable->height; @@ -239,8 +277,8 @@ static Bool R100CheckCompositeTexture(PicturePtr pPict, int unit) RADEON_FALLBACK(("Unsupported picture format 0x%x\n", (int)pPict->format)); - if (pPict->repeat && ((w & (w - 1)) != 0 || (h & (h - 1)) != 0)) - RADEON_FALLBACK(("NPOT repeat unsupported (%dx%d)\n", w, h)); + if (!RADEONCheckTexturePOT(pPict, canTile)) + return FALSE; if (pPict->filter != PictFilterNearest && pPict->filter != PictFilterBilinear) @@ -401,11 +439,11 @@ static Bool R100CheckComposite(int op, PicturePtr pSrcPicture, } } - if (!R100CheckCompositeTexture(pMaskPicture, 1)) + if (!R100CheckCompositeTexture(pMaskPicture, 1, FALSE)) return FALSE; } - if (!R100CheckCompositeTexture(pSrcPicture, 0)) + if (!R100CheckCompositeTexture(pSrcPicture, 0, TRUE)) return FALSE; if (!RADEONGetDestFormat(pDstPicture, &tmp1)) @@ -452,6 +490,9 @@ static Bool FUNC_NAME(R100PrepareComposite)(int op, if (((dst_pitch >> pixel_shift) & 0x7) != 0) RADEON_FALLBACK(("Bad destination pitch 0x%x\n", (int)dst_pitch)); + if (!RADEONSetupSourceTile(pSrcPicture)) + return FALSE; + if (!FUNC_NAME(R100TextureSetup)(pSrcPicture, pSrc, 0)) return FALSE; pp_cntl = RADEON_TEX_0_ENABLE | RADEON_TEX_BLEND_0_ENABLE; @@ -521,7 +562,7 @@ static Bool FUNC_NAME(R100PrepareComposite)(int op, #ifdef ONLY_ONCE -static Bool R200CheckCompositeTexture(PicturePtr pPict, int unit) +static Bool R200CheckCompositeTexture(PicturePtr pPict, int unit, Bool canTile) { int w = pPict->pDrawable->width; int h = pPict->pDrawable->height; @@ -539,8 +580,8 @@ static Bool R200CheckCompositeTexture(PicturePtr pPict, int unit) RADEON_FALLBACK(("Unsupported picture format 0x%x\n", (int)pPict->format)); - if (pPict->repeat && ((w & (w - 1)) != 0 || (h & (h - 1)) != 0)) - RADEON_FALLBACK(("NPOT repeat unsupported (%dx%d)\n", w, h)); + if (!RADEONCheckTexturePOT(pPict, canTile)) + return FALSE; if (pPict->filter != PictFilterNearest && pPict->filter != PictFilterBilinear) @@ -689,11 +730,11 @@ static Bool R200CheckComposite(int op, PicturePtr pSrcPicture, PicturePtr pMaskP } } - if (!R200CheckCompositeTexture(pMaskPicture, 1)) + if (!R200CheckCompositeTexture(pMaskPicture, 1, FALSE)) return FALSE; } - if (!R200CheckCompositeTexture(pSrcPicture, 0)) + if (!R200CheckCompositeTexture(pSrcPicture, 0, TRUE)) return FALSE; if (!RADEONGetDestFormat(pDstPicture, &tmp1)) @@ -734,6 +775,9 @@ static Bool FUNC_NAME(R200PrepareComposite)(int op, PicturePtr pSrcPicture, if (((dst_pitch >> pixel_shift) & 0x7) != 0) RADEON_FALLBACK(("Bad destination pitch 0x%x\n", (int)dst_pitch)); + if (!RADEONSetupSourceTile(pSrcPicture)) + return FALSE; + if (!FUNC_NAME(R200TextureSetup)(pSrcPicture, pSrc, 0)) return FALSE; pp_cntl = RADEON_TEX_0_ENABLE | RADEON_TEX_BLEND_0_ENABLE; @@ -811,7 +855,7 @@ static Bool FUNC_NAME(R200PrepareComposite)(int op, PicturePtr pSrcPicture, #ifdef ONLY_ONCE -static Bool R300CheckCompositeTexture(PicturePtr pPict, int unit, Bool is_r500) +static Bool R300CheckCompositeTexture(PicturePtr pPict, int unit, Bool canTile, Bool is_r500) { int w = pPict->pDrawable->width; int h = pPict->pDrawable->height; @@ -838,8 +882,8 @@ static Bool R300CheckCompositeTexture(PicturePtr pPict, int unit, Bool is_r500) RADEON_FALLBACK(("Unsupported picture format 0x%x\n", (int)pPict->format)); - if (pPict->repeat && ((w & (w - 1)) != 0 || (h & (h - 1)) != 0)) - RADEON_FALLBACK(("NPOT repeat unsupported (%dx%d)\n", w, h)); + if (!RADEONCheckTexturePOT(pPict, canTile)) + return FALSE; if (pPict->filter != PictFilterNearest && pPict->filter != PictFilterBilinear) @@ -915,13 +959,16 @@ static Bool FUNC_NAME(R300TextureSetup)(PicturePtr pPict, PixmapPtr pPix, info->texW[unit] = w; info->texH[unit] = h; - if (pPict->repeat) - txfilter = (R300_TX_CLAMP_S(R300_TX_CLAMP_WRAP) | - R300_TX_CLAMP_T(R300_TX_CLAMP_WRAP)); + if (pPict->repeat && !need_src_tile_x) + txfilter = R300_TX_CLAMP_S(R300_TX_CLAMP_WRAP); else - txfilter = (R300_TX_CLAMP_S(R300_TX_CLAMP_CLAMP_GL) | - R300_TX_CLAMP_T(R300_TX_CLAMP_CLAMP_GL)); + txfilter = R300_TX_CLAMP_S(R300_TX_CLAMP_CLAMP_GL); + if (pPict->repeat && !need_src_tile_y) + txfilter |= R300_TX_CLAMP_T(R300_TX_CLAMP_WRAP); + else + txfilter |= R300_TX_CLAMP_T(R300_TX_CLAMP_CLAMP_GL); + txfilter |= (unit << R300_TX_ID_SHIFT); switch (pPict->filter) { @@ -1027,11 +1074,11 @@ static Bool R300CheckComposite(int op, PicturePtr pSrcPicture, PicturePtr pMaskP } } - if (!R300CheckCompositeTexture(pMaskPicture, 1, IS_R500_3D)) + if (!R300CheckCompositeTexture(pMaskPicture, 1, FALSE, IS_R500_3D)) return FALSE; } - if (!R300CheckCompositeTexture(pSrcPicture, 0, IS_R500_3D)) + if (!R300CheckCompositeTexture(pSrcPicture, 0, TRUE, IS_R500_3D)) return FALSE; if (!R300GetDestFormat(pDstPicture, &tmp1)) @@ -1077,6 +1124,9 @@ static Bool FUNC_NAME(R300PrepareComposite)(int op, PicturePtr pSrcPicture, if (((dst_pitch >> pixel_shift) & 0x7) != 0) RADEON_FALLBACK(("Bad destination pitch 0x%x\n", (int)dst_pitch)); + if (!RADEONSetupSourceTile(pSrcPicture)) + return FALSE; + if (!FUNC_NAME(R300TextureSetup)(pSrcPicture, pSrc, 0)) return FALSE; txenable = R300_TEX_0_ENABLE; @@ -1775,11 +1825,11 @@ static inline void transformPoint(PictTransform *transform, xPointFixed *point) } #endif -static void FUNC_NAME(RadeonComposite)(PixmapPtr pDst, - int srcX, int srcY, - int maskX, int maskY, - int dstX, int dstY, - int w, int h) +static void FUNC_NAME(RadeonCompositeTile)(PixmapPtr pDst, + int srcX, int srcY, + int maskX, int maskY, + int dstX, int dstY, + int w, int h) { RINFO_FROM_SCREEN(pDst->drawable.pScreen); int vtx_count; @@ -1903,6 +1953,72 @@ static void FUNC_NAME(RadeonComposite)(PixmapPtr pDst, } #undef VTX_OUT +static void FUNC_NAME(RadeonComposite)(PixmapPtr pDst, + int srcX, int srcY, + int maskX, int maskY, + int dstX, int dstY, + int width, int height) +{ + RINFO_FROM_SCREEN(pDst->drawable.pScreen); + int tileHeight, tileWidth; + int tileSrcY, tileMaskY, tileDstY; + int remainingHeight; + + if (!need_src_tile_x && !need_src_tile_y) { + FUNC_NAME(RadeonCompositeTile)(pDst, + srcX, srcY, + maskX, maskY, + dstX, dstY, + width, height); + return; + } + + /* Tiling logic borrowed from exaFillRegionTiled */ + + /* 65536 == "infinity" */ + tileWidth = need_src_tile_x ? info->texW[0] : 65536; + tileHeight = need_src_tile_y ? info->texH[0] : 65536; + + modulus(srcY, tileHeight, tileSrcY); + tileMaskY = maskY; + tileDstY = dstY; + + remainingHeight = height; + while (remainingHeight > 0) { + int remainingWidth = width; + int tileSrcX, tileMaskX, tileDstX; + int h = tileHeight - tileSrcY; + + if (h > remainingHeight) + h = remainingHeight; + remainingHeight -= h; + + modulus(srcX, tileWidth, tileSrcX); + tileMaskX = maskX; + tileDstX = dstX; + + while (remainingWidth > 0) { + int w = tileWidth - tileSrcX; + if (w > remainingWidth) + w = remainingWidth; + remainingWidth -= w; + + FUNC_NAME(RadeonCompositeTile)(pDst, + tileSrcX, tileSrcY, + tileMaskX, tileMaskY, + tileDstX, tileDstY, + w, h); + + tileSrcX = 0; + tileMaskX += w; + tileDstX += w; + } + tileSrcY = 0; + tileMaskY += h; + tileDstY += h; + } +} + #ifdef ONLY_ONCE static void RadeonDoneComposite(PixmapPtr pDst) { -- 1.5.4.5