Greatly improve the correctness and performance of the MGA render

implementation. Includes cache flushing to prevent bad first reads of
    the framebuffer, fixing blending of many formats, falling back on many
    unsupported operations, and falling back early to prevent migration.
    Passes all of rendercheck except some of the blend (!) tests.
This commit is contained in:
Eric Anholt 2005-06-09 21:59:26 +00:00
parent 9f81ce9456
commit e11e60b361
4 changed files with 185 additions and 114 deletions

View File

@ -51,6 +51,7 @@
# define MGA_SRC_DST_ALPHA (0x00000006) # define MGA_SRC_DST_ALPHA (0x00000006)
# define MGA_SRC_ONE_MINUS_DST_ALPHA (0x00000007) # define MGA_SRC_ONE_MINUS_DST_ALPHA (0x00000007)
# define MGA_SRC_SRC_ALPHA_SATURATE (0x00000008) # define MGA_SRC_SRC_ALPHA_SATURATE (0x00000008)
# define MGA_SRC_BLEND_MASK (0x0000000f)
# define MGA_DST_ZERO (0x00000000) # define MGA_DST_ZERO (0x00000000)
# define MGA_DST_ONE (0x00000010) # define MGA_DST_ONE (0x00000010)
@ -60,6 +61,7 @@
# define MGA_DST_ONE_MINUS_SRC_ALPHA (0x00000050) # define MGA_DST_ONE_MINUS_SRC_ALPHA (0x00000050)
# define MGA_DST_DST_ALPHA (0x00000060) # define MGA_DST_DST_ALPHA (0x00000060)
# define MGA_DST_ONE_MINUS_DST_ALPHA (0x00000070) # define MGA_DST_ONE_MINUS_DST_ALPHA (0x00000070)
# define MGA_DST_BLEND_MASK (0x00000070)
# define MGA_ALPHACHANNEL (0x00000100) # define MGA_ALPHACHANNEL (0x00000100)
# define MGA_VIDEOALPHA (0x00000200) # define MGA_VIDEOALPHA (0x00000200)
@ -93,7 +95,7 @@
# define MGA_TW8AL (0x00000008) # define MGA_TW8AL (0x00000008)
# define MGA_TW422 (0x0000000A) # define MGA_TW422 (0x0000000A)
# define MGA_TW422UYVY (0x0000000B) # define MGA_TW422UYVY (0x0000000B)
# define MGA_PITCHEXT (0x00000100) # define MGA_PITCHLIN (0x00000100)
# define MGA_NOPERSPECTIVE (0x00200000) # define MGA_NOPERSPECTIVE (0x00200000)
# define MGA_TAKEY (0x02000000) # define MGA_TAKEY (0x02000000)
# define MGA_TAMASK (0x04000000) # define MGA_TAMASK (0x04000000)
@ -168,14 +170,8 @@
/* Composition Prototypes. MMIO Access */ /* Composition Prototypes. MMIO Access */
Bool Bool
mgaPrepareBlend(int op, PicturePtr pSrcPicture, PicturePtr pDstPicture, mgaCheckComposite(int op, PicturePtr pSrcPicture, PicturePtr pMaskPicture,
PixmapPtr pSrc, PixmapPtr pDst); PicturePtr pDstPicture);
void
mgaBlend(int srcX, int srcY, int dstX, int dstY, int width, int height);
void
mgaDoneBlend(void);
Bool Bool
mgaPrepareComposite(int op, PicturePtr pSrcPicture, PicturePtr pMaskPicture, mgaPrepareComposite(int op, PicturePtr pSrcPicture, PicturePtr pMaskPicture,

View File

@ -34,37 +34,56 @@
static PixmapPtr currentSrc; static PixmapPtr currentSrc;
static PixmapPtr currentMask; static PixmapPtr currentMask;
static CARD32 mgaBlendOP[14] = { struct blendinfo {
/* Clear */ Bool dst_alpha;
MGA_SRC_ZERO | MGA_DST_ZERO, Bool src_alpha;
/* Src */ CARD32 blend_cntl;
MGA_SRC_ONE | MGA_DST_ZERO,
/* Dst */
MGA_SRC_ZERO | MGA_DST_ONE,
/* Over */
MGA_SRC_ALPHA | MGA_DST_ONE_MINUS_SRC_ALPHA,
/* OverReverse */
MGA_SRC_ONE_MINUS_DST_ALPHA | MGA_DST_ONE,
/* In */
MGA_SRC_DST_ALPHA | MGA_DST_ZERO,
/* InReverse */
MGA_SRC_ZERO | MGA_DST_SRC_ALPHA,
/* Out */
MGA_SRC_ONE_MINUS_DST_ALPHA | MGA_DST_ZERO,
/* OutReverse */
MGA_SRC_ZERO | MGA_DST_ONE_MINUS_SRC_ALPHA,
/* Atop */
MGA_SRC_DST_ALPHA | MGA_DST_ONE_MINUS_SRC_ALPHA,
/* AtopReverse */
MGA_SRC_ONE_MINUS_DST_ALPHA | MGA_DST_SRC_ALPHA,
/* Xor */
MGA_SRC_ONE_MINUS_DST_ALPHA | MGA_DST_ONE_MINUS_SRC_ALPHA,
/* Add */
MGA_SRC_ONE | MGA_DST_ONE,
/* Saturate */
MGA_SRC_SRC_ALPHA_SATURATE | MGA_DST_ONE
}; };
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 ) static int MGA_LOG2( int val )
{ {
@ -76,37 +95,32 @@ static int MGA_LOG2( int val )
return ((1 << (ret-1)) == val) ? (ret-1) : ret; return ((1 << (ret-1)) == val) ? (ret-1) : ret;
} }
static Bool
Bool mgaCheckSourceTexture (int tmu,
mgaPrepareBlend (int op, PicturePtr pPict)
PicturePtr pSrcPicture,
PicturePtr pDstPicture,
PixmapPtr pSrc,
PixmapPtr pDst)
{ {
return mgaPrepareComposite (op, pSrcPicture, NULL, pDstPicture, int w = pPict->pDrawable->width;
pSrc, NULL, pDst); int h = pPict->pDrawable->height;
int i;
CARD32 texctl = 0;
if ((w > 2047) || (h > 2047))
MGA_FALLBACK(("Picture too large for composition (%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(("Picture is in unsupported format 0x%x\n"
pPict->format));
} }
void return TRUE;
mgaBlend (int srcX,
int srcY,
int dstX,
int dstY,
int width,
int height)
{
mgaComposite (srcX, srcY, 0, 0, dstX, dstY, width, height);
} }
void
mgaDoneBlend (void)
{
mgaDoneComposite ();
}
static Bool static Bool
PrepareSourceTexture (int tmu, PrepareSourceTexture (int tmu,
PicturePtr pSrcPicture, PicturePtr pSrcPicture,
@ -115,39 +129,31 @@ PrepareSourceTexture (int tmu,
KdScreenPriv (pSrc->drawable.pScreen); KdScreenPriv (pSrc->drawable.pScreen);
int mem_base=(int)pScreenPriv->screen->memory_base; int mem_base=(int)pScreenPriv->screen->memory_base;
int pitch = pSrc->devKind / (pSrc->drawable.bitsPerPixel >> 3); int pitch = pSrc->devKind / (pSrc->drawable.bitsPerPixel >> 3);
int i;
int w = pSrc->drawable.width; int w = pSrc->drawable.width;
int h = pSrc->drawable.height; int h = pSrc->drawable.height;
int w_log2 = MGA_LOG2(w); int w_log2 = MGA_LOG2(w);
int h_log2 = MGA_LOG2(h); int h_log2 = MGA_LOG2(h);
int texctl=MGA_PITCHEXT | ((pitch&0x7ff)<<9) | int texctl = MGA_PITCHLIN | ((pitch & (2048 - 1)) << 9) |
MGA_TAKEY | MGA_CLAMPUV | MGA_NOPERSPECTIVE; MGA_CLAMPUV | MGA_NOPERSPECTIVE;
int texctl2=MGA_G400_TC2_MAGIC; int texctl2=MGA_G400_TC2_MAGIC;
if ((w > 2047) || (h > 2047)) for (i = 0; i < sizeof(texformats) / sizeof(texformats[0]); i++) {
MGA_FALLBACK(("Picture too large for composition (%dx%d)\n", w, h)); if (texformats[i].fmt == pSrcPicture->format) {
texctl |= texformats[i].card_fmt;
switch (pSrcPicture->format) {
case PICT_a8r8g8b8:
case PICT_x8r8g8b8:
case PICT_a8b8g8r8:
case PICT_x8b8g8r8:
texctl |= MGA_TW32;
break; break;
case PICT_r5g6b5: }
case PICT_b5g6r5: }
texctl |= MGA_TW16; if (PICT_FORMAT_A(pSrcPicture->format) != 0) {
break; texctl |= MGA_TAKEY;
case PICT_a8: } else {
texctl |= MGA_TW8A; texctl |= MGA_TAMASK | MGA_TAKEY;
break;
default:
MGA_FALLBACK(("unsupported Picture format for composition (%x)\n",
pSrcPicture->format));
} }
if (tmu == 1) texctl2 |= MGA_TC2_DUALTEX | MGA_TC2_SELECT_TMU1; if (tmu == 1)
texctl2 |= MGA_TC2_DUALTEX | MGA_TC2_SELECT_TMU1;
mgaWaitAvail (6); mgaWaitAvail (6);
MGA_OUT32 (mmio, MGA_REG_TEXCTL2, texctl2); MGA_OUT32 (mmio, MGA_REG_TEXCTL2, texctl2);
@ -167,6 +173,50 @@ PrepareSourceTexture (int tmu,
return TRUE; return TRUE;
} }
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 (pSrcPicture->transform != NULL)
MGA_FALLBACK(("Transformed src unsupported"));
if (pMaskPicture != NULL) {
if (PICT_FORMAT_A(pMaskPicture->format) == 0)
MGA_FALLBACK(("Mask without alpha unsupported"));
if (!mgaCheckSourceTexture (1, pMaskPicture))
return FALSE;
if (pMaskPicture->transform != NULL)
MGA_FALLBACK(("Transformed mask unsupported"));
}
if (pMaskPicture->componentAlpha)
MGA_FALLBACK(("Component alpha unsupported"));
switch (pDstPicture->format) {
case PICT_a8:
MGA_FALLBACK(("render to A8 unsupported"));
}
return TRUE;
}
#define C_ARG1_CUR 0x0
#define C_ARG2_DIFFUSE MGA_TDS_COLOR_ARG2_DIFFUSE
#define C_ARG2_PREV MGA_TDS_COLOR_ARG2_PREVSTAGE
#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_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 Bool
mgaPrepareComposite (int op, mgaPrepareComposite (int op,
PicturePtr pSrcPicture, PicturePtr pSrcPicture,
@ -178,17 +228,7 @@ mgaPrepareComposite (int op,
{ {
KdScreenPriv (pSrc->drawable.pScreen); KdScreenPriv (pSrc->drawable.pScreen);
int mem_base=(int)pScreenPriv->screen->memory_base; int mem_base=(int)pScreenPriv->screen->memory_base;
int cmd; int cmd, blendcntl;
/* sometimes mgaPrepareComposite is given the same pointer for Src
* and Mask. PSrcPicture is an unsupported format (x8b8g8r8) whereas
* pMaskPicture is supported (a8r8g8b8). We Choose to render a
* simple blend and using pMaskPicture as the Source.
*/
if (pMask == pSrc) {
pMask=NULL;
pMaskPicture=NULL;
}
mgaWaitIdle(); mgaWaitIdle();
/* Init MGA (clipping) */ /* Init MGA (clipping) */
@ -202,6 +242,18 @@ mgaPrepareComposite (int op,
MGA_OUT32 (mmio, MGA_REG_TMR7, 0); MGA_OUT32 (mmio, MGA_REG_TMR7, 0);
MGA_OUT32 (mmio, MGA_REG_TMR8, 0x10000); MGA_OUT32 (mmio, MGA_REG_TMR8, 0x10000);
/* Initialize colors to 0, used in the src = A8 case */
mgaWaitAvail(9);
MGA_OUT32 (mmio, MGA_REG_DR4, 0);
MGA_OUT32 (mmio, MGA_REG_DR6, 0);
MGA_OUT32 (mmio, MGA_REG_DR7, 0);
MGA_OUT32 (mmio, MGA_REG_DR8, 0);
MGA_OUT32 (mmio, MGA_REG_DR10, 0);
MGA_OUT32 (mmio, MGA_REG_DR11, 0);
MGA_OUT32 (mmio, MGA_REG_DR12, 0);
MGA_OUT32 (mmio, MGA_REG_DR14, 0);
MGA_OUT32 (mmio, MGA_REG_DR15, 0);
/* Destination flags */ /* Destination flags */
mgaWaitAvail (2); mgaWaitAvail (2);
MGA_OUT32 (mmio, MGA_REG_DSTORG, ((int)pDst->devPrivate.ptr - mem_base)); MGA_OUT32 (mmio, MGA_REG_DSTORG, ((int)pDst->devPrivate.ptr - mem_base));
@ -215,16 +267,28 @@ mgaPrepareComposite (int op,
/* MultiTexture modulation */ /* MultiTexture modulation */
mgaWaitAvail (2); mgaWaitAvail (2);
MGA_OUT32 (mmio, MGA_REG_TDUALSTAGE0, MGA_TDS_COLOR_SEL_ARG1); if (pSrcPicture->format == PICT_a8) {
/* C = 0 A = As */
MGA_OUT32 (mmio, MGA_REG_TDUALSTAGE0,
C_ARG2_DIFFUSE | COLOR_ARG2 |
A_ARG1_CUR | ALPHA_ARG1);
} else {
/* C = Cs A = As */
MGA_OUT32 (mmio, MGA_REG_TDUALSTAGE0,
C_ARG1_CUR | COLOR_ARG1 |
A_ARG1_CUR | ALPHA_ARG1);
}
if (pMask != NULL) { if (pMask != NULL) {
if (PICT_FORMAT_A (pSrcPicture->format) == 0) { if (PICT_FORMAT_A (pSrcPicture->format) == 0) {
MGA_OUT32 (mmio, MGA_REG_TDUALSTAGE1, MGA_OUT32 (mmio, MGA_REG_TDUALSTAGE1,
MGA_TDS_COLOR_ARG2_PREVSTAGE | MGA_TDS_COLOR_SEL_ARG2 | C_ARG1_CUR | C_ARG2_PREV | COLOR_MUL |
MGA_TDS_ALPHA_SEL_ARG1); A_ARG1_CUR | A_ARG2_IGN | ALPHA_ARG1 |
MGA_TDS_COLOR_ARG1_REPLICATEALPHA);
} else { } else {
MGA_OUT32 (mmio, MGA_REG_TDUALSTAGE1, MGA_OUT32 (mmio, MGA_REG_TDUALSTAGE1,
MGA_TDS_COLOR_ARG2_PREVSTAGE | MGA_TDS_COLOR_SEL_ARG2 | C_ARG1_CUR | C_ARG2_PREV | COLOR_MUL |
MGA_TDS_ALPHA_ARG2_PREVSTAGE | MGA_TDS_ALPHA_SEL_MUL); A_ARG1_CUR | A_ARG2_PREV | ALPHA_MUL |
MGA_TDS_COLOR_ARG1_REPLICATEALPHA);
} }
} else { } else {
MGA_OUT32 (mmio, MGA_REG_TDUALSTAGE1, 0); MGA_OUT32 (mmio, MGA_REG_TDUALSTAGE1, 0);
@ -234,9 +298,17 @@ mgaPrepareComposite (int op,
MGA_DWGCTL_SHIFTZERO | MGA_DWGCTL_SGNZERO | MGA_DWGCTL_ARZERO | MGA_DWGCTL_SHIFTZERO | MGA_DWGCTL_SGNZERO | MGA_DWGCTL_ARZERO |
MGA_ATYPE_I; 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); mgaWaitAvail (2);
MGA_OUT32 (mmio, MGA_REG_DWGCTL, cmd); MGA_OUT32 (mmio, MGA_REG_DWGCTL, cmd);
MGA_OUT32 (mmio, MGA_REG_ALPHACTRL, MGA_ALPHACHANNEL | mgaBlendOP[op]); MGA_OUT32 (mmio, MGA_REG_ALPHACTRL, MGA_ALPHACHANNEL | blendcntl);
currentSrc=pSrc; currentSrc=pSrc;
currentMask=pMask; currentMask=pMask;

View File

@ -56,6 +56,7 @@
#define MGA_REG_YBOT (0x1c9c) #define MGA_REG_YBOT (0x1c9c)
#define MGA_REG_FIFOSTATUS (0x1e10) #define MGA_REG_FIFOSTATUS (0x1e10)
#define MGA_REG_STATUS (0x1e14) #define MGA_REG_STATUS (0x1e14)
#define MGA_REG_CACHEFLUSH (0x1fff)
#define MGA_REG_SRCORG (0x2cb4) #define MGA_REG_SRCORG (0x2cb4)
#define MGA_REG_DSTORG (0x2cb8) #define MGA_REG_DSTORG (0x2cb8)

View File

@ -68,7 +68,11 @@ mgaWaitAvail (int n)
void void
mgaWaitIdle (void) mgaWaitIdle (void)
{ {
while (MGA_IN32 (mmio, MGA_REG_STATUS) & 0x10000); while (MGA_IN32 (mmio, MGA_REG_STATUS) & 0x10000)
;
mgaWaitAvail (1);
MGA_OUT32(mmio, MGA_REG_CACHEFLUSH, 0);
} }
static void static void
@ -268,9 +272,7 @@ mgaDrawInit (ScreenPtr pScreen)
mgas->kaa.flags = KAA_OFFSCREEN_PIXMAPS; mgas->kaa.flags = KAA_OFFSCREEN_PIXMAPS;
if (card->attr.deviceID == MGA_G4XX_DEVICE_ID) { if (card->attr.deviceID == MGA_G4XX_DEVICE_ID) {
mgas->kaa.PrepareBlend = mgaPrepareBlend; mgas->kaa.CheckComposite = mgaCheckComposite;
mgas->kaa.Blend = mgaBlend;
mgas->kaa.DoneBlend = mgaDoneBlend;
mgas->kaa.PrepareComposite = mgaPrepareComposite; mgas->kaa.PrepareComposite = mgaPrepareComposite;
mgas->kaa.Composite = mgaComposite; mgas->kaa.Composite = mgaComposite;
mgas->kaa.DoneComposite = mgaDoneComposite; mgas->kaa.DoneComposite = mgaDoneComposite;