summaryrefslogtreecommitdiff
path: root/src/radeon_exa_render.c
diff options
context:
space:
mode:
authorOwen Taylor <otaylor@huygens.home.fishsoup.net>2008-04-17 13:14:53 +0200
committerMichel Dänzer <michel@tungstengraphics.com>2008-04-17 13:36:36 +0200
commitc5d62fa0e8f52c3264ff9db3ff10cdf5a806bfc0 (patch)
tree5535bacf470aec18e0282219252e5eeb347419db /src/radeon_exa_render.c
parenteeb7b74bb6c813b0e3afa4b704f6ffb0d0aab92b (diff)
Emulate repeats by drawing in tiles
When we can't turn on hardware repeats, because the texture is non-power-of-two, or has padding at the ends of lines, try to draw the image in multiple tiles rather than falling back to software. (We can only do this when there is no transform.)
Diffstat (limited to 'src/radeon_exa_render.c')
-rw-r--r--src/radeon_exa_render.c215
1 files changed, 191 insertions, 24 deletions
diff --git a/src/radeon_exa_render.c b/src/radeon_exa_render.c
index e35cc176..138216fc 100644
--- a/src/radeon_exa_render.c
+++ b/src/radeon_exa_render.c
@@ -59,6 +59,12 @@
static Bool is_transform[2];
static PictTransform *transform[2];
static Bool has_mask;
+/* Whether we are tiling horizontally and vertically */
+static Bool need_src_tile_x;
+static Bool need_src_tile_y;
+/* Size of tiles ... set to 65536x65536 if not tiling in that direction */
+static Bool src_tile_width;
+static Bool src_tile_height;
struct blendinfo {
Bool dst_alpha;
@@ -222,6 +228,95 @@ union intfloat {
CARD32 i;
};
+/* Check if we need a software-fallback because of a repeating
+ * non-power-of-two texture.
+ *
+ * canTile: whether we can emulate a repeat by drawing in tiles:
+ * possible for the source, but not for the mask. (Actually
+ * we could do tiling for the mask too, but dealing with the
+ * combination of a tiled mask and a tiled source would be
+ * a lot of complexity, so we handle only the most common
+ * case of a repeating mask.)
+ */
+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;
+}
+
+/* Determine if the pitch of the pixmap meets the criteria for being
+ * used as a repeating texture: no padding or only a single line texture.
+ */
+static Bool RADEONPitchMatches(PixmapPtr pPix)
+{
+ int w = pPix->drawable.width;
+ int h = pPix->drawable.height;
+ CARD32 txpitch = exaGetPixmapPitch(pPix);
+
+ if (h > 1 && ((w * pPix->drawable.bitsPerPixel / 8 + 31) & ~31) != txpitch)
+ return FALSE;
+
+ 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 on R300 and newer, which is perfect.)
+ *
+ * canTile1d: On R300 and newer, we can repeat a texture that is NPOT in
+ * one direction and POT in the other in the POT direction; on
+ * older chips we can only repeat at all if the texture is POT in
+ * both directions.
+ *
+ * needMatchingPitch: On R100/R200, we can only repeat horizontally if
+ * there is no padding in the texture. Textures with small POT widths
+ * (1,2,4,8) thus can't be tiled.
+ */
+static Bool RADEONSetupSourceTile(PicturePtr pPict,
+ PixmapPtr pPix,
+ Bool canTile1d,
+ Bool needMatchingPitch)
+{
+ need_src_tile_x = need_src_tile_y = FALSE;
+ src_tile_width = src_tile_height = 65536; /* "infinite" */
+
+ if (pPict->repeat) {
+ Bool badPitch = needMatchingPitch && !RADEONPitchMatches(pPix);
+
+ int w = pPict->pDrawable->width;
+ int h = pPict->pDrawable->height;
+
+ if (pPict->transform) {
+ if (badPitch)
+ RADEON_FALLBACK(("Width %d and pitch %u not compatible for repeat\n",
+ w, (unsigned)exaGetPixmapPitch(pPix)));
+ } else {
+ need_src_tile_x = (w & (w - 1)) != 0 || badPitch;
+ need_src_tile_y = (h & (h - 1)) != 0;
+
+ if (!canTile1d)
+ need_src_tile_x = need_src_tile_y = need_src_tile_x || need_src_tile_y;
+ }
+
+ if (need_src_tile_x)
+ src_tile_width = w;
+ if (need_src_tile_y)
+ src_tile_height = h;
+ }
+
+ return TRUE;
+}
+
/* R100-specific code */
static Bool R100CheckCompositeTexture(PicturePtr pPict, int unit)
@@ -241,8 +336,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, unit == 0))
+ return FALSE;
if (pPict->filter != PictFilterNearest &&
pPict->filter != PictFilterBilinear)
@@ -262,6 +357,7 @@ static Bool FUNC_NAME(R100TextureSetup)(PicturePtr pPict, PixmapPtr pPix,
CARD32 txfilter, txformat, txoffset, txpitch;
int w = pPict->pDrawable->width;
int h = pPict->pDrawable->height;
+ Bool repeat = pPict->repeat && !(unit == 0 && (need_src_tile_x || need_src_tile_y));
int i;
ACCEL_PREAMBLE();
@@ -282,9 +378,8 @@ static Bool FUNC_NAME(R100TextureSetup)(PicturePtr pPict, PixmapPtr pPix,
if (RADEONPixmapIsColortiled(pPix))
txoffset |= RADEON_TXO_MACRO_TILE;
- if (pPict->repeat) {
- if ((h != 1) &&
- (((w * pPix->drawable.bitsPerPixel / 8 + 31) & ~31) != txpitch))
+ if (repeat) {
+ if (!RADEONPitchMatches(pPix))
RADEON_FALLBACK(("Width %d and pitch %u not compatible for repeat\n",
w, (unsigned)txpitch));
@@ -308,7 +403,7 @@ static Bool FUNC_NAME(R100TextureSetup)(PicturePtr pPict, PixmapPtr pPix,
RADEON_FALLBACK(("Bad filter 0x%x\n", pPict->filter));
}
- if (pPict->repeat)
+ if (repeat)
txfilter |= RADEON_CLAMP_S_WRAP | RADEON_CLAMP_T_WRAP;
BEGIN_ACCEL(5);
@@ -462,6 +557,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, pSrc, FALSE, TRUE))
+ return FALSE;
+
if (!FUNC_NAME(R100TextureSetup)(pSrcPicture, pSrc, 0))
return FALSE;
pp_cntl = RADEON_TEX_0_ENABLE | RADEON_TEX_BLEND_0_ENABLE;
@@ -553,8 +651,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, unit == 0))
+ return FALSE;
if (pPict->filter != PictFilterNearest &&
pPict->filter != PictFilterBilinear)
@@ -572,6 +670,7 @@ static Bool FUNC_NAME(R200TextureSetup)(PicturePtr pPict, PixmapPtr pPix,
CARD32 txfilter, txformat, txoffset, txpitch;
int w = pPict->pDrawable->width;
int h = pPict->pDrawable->height;
+ Bool repeat = pPict->repeat && !(unit == 0 && (need_src_tile_x || need_src_tile_y));
int i;
ACCEL_PREAMBLE();
@@ -592,9 +691,8 @@ static Bool FUNC_NAME(R200TextureSetup)(PicturePtr pPict, PixmapPtr pPix,
if (RADEONPixmapIsColortiled(pPix))
txoffset |= R200_TXO_MACRO_TILE;
- if (pPict->repeat) {
- if ((h != 1) &&
- (((w * pPix->drawable.bitsPerPixel / 8 + 31) & ~31) != txpitch))
+ if (repeat) {
+ if (!RADEONPitchMatches(pPix))
RADEON_FALLBACK(("Width %d and pitch %u not compatible for repeat\n",
w, (unsigned)txpitch));
@@ -620,7 +718,7 @@ static Bool FUNC_NAME(R200TextureSetup)(PicturePtr pPict, PixmapPtr pPix,
RADEON_FALLBACK(("Bad filter 0x%x\n", pPict->filter));
}
- if (pPict->repeat)
+ if (repeat)
txfilter |= R200_CLAMP_S_WRAP | R200_CLAMP_T_WRAP;
BEGIN_ACCEL(6);
@@ -756,6 +854,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, pSrc, FALSE, TRUE))
+ return FALSE;
+
if (!FUNC_NAME(R200TextureSetup)(pSrcPicture, pSrc, 0))
return FALSE;
pp_cntl = RADEON_TEX_0_ENABLE | RADEON_TEX_BLEND_0_ENABLE;
@@ -864,8 +965,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, unit == 0))
+ return FALSE;
if (pPict->filter != PictFilterNearest &&
pPict->filter != PictFilterBilinear)
@@ -941,13 +1042,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 && !(unit == 0 && 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 && !(unit == 0 && 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) {
@@ -1108,6 +1212,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, pSrc, TRUE, FALSE))
+ return FALSE;
+
if (!FUNC_NAME(R300TextureSetup)(pSrcPicture, pSrc, 0))
return FALSE;
txenable = R300_TEX_0_ENABLE;
@@ -1788,11 +1895,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;
@@ -1934,6 +2041,66 @@ static void FUNC_NAME(RadeonComposite)(PixmapPtr pDst,
#undef VTX_OUT
#undef VTX_OUT_MASK
+static void FUNC_NAME(RadeonComposite)(PixmapPtr pDst,
+ int srcX, int srcY,
+ int maskX, int maskY,
+ int dstX, int dstY,
+ int width, int height)
+{
+ 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 */
+
+ modulus(srcY, src_tile_height, tileSrcY);
+ tileMaskY = maskY;
+ tileDstY = dstY;
+
+ remainingHeight = height;
+ while (remainingHeight > 0) {
+ int remainingWidth = width;
+ int tileSrcX, tileMaskX, tileDstX;
+ int h = src_tile_height - tileSrcY;
+
+ if (h > remainingHeight)
+ h = remainingHeight;
+ remainingHeight -= h;
+
+ modulus(srcX, src_tile_width, tileSrcX);
+ tileMaskX = maskX;
+ tileDstX = dstX;
+
+ while (remainingWidth > 0) {
+ int w = src_tile_width - 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;
+ }
+}
+
static void FUNC_NAME(RadeonDoneComposite)(PixmapPtr pDst)
{
RINFO_FROM_SCREEN(pDst->drawable.pScreen);