[Nouveau] [PATCHv3 2/3] nv10/exa: Allow component-alpha masks.

Francisco Jerez currojerez at riseup.net
Wed Oct 7 19:10:11 PDT 2009


Signed-off-by: Francisco Jerez <currojerez at riseup.net>
---
 src/nv10_exa.c |  286 ++++++++++++++++++++++++++++++++------------------------
 1 files changed, 164 insertions(+), 122 deletions(-)

diff --git a/src/nv10_exa.c b/src/nv10_exa.c
index 4027982..eda92aa 100644
--- a/src/nv10_exa.c
+++ b/src/nv10_exa.c
@@ -39,6 +39,44 @@ typedef struct nv10_exa_state {
 } nv10_exa_state_t;
 static nv10_exa_state_t state;
 
+#define SF(x) NV10TCL_BLEND_FUNC_SRC_##x
+#define DF(x) NV10TCL_BLEND_FUNC_DST_##x
+
+static struct nv10_pictop {
+	int src;
+	int dst;
+} NV10PictOp [] = {
+	{ SF(ZERO),		   DF(ZERO) },		      /* Clear */
+	{ SF(ONE),		   DF(ZERO) },		      /* Src */
+	{ SF(ZERO),		   DF(ONE) },		      /* Dst */
+	{ SF(ONE),		   DF(ONE_MINUS_SRC_ALPHA) }, /* Over */
+	{ SF(ONE_MINUS_DST_ALPHA), DF(ONE) },		      /* OverReverse */
+	{ SF(DST_ALPHA),	   DF(ZERO) },                /* In */
+	{ SF(ZERO),		   DF(SRC_ALPHA) },           /* InReverse */
+	{ SF(ONE_MINUS_DST_ALPHA), DF(ZERO) },		      /* Out */
+	{ SF(ZERO),		   DF(ONE_MINUS_SRC_ALPHA) }, /* OutReverse */
+	{ SF(DST_ALPHA),	   DF(ONE_MINUS_SRC_ALPHA) }, /* Atop */
+	{ SF(ONE_MINUS_DST_ALPHA), DF(SRC_ALPHA) },	      /* AtopReverse */
+	{ SF(ONE_MINUS_DST_ALPHA), DF(ONE_MINUS_SRC_ALPHA) }, /* Xor */
+	{ SF(ONE),		   DF(ONE) },		      /* Add */
+};
+
+static inline bool needs_src_alpha(int op)
+{
+	return NV10PictOp[op].dst == DF(ONE_MINUS_SRC_ALPHA)
+		|| NV10PictOp[op].dst == DF(SRC_ALPHA);
+}
+
+static inline bool needs_src(int op)
+{
+	return NV10PictOp[op].src != DF(ZERO);
+}
+
+static inline bool effective_component_alpha(PicturePtr mask)
+{
+	return mask && mask->componentAlpha && PICT_FORMAT_RGB(mask->format);
+}
+
 static int NV10TexFormat(int ExaFormat)
 {
 	struct {int exa;int hw;} tex_format[] =
@@ -97,8 +135,6 @@ static Bool NV10CheckTexture(PicturePtr Picture)
 		return FALSE;
 	if (Picture->filter != PictFilterNearest && Picture->filter != PictFilterBilinear)
 		return FALSE;
-	if (Picture->componentAlpha)
-		return FALSE;
 	/* we cannot repeat on NV10 because NPOT textures do not support this. unfortunately. */
 	if (Picture->repeat != RepeatNone)
 		/* we can repeat 1x1 textures */
@@ -114,8 +150,6 @@ static Bool NV10CheckBuffer(PicturePtr Picture)
 
 	if ((w > 4096) || (h > 4096))
 		return FALSE;
-	if (Picture->componentAlpha)
-		return FALSE;
 	if (!NV10DstFormat(Picture->format))
 		return FALSE;
 	return TRUE;
@@ -265,6 +299,8 @@ NV10EXAFallbackInfo(char * reason, int op, PicturePtr pSrcPicture,
 		sprintf(out, "(%dx%d) ", pMaskPicture->pDrawable->width, pMaskPicture->pDrawable->height);
 		if ( pMaskPicture->repeat != RepeatNone )
 			strcat(out, "R ");
+		if ( pMaskPicture->componentAlpha )
+			strcat(out, "C ");
 		out+=strlen(out);
 	}
 	strcat(out, "\n");
@@ -296,19 +332,28 @@ Bool NV10EXACheckComposite(int	op,
 		NV10EXAFallbackInfo("dst", op, pSrcPicture, pMaskPicture, pDstPicture);
 		return FALSE;
 		}
-		
+
 	if (!NV10CheckTexture(pSrcPicture))
 		{
 		NV10EXAFallbackInfo("src", op, pSrcPicture, pMaskPicture, pDstPicture);
 		return FALSE;
 		}
-		
-	if ((pMaskPicture) &&(!NV10CheckTexture(pMaskPicture)))
-		{
-		NV10EXAFallbackInfo("mask", op, pSrcPicture, pMaskPicture, pDstPicture);
-		return FALSE;
+
+	if (pMaskPicture) {
+		if (!NV10CheckTexture(pMaskPicture)) {
+			NV10EXAFallbackInfo("mask", op, pSrcPicture,
+					    pMaskPicture, pDstPicture);
+			return FALSE;
 		}
-		
+
+		if (effective_component_alpha(pMaskPicture) &&
+		    needs_src(op) && needs_src_alpha(op)) {
+			NV10EXAFallbackInfo("ca-mask", op, pSrcPicture,
+					    pMaskPicture, pDstPicture);
+			return FALSE;
+		}
+	}
+
 	NV10EXAFallbackInfo("Accelerating", op, pSrcPicture, pMaskPicture, pDstPicture);
 	return TRUE;
 }
@@ -439,10 +484,16 @@ static void NV10SetBuffer(NVPtr pNv,PicturePtr Pict,PixmapPtr pixmap)
 	OUT_RING  (chan, 0);
 }
 
+#define RC_IN_ONE(chan, input)						\
+	(NV10TCL_RC_IN_##chan##_##input##_INPUT_ZERO			\
+	 | NV10TCL_RC_IN_##chan##_##input##_COMPONENT_USAGE_##chan	\
+	 | NV10TCL_RC_IN_##chan##_##input##_MAPPING_UNSIGNED_INVERT_NV)
+
 static void NV10SetRegCombs(NVPtr pNv, PicturePtr src, PicturePtr mask)
 {
 	struct nouveau_channel *chan = pNv->chan;
 	struct nouveau_grobj *celcius = pNv->Nv3D;
+	unsigned int rc0_in_alpha = 0, rc0_in_rgb = 0;
 
 /*This can be a bit difficult to understand at first glance.
 Reg combiners are described here:
@@ -463,65 +514,61 @@ RC 1s are unused
 Final combiner uses default setup
 	
 */
+	if (PICT_FORMAT_A(src->format))
+		rc0_in_alpha |= NV10TCL_RC_IN_ALPHA_A_INPUT_TEXTURE0_ARB
+			| NV10TCL_RC_IN_RGB_A_COMPONENT_USAGE_ALPHA;
+	else
+		rc0_in_alpha |= RC_IN_ONE(ALPHA, A);
 
-unsigned int rc0_in_alpha = 0, rc0_in_rgb = 0;
-unsigned int rc1_in_alpha = 0, rc1_in_rgb = 0;
-unsigned int color0 = 0, color1 = 0;
-#define A_ALPHA_ZERO (NV10TCL_RC_IN_ALPHA_A_INPUT_ZERO | NV10TCL_RC_IN_ALPHA_A_COMPONENT_USAGE_ALPHA)
-#define B_ALPHA_ZERO (NV10TCL_RC_IN_ALPHA_B_INPUT_ZERO | NV10TCL_RC_IN_ALPHA_B_COMPONENT_USAGE_ALPHA)
-#define C_ALPHA_ZERO (NV10TCL_RC_IN_ALPHA_C_INPUT_ZERO | NV10TCL_RC_IN_ALPHA_C_COMPONENT_USAGE_ALPHA)
-#define D_ALPHA_ZERO (NV10TCL_RC_IN_ALPHA_D_INPUT_ZERO | NV10TCL_RC_IN_ALPHA_D_COMPONENT_USAGE_ALPHA)
-	
-#define A_ALPHA_ONE (A_ALPHA_ZERO | (NV10TCL_RC_IN_ALPHA_A_MAPPING_UNSIGNED_INVERT_NV))
-#define B_ALPHA_ONE (B_ALPHA_ZERO | (NV10TCL_RC_IN_ALPHA_B_MAPPING_UNSIGNED_INVERT_NV))
-#define C_ALPHA_ONE (C_ALPHA_ZERO | (NV10TCL_RC_IN_ALPHA_C_MAPPING_UNSIGNED_INVERT_NV))
-#define D_ALPHA_ONE (D_ALPHA_ZERO | (NV10TCL_RC_IN_ALPHA_D_MAPPING_UNSIGNED_INVERT_NV))
-
-#define A_RGB_ZERO (NV10TCL_RC_IN_RGB_A_INPUT_ZERO | NV10TCL_RC_IN_RGB_A_COMPONENT_USAGE_RGB)
-#define B_RGB_ZERO (NV10TCL_RC_IN_RGB_B_INPUT_ZERO | NV10TCL_RC_IN_RGB_B_COMPONENT_USAGE_RGB)
-#define C_RGB_ZERO (NV10TCL_RC_IN_RGB_C_INPUT_ZERO | NV10TCL_RC_IN_RGB_C_COMPONENT_USAGE_RGB)
-#define D_RGB_ZERO (NV10TCL_RC_IN_RGB_D_INPUT_ZERO | NV10TCL_RC_IN_RGB_D_COMPONENT_USAGE_RGB)
-
-#define A_RGB_ONE (A_RGB_ZERO | NV10TCL_RC_IN_RGB_A_MAPPING_UNSIGNED_INVERT_NV)
-#define B_RGB_ONE (B_RGB_ZERO | NV10TCL_RC_IN_RGB_B_MAPPING_UNSIGNED_INVERT_NV)
-#define C_RGB_ONE (C_RGB_ZERO | NV10TCL_RC_IN_RGB_C_MAPPING_UNSIGNED_INVERT_NV)
-#define D_RGB_ONE (D_RGB_ZERO | NV10TCL_RC_IN_RGB_D_MAPPING_UNSIGNED_INVERT_NV)
-
-	rc0_in_alpha |= C_ALPHA_ZERO | D_ALPHA_ZERO;
-	if (src->format == PICT_x8r8g8b8)
-		rc0_in_alpha |= A_ALPHA_ONE;
+	if (mask && PICT_FORMAT_A(mask->format))
+		rc0_in_alpha |= NV10TCL_RC_IN_RGB_B_INPUT_TEXTURE1_ARB
+			| NV10TCL_RC_IN_RGB_B_COMPONENT_USAGE_ALPHA;
 	else
-		rc0_in_alpha |= 0x18000000;
+		rc0_in_alpha |= RC_IN_ONE(ALPHA, B);
+
+	if (effective_component_alpha(mask)) {
+		rc0_in_rgb |= NV10TCL_RC_IN_RGB_B_INPUT_TEXTURE1_ARB
+			| NV10TCL_RC_IN_RGB_B_COMPONENT_USAGE_RGB;
+
+		if (!needs_src_alpha(pNv->alu)) {
+			/*
+			 * The alpha channels won't be used for blending. Drop
+			 * them, as our pixels only have 4 components...
+			 * output_i = src_i * mask_i
+			 */
+			if (PICT_FORMAT_RGB(src->format))
+				rc0_in_rgb |= NV10TCL_RC_IN_RGB_A_INPUT_TEXTURE0_ARB
+					| NV10TCL_RC_IN_RGB_A_COMPONENT_USAGE_RGB;
+
+		} else {
+			/*
+			 * The RGB channels won't be used for blending. Drop
+			 * them.
+			 * output_i = src_alpha * mask_i
+			 */
+			if (PICT_FORMAT_A(src->format))
+				rc0_in_rgb |= NV10TCL_RC_IN_RGB_A_INPUT_TEXTURE0_ARB
+					| NV10TCL_RC_IN_RGB_A_COMPONENT_USAGE_ALPHA;
+			else
+				rc0_in_rgb |= RC_IN_ONE(RGB, A);
+		}
 
-	if ( ! mask ) 
-		rc0_in_alpha |= B_ALPHA_ONE;
-	else 
-		if ( mask->format == PICT_x8r8g8b8 )  /*no alpha? ignore it*/
-			rc0_in_alpha |= B_ALPHA_ONE;
-		else
-			rc0_in_alpha |= 0x00190000; /*B = a_1*/
-
-	rc0_in_rgb |=  C_RGB_ZERO | D_RGB_ZERO;
-	if (src->format == PICT_a8 )
-		rc0_in_rgb |= A_RGB_ZERO;
-	else 
-		rc0_in_rgb |= 0x08000000; /*A = rgb_0*/
-
-	if ( ! mask )
-		rc0_in_rgb |= B_RGB_ONE;
-	else 
-		if (  mask->format == PICT_x8r8g8b8 )  /*no alpha? ignore it*/
-			rc0_in_rgb |= B_RGB_ONE;
+	} else {
+		if (PICT_FORMAT_RGB(src->format))
+			rc0_in_rgb |= NV10TCL_RC_IN_RGB_A_INPUT_TEXTURE0_ARB
+				| NV10TCL_RC_IN_RGB_A_COMPONENT_USAGE_RGB;
+
+		if (mask && PICT_FORMAT_A(mask->format))
+			rc0_in_rgb |= NV10TCL_RC_IN_RGB_B_INPUT_TEXTURE1_ARB
+				| NV10TCL_RC_IN_RGB_B_COMPONENT_USAGE_ALPHA;
 		else
-			rc0_in_rgb |= 0x00190000; /*B = a_1*/
-		
-	BEGIN_RING(chan, celcius, NV10TCL_RC_IN_ALPHA(0), 6);
+			rc0_in_rgb |= RC_IN_ONE(RGB, B);
+	}
+
+	BEGIN_RING(chan, celcius, NV10TCL_RC_IN_ALPHA(0), 1);
 	OUT_RING  (chan, rc0_in_alpha);
-	OUT_RING  (chan, rc1_in_alpha);
+	BEGIN_RING(chan, celcius, NV10TCL_RC_IN_RGB(0), 1);
 	OUT_RING  (chan, rc0_in_rgb);
-	OUT_RING  (chan, rc1_in_rgb);
-	OUT_RING  (chan, color0); /*COLOR 0*/
-	OUT_RING  (chan, color1); /*COLOR 1*/
 }
 
 static void NV10SetRegCombs_A8plusA8(NVPtr pNv, int pass, int mask_out_bytes)
@@ -529,82 +576,70 @@ static void NV10SetRegCombs_A8plusA8(NVPtr pNv, int pass, int mask_out_bytes)
 	struct nouveau_channel *chan = pNv->chan;
 	struct nouveau_grobj *celcius = pNv->Nv3D;
 	unsigned int rc0_in_alpha = 0, rc0_in_rgb = 0;
-	unsigned int rc1_in_alpha = 0, rc1_in_rgb = 0;
 	unsigned int color0 = 0, color1 = 0;
 
-	if ( pass == 1)
-		{
-		if ( mask_out_bytes & 1 )
-			rc0_in_alpha = A_ALPHA_ZERO | B_ALPHA_ZERO | C_ALPHA_ZERO | D_ALPHA_ZERO;
-		else rc0_in_alpha = 0x19000000 | B_ALPHA_ONE | C_ALPHA_ZERO | D_ALPHA_ZERO;
-		
-		rc0_in_rgb = C_RGB_ZERO | D_RGB_ZERO;
-		
-		if ( mask_out_bytes & 2 )
-			rc0_in_rgb |= A_RGB_ZERO | B_RGB_ZERO;
-		else rc0_in_rgb |= 0x18000000 | 0x00010000;
-		
+	if (pass == 1) {
+		if (~mask_out_bytes & 1)
+			rc0_in_alpha |= NV10TCL_RC_IN_ALPHA_A_INPUT_TEXTURE1_ARB
+				| NV10TCL_RC_IN_ALPHA_A_COMPONENT_USAGE_ALPHA
+				| RC_IN_ONE(ALPHA, B);
+
+		if (~mask_out_bytes & 2)
+			rc0_in_rgb |= NV10TCL_RC_IN_RGB_A_INPUT_TEXTURE0_ARB
+				| NV10TCL_RC_IN_RGB_A_COMPONENT_USAGE_ALPHA
+				| NV10TCL_RC_IN_RGB_B_INPUT_CONSTANT_COLOR0_NV
+				| NV10TCL_RC_IN_RGB_B_COMPONENT_USAGE_RGB;
+
 		color0 = 0x00ff0000; /*R = 1 G = 0 B = 0*/
-		}
-	else {
-		rc0_in_alpha = A_ALPHA_ZERO | B_ALPHA_ZERO | C_ALPHA_ZERO | D_ALPHA_ZERO;
-		
-		rc0_in_rgb = 0;
-		
-		
-		
-		if ( mask_out_bytes & 8 )
-			rc0_in_rgb |= A_RGB_ZERO | B_RGB_ZERO;
-		else  rc0_in_rgb |= 0x18000000 | 0x00010000; /*A = a_0, B= cst color 0*/
-		
-		color0 = 0x000000ff; 
-		
-		if ( mask_out_bytes & 4)
-			rc0_in_rgb |= C_RGB_ZERO | D_RGB_ZERO;
-		else rc0_in_rgb |= 0x1900 | 0x02; /*C = a_1, D = cst color 1*/
-			
+	} else {
+		if (~mask_out_bytes & 8)
+			rc0_in_rgb |= NV10TCL_RC_IN_RGB_A_INPUT_TEXTURE0_ARB
+				| NV10TCL_RC_IN_RGB_A_COMPONENT_USAGE_ALPHA
+				| NV10TCL_RC_IN_RGB_B_INPUT_CONSTANT_COLOR0_NV
+				| NV10TCL_RC_IN_RGB_B_COMPONENT_USAGE_RGB;
+
+		color0 = 0x000000ff;
+
+		if (~mask_out_bytes & 4)
+			rc0_in_rgb |= NV10TCL_RC_IN_RGB_C_INPUT_TEXTURE1_ARB
+				| NV10TCL_RC_IN_RGB_C_COMPONENT_USAGE_ALPHA
+				| NV10TCL_RC_IN_RGB_D_INPUT_CONSTANT_COLOR1_NV
+				| NV10TCL_RC_IN_RGB_D_COMPONENT_USAGE_RGB;
+
 		color1 = 0x0000ff00; /*R = 0, G = 1, B = 0*/
-		}
+	}
 
-	BEGIN_RING(chan, celcius, NV10TCL_RC_IN_ALPHA(0), 6);
+	BEGIN_RING(chan, celcius, NV10TCL_RC_IN_ALPHA(0), 1);
 	OUT_RING  (chan, rc0_in_alpha);
-	OUT_RING  (chan, rc1_in_alpha);
+	BEGIN_RING(chan, celcius, NV10TCL_RC_IN_RGB(0), 1);
 	OUT_RING  (chan, rc0_in_rgb);
-	OUT_RING  (chan, rc1_in_rgb);
-	OUT_RING  (chan, color0); /*COLOR 0*/
-	OUT_RING  (chan, color1); /*COLOR 1*/
+	BEGIN_RING(chan, celcius, NV10TCL_RC_COLOR(0), 2);
+	OUT_RING  (chan, color0);
+	OUT_RING  (chan, color1);
 }
 
 static void NV10SetPictOp(NVPtr pNv,int op)
 {
 	struct nouveau_channel *chan = pNv->chan;
 	struct nouveau_grobj *celcius = pNv->Nv3D;
-	struct {int src;int dst;} pictops[] =
-	{
-		{0x0000,0x0000}, /* PictOpClear */
-		{0x0001,0x0000}, /* PictOpSrc */
-		{0x0000,0x0001}, /* PictOpDst */
-		{0x0001,0x0303}, /* PictOpOver */
-		{0x0305,0x0001}, /* PictOpOverReverse */
-		{0x0304,0x0000}, /* PictOpIn */
-		{0x0000,0x0302}, /* PictOpInReverse */
-		{0x0305,0x0000}, /* PictOpOut */
-		{0x0000,0x0303}, /* PictOpOutReverse */
-		{0x0304,0x0303}, /* PictOpAtop */
-		{0x0305,0x0302}, /* PictOpAtopReverse */
-		{0x0305,0x0303}, /* PictOpXor */
-		{0x0001,0x0001}, /* PictOpAdd */
-	};
-	int src_factor = pictops[op].src;
-	int dst_factor = pictops[op].dst;
-	
-	if (src_factor == NV10TCL_BLEND_FUNC_SRC_ONE_MINUS_DST_ALPHA &&
+	struct nv10_pictop *nv10_op = &NV10PictOp[op];
+	int src_factor = nv10_op->src;
+	int dst_factor = nv10_op->dst;
+
+	if (src_factor == SF(ONE_MINUS_DST_ALPHA) &&
 	    !PICT_FORMAT_A(pNv->pdpict->format))
 		/* ONE_MINUS_DST_ALPHA doesn't always do the right thing for
 		 * framebuffers without alpha channel. But it's the same as
 		 * ZERO in that case.
 		 */
-		src_factor = NV10TCL_BLEND_FUNC_SRC_ZERO;
+		src_factor = SF(ZERO);
+
+	if (effective_component_alpha(pNv->pmpict)) {
+		if (dst_factor == DF(SRC_ALPHA))
+			dst_factor = DF(SRC_COLOR);
+		else if (dst_factor == DF(ONE_MINUS_SRC_ALPHA))
+			dst_factor = DF(ONE_MINUS_SRC_COLOR);
+	}
 
 	BEGIN_RING(chan, celcius, NV10TCL_BLEND_FUNC_SRC, 2);
 	OUT_RING  (chan, src_factor);
@@ -1001,6 +1036,13 @@ NVAccelInitNV10TCL(ScrnInfoPtr pScrn)
 	BEGIN_RING(chan, celcius, NV10TCL_TX_ENABLE(0), 2);
 	OUT_RING  (chan, 0);
 	OUT_RING  (chan, 0);
+	BEGIN_RING(chan, celcius, NV10TCL_RC_IN_ALPHA(0), 6);
+	OUT_RING  (chan, 0);
+	OUT_RING  (chan, 0);
+	OUT_RING  (chan, 0);
+	OUT_RING  (chan, 0);
+	OUT_RING  (chan, 0);
+	OUT_RING  (chan, 0);
 	BEGIN_RING(chan, celcius, NV10TCL_RC_OUT_ALPHA(0), 6);
 	OUT_RING  (chan, 0x00000c00);
 	OUT_RING  (chan, 0);
-- 
1.6.3.3



More information about the Nouveau mailing list