mesa: begin implementation of GL_ARB_draw_buffers_blend
diff --git a/src/mesa/drivers/common/driverfuncs.c b/src/mesa/drivers/common/driverfuncs.c
index fc67bee..3c6ecb8 100644
--- a/src/mesa/drivers/common/driverfuncs.c
+++ b/src/mesa/drivers/common/driverfuncs.c
@@ -231,13 +231,14 @@
    ctx->Driver.BlendColor(ctx, ctx->Color.BlendColor);
 
    ctx->Driver.BlendEquationSeparate(ctx,
-                                     ctx->Color.BlendEquationRGB,
-                                     ctx->Color.BlendEquationA);
+                                     ctx->Color.Blend[0].EquationRGB,
+                                     ctx->Color.Blend[0].EquationA);
 
    ctx->Driver.BlendFuncSeparate(ctx,
-                                 ctx->Color.BlendSrcRGB,
-                                 ctx->Color.BlendDstRGB,
-                                 ctx->Color.BlendSrcA, ctx->Color.BlendDstA);
+                                 ctx->Color.Blend[0].SrcRGB,
+                                 ctx->Color.Blend[0].DstRGB,
+                                 ctx->Color.Blend[0].SrcA,
+                                 ctx->Color.Blend[0].DstA);
 
    if (ctx->Driver.ColorMaskIndexed) {
       GLuint i;
diff --git a/src/mesa/drivers/dri/i810/i810state.c b/src/mesa/drivers/dri/i810/i810state.c
index 7c3fbb1..6040abf 100644
--- a/src/mesa/drivers/dri/i810/i810state.c
+++ b/src/mesa/drivers/dri/i810/i810state.c
@@ -95,7 +95,7 @@
    GLuint a = SDM_UPDATE_SRC_BLEND | SDM_UPDATE_DST_BLEND;
    GLboolean fallback = GL_FALSE;
 
-   switch (ctx->Color.BlendSrcRGB) {
+   switch (ctx->Color.Blend[0].SrcRGB) {
    case GL_ZERO:                a |= SDM_SRC_ZERO; break;
    case GL_ONE:                 a |= SDM_SRC_ONE; break;
    case GL_SRC_COLOR:           a |= SDM_SRC_SRC_COLOR; break;
@@ -124,7 +124,7 @@
       return;
    }
 
-   switch (ctx->Color.BlendDstRGB) {
+   switch (ctx->Color.Blend[0].DstRGB) {
    case GL_ZERO:                a |= SDM_DST_ZERO; break;
    case GL_ONE:                 a |= SDM_DST_ONE; break;
    case GL_SRC_COLOR:           a |= SDM_DST_SRC_COLOR; break;
diff --git a/src/mesa/drivers/dri/i915/i830_state.c b/src/mesa/drivers/dri/i915/i830_state.c
index 147192a..ef5b8d9 100644
--- a/src/mesa/drivers/dri/i915/i830_state.c
+++ b/src/mesa/drivers/dri/i915/i830_state.c
@@ -291,10 +291,10 @@
 
 
    funcRGB =
-      SRC_BLND_FACT(intel_translate_blend_factor(ctx->Color.BlendSrcRGB))
-      | DST_BLND_FACT(intel_translate_blend_factor(ctx->Color.BlendDstRGB));
+      SRC_BLND_FACT(intel_translate_blend_factor(ctx->Color.Blend[0].SrcRGB))
+      | DST_BLND_FACT(intel_translate_blend_factor(ctx->Color.Blend[0].DstRGB));
 
-   switch (ctx->Color.BlendEquationRGB) {
+   switch (ctx->Color.Blend[0].EquationRGB) {
    case GL_FUNC_ADD:
       eqnRGB = BLENDFUNC_ADD;
       break;
@@ -314,15 +314,15 @@
       break;
    default:
       fprintf(stderr, "[%s:%u] Invalid RGB blend equation (0x%04x).\n",
-              __FUNCTION__, __LINE__, ctx->Color.BlendEquationRGB);
+              __FUNCTION__, __LINE__, ctx->Color.Blend[0].EquationRGB);
       return;
    }
 
 
-   funcA = SRC_ABLEND_FACT(intel_translate_blend_factor(ctx->Color.BlendSrcA))
-      | DST_ABLEND_FACT(intel_translate_blend_factor(ctx->Color.BlendDstA));
+   funcA = SRC_ABLEND_FACT(intel_translate_blend_factor(ctx->Color.Blend[0].SrcA))
+      | DST_ABLEND_FACT(intel_translate_blend_factor(ctx->Color.Blend[0].DstA));
 
-   switch (ctx->Color.BlendEquationA) {
+   switch (ctx->Color.Blend[0].EquationA) {
    case GL_FUNC_ADD:
       eqnA = BLENDFUNC_ADD;
       break;
@@ -342,7 +342,7 @@
       break;
    default:
       fprintf(stderr, "[%s:%u] Invalid alpha blend equation (0x%04x).\n",
-              __FUNCTION__, __LINE__, ctx->Color.BlendEquationA);
+              __FUNCTION__, __LINE__, ctx->Color.Blend[0].EquationA);
       return;
    }
 
diff --git a/src/mesa/drivers/dri/i915/i915_state.c b/src/mesa/drivers/dri/i915/i915_state.c
index 9508fba..63c6e78 100644
--- a/src/mesa/drivers/dri/i915/i915_state.c
+++ b/src/mesa/drivers/dri/i915/i915_state.c
@@ -267,12 +267,12 @@
                   ~(S6_CBUF_SRC_BLEND_FACT_MASK |
                     S6_CBUF_DST_BLEND_FACT_MASK | S6_CBUF_BLEND_FUNC_MASK));
 
-   GLuint eqRGB = ctx->Color.BlendEquationRGB;
-   GLuint eqA = ctx->Color.BlendEquationA;
-   GLuint srcRGB = ctx->Color.BlendSrcRGB;
-   GLuint dstRGB = ctx->Color.BlendDstRGB;
-   GLuint srcA = ctx->Color.BlendSrcA;
-   GLuint dstA = ctx->Color.BlendDstA;
+   GLuint eqRGB = ctx->Color.Blend[0].EquationRGB;
+   GLuint eqA = ctx->Color.Blend[0].EquationA;
+   GLuint srcRGB = ctx->Color.Blend[0].SrcRGB;
+   GLuint dstRGB = ctx->Color.Blend[0].DstRGB;
+   GLuint srcA = ctx->Color.Blend[0].SrcA;
+   GLuint dstA = ctx->Color.Blend[0].DstA;
 
    if (eqRGB == GL_MIN || eqRGB == GL_MAX) {
       srcRGB = dstRGB = GL_ONE;
diff --git a/src/mesa/drivers/dri/i965/brw_cc.c b/src/mesa/drivers/dri/i965/brw_cc.c
index d286c9d..c986970 100644
--- a/src/mesa/drivers/dri/i965/brw_cc.c
+++ b/src/mesa/drivers/dri/i965/brw_cc.c
@@ -141,12 +141,12 @@
       cc.cc2.logicop_enable = 1;
       cc.cc5.logicop_func = intel_translate_logic_op(ctx->Color.LogicOp);
    } else if (ctx->Color.BlendEnabled) {
-      GLenum eqRGB = ctx->Color.BlendEquationRGB;
-      GLenum eqA = ctx->Color.BlendEquationA;
-      GLenum srcRGB = ctx->Color.BlendSrcRGB;
-      GLenum dstRGB = ctx->Color.BlendDstRGB;
-      GLenum srcA = ctx->Color.BlendSrcA;
-      GLenum dstA = ctx->Color.BlendDstA;
+      GLenum eqRGB = ctx->Color.Blend[0].EquationRGB;
+      GLenum eqA = ctx->Color.Blend[0].EquationA;
+      GLenum srcRGB = ctx->Color.Blend[0].SrcRGB;
+      GLenum dstRGB = ctx->Color.Blend[0].DstRGB;
+      GLenum srcA = ctx->Color.Blend[0].SrcA;
+      GLenum dstA = ctx->Color.Blend[0].DstA;
 
       /* If the renderbuffer is XRGB, we have to frob the blend function to
        * force the destination alpha to 1.0.  This means replacing GL_DST_ALPHA
diff --git a/src/mesa/drivers/dri/i965/gen6_cc.c b/src/mesa/drivers/dri/i965/gen6_cc.c
index dbcdc5b..f51afa4 100644
--- a/src/mesa/drivers/dri/i965/gen6_cc.c
+++ b/src/mesa/drivers/dri/i965/gen6_cc.c
@@ -66,12 +66,12 @@
    /* _NEW_COLOR */
    key->color_blend = ctx->Color.BlendEnabled;
    if (key->color_blend) {
-      key->blend_eq_rgb = ctx->Color.BlendEquationRGB;
-      key->blend_eq_a = ctx->Color.BlendEquationA;
-      key->blend_src_rgb = ctx->Color.BlendSrcRGB;
-      key->blend_dst_rgb = ctx->Color.BlendDstRGB;
-      key->blend_src_a = ctx->Color.BlendSrcA;
-      key->blend_dst_a = ctx->Color.BlendDstA;
+      key->blend_eq_rgb = ctx->Color.Blend[0].EquationRGB;
+      key->blend_eq_a = ctx->Color.Blend[0].EquationA;
+      key->blend_src_rgb = ctx->Color.Blend[0].SrcRGB;
+      key->blend_dst_rgb = ctx->Color.Blend[0].DstRGB;
+      key->blend_src_a = ctx->Color.Blend[0].SrcA;
+      key->blend_dst_a = ctx->Color.Blend[0].DstA;
    }
 
    /* _NEW_COLOR */
diff --git a/src/mesa/drivers/dri/intel/intel_pixel.c b/src/mesa/drivers/dri/intel/intel_pixel.c
index d5c3577..f97256e 100644
--- a/src/mesa/drivers/dri/intel/intel_pixel.c
+++ b/src/mesa/drivers/dri/intel/intel_pixel.c
@@ -66,12 +66,12 @@
    }
 
    if (ctx->Color.BlendEnabled &&
-       (effective_func(ctx->Color.BlendSrcRGB, src_alpha_is_one) != GL_ONE ||
-	effective_func(ctx->Color.BlendDstRGB, src_alpha_is_one) != GL_ZERO ||
-	ctx->Color.BlendEquationRGB != GL_FUNC_ADD ||
-	effective_func(ctx->Color.BlendSrcA, src_alpha_is_one) != GL_ONE ||
-	effective_func(ctx->Color.BlendDstA, src_alpha_is_one) != GL_ZERO ||
-	ctx->Color.BlendEquationA != GL_FUNC_ADD)) {
+       (effective_func(ctx->Color.Blend[0].SrcRGB, src_alpha_is_one) != GL_ONE ||
+	effective_func(ctx->Color.Blend[0].DstRGB, src_alpha_is_one) != GL_ZERO ||
+	ctx->Color.Blend[0].EquationRGB != GL_FUNC_ADD ||
+	effective_func(ctx->Color.Blend[0].SrcA, src_alpha_is_one) != GL_ONE ||
+	effective_func(ctx->Color.Blend[0].DstA, src_alpha_is_one) != GL_ZERO ||
+	ctx->Color.Blend[0].EquationA != GL_FUNC_ADD)) {
       DBG("fallback due to blend\n");
       return GL_FALSE;
    }
diff --git a/src/mesa/drivers/dri/mach64/mach64_state.c b/src/mesa/drivers/dri/mach64/mach64_state.c
index 8e79595..c1a4e63 100644
--- a/src/mesa/drivers/dri/mach64/mach64_state.c
+++ b/src/mesa/drivers/dri/mach64/mach64_state.c
@@ -102,7 +102,7 @@
 	     MACH64_ALPHA_BLEND_DST_MASK |
 	     MACH64_ALPHA_BLEND_SAT);
 
-      switch ( ctx->Color.BlendSrcRGB ) {
+      switch ( ctx->Color.Blend[0].SrcRGB ) {
       case GL_ZERO:
 	 s |= MACH64_ALPHA_BLEND_SRC_ZERO;
 	 break;
@@ -135,7 +135,7 @@
          FALLBACK( mmesa, MACH64_FALLBACK_BLEND_FUNC, GL_TRUE );
       }
 
-      switch ( ctx->Color.BlendDstRGB ) {
+      switch ( ctx->Color.Blend[0].DstRGB ) {
       case GL_ZERO:
 	 s |= MACH64_ALPHA_BLEND_DST_ZERO;
 	 break;
diff --git a/src/mesa/drivers/dri/mga/mgastate.c b/src/mesa/drivers/dri/mga/mgastate.c
index 25d7de2..2fac2b4 100644
--- a/src/mesa/drivers/dri/mga/mgastate.c
+++ b/src/mesa/drivers/dri/mga/mgastate.c
@@ -141,7 +141,7 @@
    GLuint   src;
    GLuint   dst;
 
-   switch (ctx->Color.BlendSrcRGB) {
+   switch (ctx->Color.Blend[0].SrcRGB) {
    case GL_ZERO:
       src = AC_src_zero; break;
    case GL_SRC_ALPHA:
@@ -169,7 +169,7 @@
       break;
    }
 
-   switch (ctx->Color.BlendDstRGB) {
+   switch (ctx->Color.Blend[0].DstRGB) {
    case GL_SRC_ALPHA:
       dst = AC_dst_src_alpha; break;
    case GL_ONE_MINUS_SRC_ALPHA:
diff --git a/src/mesa/drivers/dri/nouveau/nv04_state_raster.c b/src/mesa/drivers/dri/nouveau/nv04_state_raster.c
index 98f2f98..ecfbdfe 100644
--- a/src/mesa/drivers/dri/nouveau/nv04_state_raster.c
+++ b/src/mesa/drivers/dri/nouveau/nv04_state_raster.c
@@ -264,8 +264,8 @@
 			NV04_MULTITEX_TRIANGLE_BLEND_TEXTURE_PERSPECTIVE_ENABLE;
 
 		/* Alpha blending. */
-		blend |= get_blend_func(ctx->Color.BlendDstRGB) << 28 |
-			get_blend_func(ctx->Color.BlendSrcRGB) << 24;
+		blend |= get_blend_func(ctx->Color.Blend[0].DstRGB) << 28 |
+			get_blend_func(ctx->Color.Blend[0].SrcRGB) << 24;
 
 		if (ctx->Color.BlendEnabled)
 			blend |= NV04_MULTITEX_TRIANGLE_BLEND_BLEND_ENABLE;
@@ -296,8 +296,8 @@
 			NV04_TEXTURED_TRIANGLE_BLEND_TEXTURE_PERSPECTIVE_ENABLE;
 
 		/* Alpha blending. */
-		blend |= get_blend_func(ctx->Color.BlendDstRGB) << 28 |
-			get_blend_func(ctx->Color.BlendSrcRGB) << 24;
+		blend |= get_blend_func(ctx->Color.Blend[0].DstRGB) << 28 |
+			get_blend_func(ctx->Color.Blend[0].SrcRGB) << 24;
 
 		if (ctx->Color.BlendEnabled)
 			blend |= NV04_TEXTURED_TRIANGLE_BLEND_BLEND_ENABLE;
diff --git a/src/mesa/drivers/dri/nouveau/nv10_state_raster.c b/src/mesa/drivers/dri/nouveau/nv10_state_raster.c
index bb1084e..50021b0 100644
--- a/src/mesa/drivers/dri/nouveau/nv10_state_raster.c
+++ b/src/mesa/drivers/dri/nouveau/nv10_state_raster.c
@@ -68,7 +68,7 @@
 	OUT_RINGb(chan, ctx->Color.BlendEnabled);
 
 	BEGIN_RING(chan, celsius, NV10_3D_BLEND_EQUATION, 1);
-	OUT_RING(chan, nvgl_blend_eqn(ctx->Color.BlendEquationRGB));
+	OUT_RING(chan, nvgl_blend_eqn(ctx->Color.Blend[0].EquationRGB));
 }
 
 void
@@ -78,8 +78,8 @@
 	struct nouveau_grobj *celsius = context_eng3d(ctx);
 
 	BEGIN_RING(chan, celsius, NV10_3D_BLEND_FUNC_SRC, 2);
-	OUT_RING(chan, nvgl_blend_func(ctx->Color.BlendSrcRGB));
-	OUT_RING(chan, nvgl_blend_func(ctx->Color.BlendDstRGB));
+	OUT_RING(chan, nvgl_blend_func(ctx->Color.Blend[0].SrcRGB));
+	OUT_RING(chan, nvgl_blend_func(ctx->Color.Blend[0].DstRGB));
 }
 
 void
diff --git a/src/mesa/drivers/dri/r128/r128_state.c b/src/mesa/drivers/dri/r128/r128_state.c
index 4a49e8f..d6725cd 100644
--- a/src/mesa/drivers/dri/r128/r128_state.c
+++ b/src/mesa/drivers/dri/r128/r128_state.c
@@ -178,12 +178,12 @@
 	     (R128_ALPHA_BLEND_MASK << R128_ALPHA_BLEND_DST_SHIFT)
 	     | R128_ALPHA_COMB_FCN_MASK);
 
-      a |= blend_factor( rmesa, ctx->Color.BlendSrcRGB, GL_TRUE ) 
+      a |= blend_factor( rmesa, ctx->Color.Blend[0].SrcRGB, GL_TRUE ) 
 	  << R128_ALPHA_BLEND_SRC_SHIFT;
-      a |= blend_factor( rmesa, ctx->Color.BlendDstRGB, GL_FALSE ) 
+      a |= blend_factor( rmesa, ctx->Color.Blend[0].DstRGB, GL_FALSE ) 
 	  << R128_ALPHA_BLEND_DST_SHIFT;
 
-      switch (ctx->Color.BlendEquationRGB) {
+      switch (ctx->Color.Blend[0].EquationRGB) {
       case GL_FUNC_ADD:
 	 a |= R128_ALPHA_COMB_ADD_CLAMP;
 	 break;
diff --git a/src/mesa/drivers/dri/r200/r200_state.c b/src/mesa/drivers/dri/r200/r200_state.c
index b523edcb..0a1e0b4 100644
--- a/src/mesa/drivers/dri/r200/r200_state.c
+++ b/src/mesa/drivers/dri/r200/r200_state.c
@@ -245,10 +245,10 @@
       }
    }
 
-   func = (blend_factor( ctx->Color.BlendSrcRGB, GL_TRUE ) << R200_SRC_BLEND_SHIFT) |
-      (blend_factor( ctx->Color.BlendDstRGB, GL_FALSE ) << R200_DST_BLEND_SHIFT);
+   func = (blend_factor( ctx->Color.Blend[0].SrcRGB, GL_TRUE ) << R200_SRC_BLEND_SHIFT) |
+      (blend_factor( ctx->Color.Blend[0].DstRGB, GL_FALSE ) << R200_DST_BLEND_SHIFT);
 
-   switch(ctx->Color.BlendEquationRGB) {
+   switch(ctx->Color.Blend[0].EquationRGB) {
    case GL_FUNC_ADD:
       eqn = R200_COMB_FCN_ADD_CLAMP;
       break;
@@ -275,7 +275,7 @@
 
    default:
       fprintf( stderr, "[%s:%u] Invalid RGB blend equation (0x%04x).\n",
-         __FUNCTION__, __LINE__, ctx->Color.BlendEquationRGB );
+         __FUNCTION__, __LINE__, ctx->Color.Blend[0].EquationRGB );
       return;
    }
 
@@ -284,10 +284,10 @@
       return;
    }
 
-   funcA = (blend_factor( ctx->Color.BlendSrcA, GL_TRUE ) << R200_SRC_BLEND_SHIFT) |
-      (blend_factor( ctx->Color.BlendDstA, GL_FALSE ) << R200_DST_BLEND_SHIFT);
+   funcA = (blend_factor( ctx->Color.Blend[0].SrcA, GL_TRUE ) << R200_SRC_BLEND_SHIFT) |
+      (blend_factor( ctx->Color.Blend[0].DstA, GL_FALSE ) << R200_DST_BLEND_SHIFT);
 
-   switch(ctx->Color.BlendEquationA) {
+   switch(ctx->Color.Blend[0].EquationA) {
    case GL_FUNC_ADD:
       eqnA = R200_COMB_FCN_ADD_CLAMP;
       break;
@@ -314,7 +314,7 @@
 
    default:
       fprintf( stderr, "[%s:%u] Invalid A blend equation (0x%04x).\n",
-         __FUNCTION__, __LINE__, ctx->Color.BlendEquationA );
+         __FUNCTION__, __LINE__, ctx->Color.Blend[0].EquationA );
       return;
    }
 
diff --git a/src/mesa/drivers/dri/r300/r300_state.c b/src/mesa/drivers/dri/r300/r300_state.c
index ab8c1df..9df9101 100644
--- a/src/mesa/drivers/dri/r300/r300_state.c
+++ b/src/mesa/drivers/dri/r300/r300_state.c
@@ -220,12 +220,12 @@
 	}
 
 	func =
-	    (blend_factor(ctx->Color.BlendSrcRGB, GL_TRUE) <<
-	     R300_SRC_BLEND_SHIFT) | (blend_factor(ctx->Color.BlendDstRGB,
+	    (blend_factor(ctx->Color.Blend[0].SrcRGB, GL_TRUE) <<
+	     R300_SRC_BLEND_SHIFT) | (blend_factor(ctx->Color.Blend[0].DstRGB,
 						   GL_FALSE) <<
 				      R300_DST_BLEND_SHIFT);
 
-	switch (ctx->Color.BlendEquationRGB) {
+	switch (ctx->Color.Blend[0].EquationRGB) {
 	case GL_FUNC_ADD:
 		eqn = R300_COMB_FCN_ADD_CLAMP;
 		break;
@@ -253,17 +253,17 @@
 	default:
 		fprintf(stderr,
 			"[%s:%u] Invalid RGB blend equation (0x%04x).\n",
-			__FUNCTION__, __LINE__, ctx->Color.BlendEquationRGB);
+			__FUNCTION__, __LINE__, ctx->Color.Blend[0].EquationRGB);
 		return;
 	}
 
 	funcA =
-	    (blend_factor(ctx->Color.BlendSrcA, GL_TRUE) <<
-	     R300_SRC_BLEND_SHIFT) | (blend_factor(ctx->Color.BlendDstA,
+	    (blend_factor(ctx->Color.Blend[0].SrcA, GL_TRUE) <<
+	     R300_SRC_BLEND_SHIFT) | (blend_factor(ctx->Color.Blend[0].DstA,
 						   GL_FALSE) <<
 				      R300_DST_BLEND_SHIFT);
 
-	switch (ctx->Color.BlendEquationA) {
+	switch (ctx->Color.Blend[0].EquationA) {
 	case GL_FUNC_ADD:
 		eqnA = R300_COMB_FCN_ADD_CLAMP;
 		break;
@@ -291,7 +291,7 @@
 	default:
 		fprintf(stderr,
 			"[%s:%u] Invalid A blend equation (0x%04x).\n",
-			__FUNCTION__, __LINE__, ctx->Color.BlendEquationA);
+			__FUNCTION__, __LINE__, ctx->Color.Blend[0].EquationA);
 		return;
 	}
 
diff --git a/src/mesa/drivers/dri/r600/evergreen_state.c b/src/mesa/drivers/dri/r600/evergreen_state.c
index 648cda0..006e500 100644
--- a/src/mesa/drivers/dri/r600/evergreen_state.c
+++ b/src/mesa/drivers/dri/r600/evergreen_state.c
@@ -363,13 +363,13 @@
 	}
 
 	SETfield(blend_reg,
-		 evergreenblend_factor(ctx->Color.BlendSrcRGB, GL_TRUE),
+		 evergreenblend_factor(ctx->Color.Blend[0].SrcRGB, GL_TRUE),
 		 COLOR_SRCBLEND_shift, COLOR_SRCBLEND_mask);
 	SETfield(blend_reg,
-		 evergreenblend_factor(ctx->Color.BlendDstRGB, GL_FALSE),
+		 evergreenblend_factor(ctx->Color.Blend[0].DstRGB, GL_FALSE),
 		 COLOR_DESTBLEND_shift, COLOR_DESTBLEND_mask);
 
-	switch (ctx->Color.BlendEquationRGB) {
+	switch (ctx->Color.Blend[0].EquationRGB) {
 	case GL_FUNC_ADD:
 		eqn = COMB_DST_PLUS_SRC;
 		break;
@@ -401,20 +401,20 @@
 	default:
 		fprintf(stderr,
 			"[%s:%u] Invalid RGB blend equation (0x%04x).\n",
-			__FUNCTION__, __LINE__, ctx->Color.BlendEquationRGB);
+			__FUNCTION__, __LINE__, ctx->Color.Blend[0].EquationRGB);
 		return;
 	}
 	SETfield(blend_reg,
 		 eqn, COLOR_COMB_FCN_shift, COLOR_COMB_FCN_mask);
 
 	SETfield(blend_reg,
-		 evergreenblend_factor(ctx->Color.BlendSrcA, GL_TRUE),
+		 evergreenblend_factor(ctx->Color.Blend[0].SrcA, GL_TRUE),
 		 ALPHA_SRCBLEND_shift, ALPHA_SRCBLEND_mask);
 	SETfield(blend_reg,
-		 evergreenblend_factor(ctx->Color.BlendDstA, GL_FALSE),
+		 evergreenblend_factor(ctx->Color.Blend[0].DstA, GL_FALSE),
 		 ALPHA_DESTBLEND_shift, ALPHA_DESTBLEND_mask);
 
-	switch (ctx->Color.BlendEquationA) {
+	switch (ctx->Color.Blend[0].EquationA) {
 	case GL_FUNC_ADD:
 		eqnA = COMB_DST_PLUS_SRC;
 		break;
@@ -445,7 +445,7 @@
 	default:
 		fprintf(stderr,
 			"[%s:%u] Invalid A blend equation (0x%04x).\n",
-			__FUNCTION__, __LINE__, ctx->Color.BlendEquationA);
+			__FUNCTION__, __LINE__, ctx->Color.Blend[0].EquationA);
 		return;
 	}
 
diff --git a/src/mesa/drivers/dri/r600/r700_state.c b/src/mesa/drivers/dri/r600/r700_state.c
index bd04a63..f877069 100644
--- a/src/mesa/drivers/dri/r600/r700_state.c
+++ b/src/mesa/drivers/dri/r600/r700_state.c
@@ -474,13 +474,13 @@
 	}
 
 	SETfield(blend_reg,
-		 blend_factor(ctx->Color.BlendSrcRGB, GL_TRUE),
+		 blend_factor(ctx->Color.Blend[0].SrcRGB, GL_TRUE),
 		 COLOR_SRCBLEND_shift, COLOR_SRCBLEND_mask);
 	SETfield(blend_reg,
-		 blend_factor(ctx->Color.BlendDstRGB, GL_FALSE),
+		 blend_factor(ctx->Color.Blend[0].DstRGB, GL_FALSE),
 		 COLOR_DESTBLEND_shift, COLOR_DESTBLEND_mask);
 
-	switch (ctx->Color.BlendEquationRGB) {
+	switch (ctx->Color.Blend[0].EquationRGB) {
 	case GL_FUNC_ADD:
 		eqn = COMB_DST_PLUS_SRC;
 		break;
@@ -512,20 +512,20 @@
 	default:
 		fprintf(stderr,
 			"[%s:%u] Invalid RGB blend equation (0x%04x).\n",
-			__FUNCTION__, __LINE__, ctx->Color.BlendEquationRGB);
+			__FUNCTION__, __LINE__, ctx->Color.Blend[0].EquationRGB);
 		return;
 	}
 	SETfield(blend_reg,
 		 eqn, COLOR_COMB_FCN_shift, COLOR_COMB_FCN_mask);
 
 	SETfield(blend_reg,
-		 blend_factor(ctx->Color.BlendSrcA, GL_TRUE),
+		 blend_factor(ctx->Color.Blend[0].SrcA, GL_TRUE),
 		 ALPHA_SRCBLEND_shift, ALPHA_SRCBLEND_mask);
 	SETfield(blend_reg,
-		 blend_factor(ctx->Color.BlendDstA, GL_FALSE),
+		 blend_factor(ctx->Color.Blend[0].DstA, GL_FALSE),
 		 ALPHA_DESTBLEND_shift, ALPHA_DESTBLEND_mask);
 
-	switch (ctx->Color.BlendEquationA) {
+	switch (ctx->Color.Blend[0].EquationA) {
 	case GL_FUNC_ADD:
 		eqnA = COMB_DST_PLUS_SRC;
 		break;
@@ -556,7 +556,7 @@
 	default:
 		fprintf(stderr,
 			"[%s:%u] Invalid A blend equation (0x%04x).\n",
-			__FUNCTION__, __LINE__, ctx->Color.BlendEquationA);
+			__FUNCTION__, __LINE__, ctx->Color.Blend[0].EquationA);
 		return;
 	}
 
diff --git a/src/mesa/drivers/dri/radeon/radeon_state.c b/src/mesa/drivers/dri/radeon/radeon_state.c
index cae12f1..ca42aa3 100644
--- a/src/mesa/drivers/dri/radeon/radeon_state.c
+++ b/src/mesa/drivers/dri/radeon/radeon_state.c
@@ -136,7 +136,7 @@
       RADEON_STATECHANGE( rmesa, ctx );
       rmesa->hw.ctx.cmd[CTX_RB3D_BLENDCNTL] = b;
       if ( (ctx->Color.ColorLogicOpEnabled || (ctx->Color.BlendEnabled
-	    && ctx->Color.BlendEquationRGB == GL_LOGIC_OP)) ) {
+	    && ctx->Color.Blend[0].EquationRGB == GL_LOGIC_OP)) ) {
 	 rmesa->hw.ctx.cmd[CTX_RB3D_CNTL] |=  RADEON_ROP_ENABLE;
       } else {
 	 rmesa->hw.ctx.cmd[CTX_RB3D_CNTL] &= ~RADEON_ROP_ENABLE;
@@ -153,7 +153,7 @@
       ~(RADEON_SRC_BLEND_MASK | RADEON_DST_BLEND_MASK);
    GLboolean fallback = GL_FALSE;
 
-   switch ( ctx->Color.BlendSrcRGB ) {
+   switch ( ctx->Color.Blend[0].SrcRGB ) {
    case GL_ZERO:
       b |= RADEON_SRC_BLEND_GL_ZERO;
       break;
@@ -200,7 +200,7 @@
       break;
    }
 
-   switch ( ctx->Color.BlendDstRGB ) {
+   switch ( ctx->Color.Blend[0].DstRGB ) {
    case GL_ZERO:
       b |= RADEON_DST_BLEND_GL_ZERO;
       break;
@@ -1602,7 +1602,7 @@
 	 rmesa->hw.ctx.cmd[CTX_RB3D_CNTL] &= ~RADEON_ALPHA_BLEND_ENABLE;
       }
       if ( (ctx->Color.ColorLogicOpEnabled || (ctx->Color.BlendEnabled
-	    && ctx->Color.BlendEquationRGB == GL_LOGIC_OP)) ) {
+	    && ctx->Color.Blend[0].EquationRGB == GL_LOGIC_OP)) ) {
 	 rmesa->hw.ctx.cmd[CTX_RB3D_CNTL] |=  RADEON_ROP_ENABLE;
       } else {
 	 rmesa->hw.ctx.cmd[CTX_RB3D_CNTL] &= ~RADEON_ROP_ENABLE;
@@ -1612,12 +1612,12 @@
        */
       if (state) {
 	 ctx->Driver.BlendEquationSeparate( ctx,
-					    ctx->Color.BlendEquationRGB,
-					    ctx->Color.BlendEquationA );
-	 ctx->Driver.BlendFuncSeparate( ctx, ctx->Color.BlendSrcRGB,
-					ctx->Color.BlendDstRGB,
-					ctx->Color.BlendSrcA,
-					ctx->Color.BlendDstA );
+					    ctx->Color.Blend[0].EquationRGB,
+					    ctx->Color.Blend[0].EquationA );
+	 ctx->Driver.BlendFuncSeparate( ctx, ctx->Color.Blend[0].SrcRGB,
+					ctx->Color.Blend[0].DstRGB,
+					ctx->Color.Blend[0].SrcA,
+					ctx->Color.Blend[0].DstA );
       }
       else {
 	 FALLBACK( rmesa, RADEON_FALLBACK_BLEND_FUNC, GL_FALSE );
@@ -1741,7 +1741,7 @@
    case GL_COLOR_LOGIC_OP:
       RADEON_STATECHANGE( rmesa, ctx );
       if ( (ctx->Color.ColorLogicOpEnabled || (ctx->Color.BlendEnabled
-	    && ctx->Color.BlendEquationRGB == GL_LOGIC_OP)) ) {
+	    && ctx->Color.Blend[0].EquationRGB == GL_LOGIC_OP)) ) {
 	 rmesa->hw.ctx.cmd[CTX_RB3D_CNTL] |=  RADEON_ROP_ENABLE;
       } else {
 	 rmesa->hw.ctx.cmd[CTX_RB3D_CNTL] &= ~RADEON_ROP_ENABLE;
diff --git a/src/mesa/drivers/dri/savage/savagestate.c b/src/mesa/drivers/dri/savage/savagestate.c
index 0906f85..1feffa0 100644
--- a/src/mesa/drivers/dri/savage/savagestate.c
+++ b/src/mesa/drivers/dri/savage/savagestate.c
@@ -136,7 +136,7 @@
      * blend modes
      */
     if(ctx->Color.BlendEnabled){
-        switch (ctx->Color.BlendDstRGB)
+        switch (ctx->Color.Blend[0].DstRGB)
         {
             case GL_ZERO:
                 imesa->regs.s4.drawLocalCtrl.ni.dstAlphaMode = DAM_Zero;
@@ -192,7 +192,7 @@
                 break;
         }
 
-        switch (ctx->Color.BlendSrcRGB)
+        switch (ctx->Color.Blend[0].SrcRGB)
         {
             case GL_ZERO:
                 imesa->regs.s4.drawLocalCtrl.ni.srcAlphaMode = SAM_Zero;
@@ -310,7 +310,7 @@
      * blend modes
      */
     if(ctx->Color.BlendEnabled){
-        switch (ctx->Color.BlendDstRGB)
+        switch (ctx->Color.Blend[0].DstRGB)
         {
             case GL_ZERO:
                 imesa->regs.s3d.drawCtrl.ni.dstAlphaMode = DAM_Zero;
@@ -366,7 +366,7 @@
                 break;
         }
 
-        switch (ctx->Color.BlendSrcRGB)
+        switch (ctx->Color.Blend[0].SrcRGB)
         {
             case GL_ZERO:
                 imesa->regs.s3d.drawCtrl.ni.srcAlphaMode = SAM_Zero;
diff --git a/src/mesa/drivers/dri/tdfx/tdfx_state.c b/src/mesa/drivers/dri/tdfx/tdfx_state.c
index 3f6822d..b26b2c7 100644
--- a/src/mesa/drivers/dri/tdfx/tdfx_state.c
+++ b/src/mesa/drivers/dri/tdfx/tdfx_state.c
@@ -84,7 +84,7 @@
 
    if ( ctx->Color.BlendEnabled
         && (fxMesa->Fallback & TDFX_FALLBACK_BLEND) == 0 ) {
-      switch ( ctx->Color.BlendSrcRGB ) {
+      switch ( ctx->Color.Blend[0].SrcRGB ) {
       case GL_ZERO:
 	 srcRGB = GR_BLEND_ZERO;
 	 break;
@@ -126,7 +126,7 @@
 	 srcRGB = GR_BLEND_ONE;
       }
 
-      switch ( ctx->Color.BlendSrcA ) {
+      switch ( ctx->Color.Blend[0].SrcA ) {
       case GL_ZERO:
 	 srcA = GR_BLEND_ZERO;
 	 break;
@@ -156,7 +156,7 @@
 	 srcA = GR_BLEND_ONE;
       }
 
-      switch ( ctx->Color.BlendDstRGB ) {
+      switch ( ctx->Color.Blend[0].DstRGB ) {
       case GL_ZERO:
 	 dstRGB = GR_BLEND_ZERO;
 	 break;
@@ -195,7 +195,7 @@
 	 dstRGB = GR_BLEND_ZERO;
       }
 
-      switch ( ctx->Color.BlendDstA ) {
+      switch ( ctx->Color.Blend[0].DstA ) {
       case GL_ZERO:
 	 dstA = GR_BLEND_ZERO;
 	 break;
@@ -222,7 +222,7 @@
 	 dstA = GR_BLEND_ZERO;
       }
 
-      switch ( ctx->Color.BlendEquationRGB ) {
+      switch ( ctx->Color.Blend[0].EquationRGB ) {
       case GL_FUNC_SUBTRACT:
 	 eqRGB = GR_BLEND_OP_SUB;
 	 break;
@@ -235,7 +235,7 @@
 	 break;
       }
 
-      switch ( ctx->Color.BlendEquationA ) {
+      switch ( ctx->Color.Blend[0].EquationA ) {
       case GL_FUNC_SUBTRACT:
 	 eqA = GR_BLEND_OP_SUB;
 	 break;
diff --git a/src/mesa/drivers/dri/unichrome/via_state.c b/src/mesa/drivers/dri/unichrome/via_state.c
index 0333521..774f439 100644
--- a/src/mesa/drivers/dri/unichrome/via_state.c
+++ b/src/mesa/drivers/dri/unichrome/via_state.c
@@ -552,7 +552,7 @@
     if (VIA_DEBUG & DEBUG_STATE) 
        fprintf(stderr, "%s in\n", __FUNCTION__);
 
-    switch (ctx->Color.BlendSrcRGB) {
+    switch (ctx->Color.Blend[0].SrcRGB) {
     case GL_SRC_ALPHA_SATURATE:  
     case GL_CONSTANT_COLOR:
     case GL_ONE_MINUS_CONSTANT_COLOR:
@@ -564,7 +564,7 @@
         break;
     }
 
-    switch (ctx->Color.BlendDstRGB) {
+    switch (ctx->Color.Blend[0].DstRGB) {
     case GL_CONSTANT_COLOR:
     case GL_ONE_MINUS_CONSTANT_COLOR:
     case GL_CONSTANT_ALPHA:
@@ -757,14 +757,14 @@
     */
 
    ctx->Driver.BlendEquationSeparate( ctx, 
-				      ctx->Color.BlendEquationRGB,
-				      ctx->Color.BlendEquationA);
+				      ctx->Color.Blend[0].EquationRGB,
+				      ctx->Color.Blend[0].EquationA);
 
    ctx->Driver.BlendFuncSeparate( ctx,
-				  ctx->Color.BlendSrcRGB,
-				  ctx->Color.BlendDstRGB,
-				  ctx->Color.BlendSrcA,
-				  ctx->Color.BlendDstA);
+				  ctx->Color.Blend[0].SrcRGB,
+				  ctx->Color.Blend[0].DstRGB,
+				  ctx->Color.Blend[0].SrcA,
+				  ctx->Color.Blend[0].DstA);
 
    ctx->Driver.Scissor( ctx, ctx->Scissor.X, ctx->Scissor.Y,
 			ctx->Scissor.Width, ctx->Scissor.Height );
@@ -953,8 +953,8 @@
 static void viaChooseColorState(struct gl_context *ctx) 
 {
     struct via_context *vmesa = VIA_CONTEXT(ctx);
-    GLenum s = ctx->Color.BlendSrcRGB;
-    GLenum d = ctx->Color.BlendDstRGB;
+    GLenum s = ctx->Color.Blend[0].SrcRGB;
+    GLenum d = ctx->Color.Blend[0].DstRGB;
 
     /* The HW's blending equation is:
      * (Ca * FCa + Cbias + Cb * FCb) << Cshift
diff --git a/src/mesa/main/attrib.c b/src/mesa/main/attrib.c
index adfec3b..7fd1287 100644
--- a/src/mesa/main/attrib.c
+++ b/src/mesa/main/attrib.c
@@ -954,20 +954,39 @@
                      _mesa_set_enable(ctx, GL_BLEND, (color->BlendEnabled & 1));
                   }
                }
-               _mesa_BlendFuncSeparateEXT(color->BlendSrcRGB,
-                                          color->BlendDstRGB,
-                                          color->BlendSrcA,
-                                          color->BlendDstA);
-	       /* This special case is because glBlendEquationSeparateEXT
-		* cannot take GL_LOGIC_OP as a parameter.
-		*/
-	       if ( color->BlendEquationRGB == color->BlendEquationA ) {
-		  _mesa_BlendEquation(color->BlendEquationRGB);
-	       }
-	       else {
-		  _mesa_BlendEquationSeparateEXT(color->BlendEquationRGB,
-						 color->BlendEquationA);
-	       }
+               if (ctx->Color._BlendFuncPerBuffer ||
+                   ctx->Color._BlendEquationPerBuffer) {
+                  /* set blend per buffer */
+                  GLuint buf;
+                  for (buf = 0; buf < ctx->Const.MaxDrawBuffers; buf++) {
+                     _mesa_BlendFuncSeparatei(buf, color->Blend[buf].SrcRGB,
+                                              color->Blend[buf].DstRGB,
+                                              color->Blend[buf].SrcA,
+                                              color->Blend[buf].DstA);
+                     _mesa_BlendEquationSeparatei(buf,
+                                                  color->Blend[buf].EquationRGB,
+                                                  color->Blend[buf].EquationA);
+                  }
+               }
+               else {
+                  /* set same blend modes for all buffers */
+                  _mesa_BlendFuncSeparateEXT(color->Blend[0].SrcRGB,
+                                             color->Blend[0].DstRGB,
+                                             color->Blend[0].SrcA,
+                                             color->Blend[0].DstA);
+                  /* This special case is because glBlendEquationSeparateEXT
+                   * cannot take GL_LOGIC_OP as a parameter.
+                   */
+                  if (color->Blend[0].EquationRGB ==
+                      color->Blend[0].EquationA) {
+                     _mesa_BlendEquation(color->Blend[0].EquationRGB);
+                  }
+                  else {
+                     _mesa_BlendEquationSeparateEXT(
+                                                 color->Blend[0].EquationRGB,
+                                                 color->Blend[0].EquationA);
+                  }
+               }
                _mesa_BlendColor(color->BlendColor[0],
                                 color->BlendColor[1],
                                 color->BlendColor[2],
diff --git a/src/mesa/main/blend.c b/src/mesa/main/blend.c
index ec778b7..43e2f7f 100644
--- a/src/mesa/main/blend.c
+++ b/src/mesa/main/blend.c
@@ -37,6 +37,110 @@
 #include "mtypes.h"
 
 
+
+/**
+ * Check if given blend source factor is legal.
+ * \return GL_TRUE if legal, GL_FALSE otherwise.
+ */
+static GLboolean
+legal_src_factor(const struct gl_context *ctx, GLenum factor)
+{
+   switch (factor) {
+   case GL_SRC_COLOR:
+   case GL_ONE_MINUS_SRC_COLOR:
+      return ctx->Extensions.NV_blend_square;
+   case GL_ZERO:
+   case GL_ONE:
+   case GL_DST_COLOR:
+   case GL_ONE_MINUS_DST_COLOR:
+   case GL_SRC_ALPHA:
+   case GL_ONE_MINUS_SRC_ALPHA:
+   case GL_DST_ALPHA:
+   case GL_ONE_MINUS_DST_ALPHA:
+   case GL_SRC_ALPHA_SATURATE:
+   case GL_CONSTANT_COLOR:
+   case GL_ONE_MINUS_CONSTANT_COLOR:
+   case GL_CONSTANT_ALPHA:
+   case GL_ONE_MINUS_CONSTANT_ALPHA:
+      return GL_TRUE;
+   default:
+      return GL_FALSE;
+   }
+}
+
+
+/**
+ * Check if given blend destination factor is legal.
+ * \return GL_TRUE if legal, GL_FALSE otherwise.
+ */
+static GLboolean
+legal_dst_factor(const struct gl_context *ctx, GLenum factor)
+{
+   switch (factor) {
+   case GL_DST_COLOR:
+   case GL_ONE_MINUS_DST_COLOR:
+      return ctx->Extensions.NV_blend_square;
+   case GL_ZERO:
+   case GL_ONE:
+   case GL_SRC_COLOR:
+   case GL_ONE_MINUS_SRC_COLOR:
+   case GL_SRC_ALPHA:
+   case GL_ONE_MINUS_SRC_ALPHA:
+   case GL_DST_ALPHA:
+   case GL_ONE_MINUS_DST_ALPHA:
+   case GL_CONSTANT_COLOR:
+   case GL_ONE_MINUS_CONSTANT_COLOR:
+   case GL_CONSTANT_ALPHA:
+   case GL_ONE_MINUS_CONSTANT_ALPHA:
+      return GL_TRUE;
+   default:
+      return GL_FALSE;
+   }
+}
+
+
+/**
+ * Check if src/dest RGB/A blend factors are legal.  If not generate
+ * a GL error.
+ * \return GL_TRUE if factors are legal, GL_FALSE otherwise.
+ */
+static GLboolean
+validate_blend_factors(struct gl_context *ctx, const char *func,
+                       GLenum sfactorRGB, GLenum dfactorRGB,
+                       GLenum sfactorA, GLenum dfactorA)
+{
+   if (!legal_src_factor(ctx, sfactorRGB)) {
+      _mesa_error(ctx, GL_INVALID_ENUM,
+                  "%s(sfactorRGB = %s)", func,
+                  _mesa_lookup_enum_by_nr(sfactorRGB));
+      return GL_FALSE;
+   }
+
+   if (!legal_dst_factor(ctx, dfactorRGB)) {
+      _mesa_error(ctx, GL_INVALID_ENUM,
+                  "%s(dfactorRGB = %s)", func,
+                  _mesa_lookup_enum_by_nr(dfactorRGB));
+      return GL_FALSE;
+   }
+
+   if (sfactorA != sfactorRGB && !legal_src_factor(ctx, sfactorA)) {
+      _mesa_error(ctx, GL_INVALID_ENUM,
+                  "%s(sfactorA = %s)", func,
+                  _mesa_lookup_enum_by_nr(sfactorA));
+      return GL_FALSE;
+   }
+
+   if (dfactorA != dfactorRGB && !legal_dst_factor(ctx, dfactorA)) {
+      _mesa_error(ctx, GL_INVALID_ENUM,
+                  "%s(dfactorA = %s)", func,
+                  _mesa_lookup_enum_by_nr(dfactorA));
+      return GL_FALSE;
+   }
+
+   return GL_TRUE;
+}
+
+
 /**
  * Specify the blending operation.
  *
@@ -53,21 +157,19 @@
 
 
 /**
- * Process GL_EXT_blend_func_separate().
+ * Set the separate blend source/dest factors for all draw buffers.
  *
  * \param sfactorRGB RGB source factor operator.
  * \param dfactorRGB RGB destination factor operator.
  * \param sfactorA alpha source factor operator.
  * \param dfactorA alpha destination factor operator.
- *
- * Verifies the parameters and updates gl_colorbuffer_attrib.
- * On a change, flush the vertices and notify the driver via
- * dd_function_table::BlendFuncSeparate.
  */
 void GLAPIENTRY
 _mesa_BlendFuncSeparateEXT( GLenum sfactorRGB, GLenum dfactorRGB,
                             GLenum sfactorA, GLenum dfactorA )
 {
+   GLuint buf, numBuffers;
+   GLboolean changed;
    GET_CURRENT_CONTEXT(ctx);
    ASSERT_OUTSIDE_BEGIN_END(ctx);
 
@@ -78,165 +180,130 @@
                   _mesa_lookup_enum_by_nr(sfactorA),
                   _mesa_lookup_enum_by_nr(dfactorA));
 
-   switch (sfactorRGB) {
-      case GL_SRC_COLOR:
-      case GL_ONE_MINUS_SRC_COLOR:
-         if (!ctx->Extensions.NV_blend_square) {
-            _mesa_error(ctx, GL_INVALID_ENUM, "glBlendFunc or glBlendFuncSeparate (sfactorRGB)");
-            return;
-         }
-         /* fall-through */
-      case GL_ZERO:
-      case GL_ONE:
-      case GL_DST_COLOR:
-      case GL_ONE_MINUS_DST_COLOR:
-      case GL_SRC_ALPHA:
-      case GL_ONE_MINUS_SRC_ALPHA:
-      case GL_DST_ALPHA:
-      case GL_ONE_MINUS_DST_ALPHA:
-      case GL_SRC_ALPHA_SATURATE:
-      case GL_CONSTANT_COLOR:
-      case GL_ONE_MINUS_CONSTANT_COLOR:
-      case GL_CONSTANT_ALPHA:
-      case GL_ONE_MINUS_CONSTANT_ALPHA:
-         break;
-      default:
-         _mesa_error(ctx, GL_INVALID_ENUM, "glBlendFunc or glBlendFuncSeparate (sfactorRGB)");
-         return;
+   if (!validate_blend_factors(ctx, "glBlendFuncSeparate",
+                               sfactorRGB, dfactorRGB,
+                               sfactorA, dfactorA)) {
+      return;
    }
 
-   switch (dfactorRGB) {
-      case GL_DST_COLOR:
-      case GL_ONE_MINUS_DST_COLOR:
-         if (!ctx->Extensions.NV_blend_square) {
-            _mesa_error(ctx, GL_INVALID_ENUM, "glBlendFunc or glBlendFuncSeparate (dfactorRGB)");
-            return;
-         }
-         /* fall-through */
-      case GL_ZERO:
-      case GL_ONE:
-      case GL_SRC_COLOR:
-      case GL_ONE_MINUS_SRC_COLOR:
-      case GL_SRC_ALPHA:
-      case GL_ONE_MINUS_SRC_ALPHA:
-      case GL_DST_ALPHA:
-      case GL_ONE_MINUS_DST_ALPHA:
-      case GL_CONSTANT_COLOR:
-      case GL_ONE_MINUS_CONSTANT_COLOR:
-      case GL_CONSTANT_ALPHA:
-      case GL_ONE_MINUS_CONSTANT_ALPHA:
-         break;
-      default:
-         _mesa_error(ctx, GL_INVALID_ENUM, "glBlendFunc or glBlendFuncSeparate (dfactorRGB)");
-         return;
-   }
+   numBuffers = ctx->Extensions.ARB_draw_buffers_blend
+      ? ctx->Const.MaxDrawBuffers : 1;
 
-   switch (sfactorA) {
-      case GL_SRC_COLOR:
-      case GL_ONE_MINUS_SRC_COLOR:
-         if (!ctx->Extensions.NV_blend_square) {
-            _mesa_error(ctx, GL_INVALID_ENUM, "glBlendFunc or glBlendFuncSeparate (sfactorA)");
-            return;
-         }
-         /* fall-through */
-      case GL_ZERO:
-      case GL_ONE:
-      case GL_DST_COLOR:
-      case GL_ONE_MINUS_DST_COLOR:
-      case GL_SRC_ALPHA:
-      case GL_ONE_MINUS_SRC_ALPHA:
-      case GL_DST_ALPHA:
-      case GL_ONE_MINUS_DST_ALPHA:
-      case GL_SRC_ALPHA_SATURATE:
-      case GL_CONSTANT_COLOR:
-      case GL_ONE_MINUS_CONSTANT_COLOR:
-      case GL_CONSTANT_ALPHA:
-      case GL_ONE_MINUS_CONSTANT_ALPHA:
+   changed = GL_FALSE;
+   for (buf = 0; buf < numBuffers; buf++) {
+      if (ctx->Color.Blend[buf].SrcRGB != sfactorRGB ||
+          ctx->Color.Blend[buf].DstRGB != dfactorRGB ||
+          ctx->Color.Blend[buf].SrcA != sfactorA ||
+          ctx->Color.Blend[buf].DstA != dfactorA) {
+         changed = GL_TRUE;
          break;
-      default:
-         _mesa_error(ctx, GL_INVALID_ENUM, "glBlendFunc or glBlendFuncSeparate (sfactorA)");
-         return;
+      }
    }
-
-   switch (dfactorA) {
-      case GL_DST_COLOR:
-      case GL_ONE_MINUS_DST_COLOR:
-         if (!ctx->Extensions.NV_blend_square) {
-            _mesa_error(ctx, GL_INVALID_ENUM, "glBlendFunc or glBlendFuncSeparate (dfactorA)");
-            return;
-         }
-         /* fall-through */
-      case GL_ZERO:
-      case GL_ONE:
-      case GL_SRC_COLOR:
-      case GL_ONE_MINUS_SRC_COLOR:
-      case GL_SRC_ALPHA:
-      case GL_ONE_MINUS_SRC_ALPHA:
-      case GL_DST_ALPHA:
-      case GL_ONE_MINUS_DST_ALPHA:
-      case GL_CONSTANT_COLOR:
-      case GL_ONE_MINUS_CONSTANT_COLOR:
-      case GL_CONSTANT_ALPHA:
-      case GL_ONE_MINUS_CONSTANT_ALPHA:
-         break;
-      default:
-         _mesa_error( ctx, GL_INVALID_ENUM, "glBlendFunc or glBlendFuncSeparate (dfactorA)" );
-         return;
-   }
-
-   if (ctx->Color.BlendSrcRGB == sfactorRGB &&
-       ctx->Color.BlendDstRGB == dfactorRGB &&
-       ctx->Color.BlendSrcA == sfactorA &&
-       ctx->Color.BlendDstA == dfactorA)
+   if (!changed)
       return;
 
    FLUSH_VERTICES(ctx, _NEW_COLOR);
 
-   ctx->Color.BlendSrcRGB = sfactorRGB;
-   ctx->Color.BlendDstRGB = dfactorRGB;
-   ctx->Color.BlendSrcA = sfactorA;
-   ctx->Color.BlendDstA = dfactorA;
+   for (buf = 0; buf < numBuffers; buf++) {
+      ctx->Color.Blend[buf].SrcRGB = sfactorRGB;
+      ctx->Color.Blend[buf].DstRGB = dfactorRGB;
+      ctx->Color.Blend[buf].SrcA = sfactorA;
+      ctx->Color.Blend[buf].DstA = dfactorA;
+   }
+   ctx->Color._BlendFuncPerBuffer = GL_FALSE;
 
    if (ctx->Driver.BlendFuncSeparate) {
-      (*ctx->Driver.BlendFuncSeparate)( ctx, sfactorRGB, dfactorRGB,
-					sfactorA, dfactorA );
+      ctx->Driver.BlendFuncSeparate(ctx, sfactorRGB, dfactorRGB,
+                                    sfactorA, dfactorA);
    }
 }
 
 
 #if _HAVE_FULL_GL
 
-static GLboolean
-_mesa_validate_blend_equation( struct gl_context *ctx,
-			       GLenum mode, GLboolean is_separate )
+
+/**
+ * Set blend source/dest factors for one color buffer/target.
+ */
+void GLAPIENTRY
+_mesa_BlendFunci(GLuint buf, GLenum sfactor, GLenum dfactor)
 {
-   switch (mode) {
-      case GL_FUNC_ADD:
-         break;
-      case GL_MIN:
-      case GL_MAX:
-         if (!ctx->Extensions.EXT_blend_minmax) {
-            return GL_FALSE;
-         }
-         break;
-      /* glBlendEquationSeparate cannot take GL_LOGIC_OP as a parameter.
-       */
-      case GL_LOGIC_OP:
-         if (!ctx->Extensions.EXT_blend_logic_op || is_separate) {
-            return GL_FALSE;
-         }
-         break;
-      case GL_FUNC_SUBTRACT:
-      case GL_FUNC_REVERSE_SUBTRACT:
-         if (!ctx->Extensions.EXT_blend_subtract) {
-            return GL_FALSE;
-         }
-         break;
-      default:
-         return GL_FALSE;
+   _mesa_BlendFuncSeparatei(buf, sfactor, dfactor, sfactor, dfactor);
+}
+
+
+/**
+ * Set separate blend source/dest factors for one color buffer/target.
+ */
+void GLAPIENTRY
+_mesa_BlendFuncSeparatei(GLuint buf, GLenum sfactorRGB, GLenum dfactorRGB,
+                         GLenum sfactorA, GLenum dfactorA)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+   if (!ctx->Extensions.ARB_draw_buffers_blend) {
+      _mesa_error(ctx, GL_INVALID_OPERATION, "glBlendFunc[Separate]i()");
+      return;
    }
 
-   return GL_TRUE;
+   if (buf >= ctx->Const.MaxDrawBuffers) {
+      _mesa_error(ctx, GL_INVALID_VALUE, "glBlendFuncSeparatei(buffer=%u)",
+                  buf);
+      return;
+   }
+
+   if (!validate_blend_factors(ctx, "glBlendFuncSeparatei",
+                               sfactorRGB, dfactorRGB,
+                               sfactorA, dfactorA)) {
+      return;
+   }
+
+   if (ctx->Color.Blend[buf].SrcRGB == sfactorRGB &&
+       ctx->Color.Blend[buf].DstRGB == dfactorRGB &&
+       ctx->Color.Blend[buf].SrcA == sfactorA &&
+       ctx->Color.Blend[buf].DstA == dfactorA)
+      return; /* no change */
+
+   FLUSH_VERTICES(ctx, _NEW_COLOR);
+
+   ctx->Color.Blend[buf].SrcRGB = sfactorRGB;
+   ctx->Color.Blend[buf].DstRGB = dfactorRGB;
+   ctx->Color.Blend[buf].SrcA = sfactorA;
+   ctx->Color.Blend[buf].DstA = dfactorA;
+   ctx->Color._BlendFuncPerBuffer = GL_TRUE;
+
+   if (ctx->Driver.BlendFuncSeparatei) {
+      ctx->Driver.BlendFuncSeparatei(ctx, buf, sfactorRGB, dfactorRGB,
+                                     sfactorA, dfactorA);
+   }
+}
+
+
+/**
+ * Check if given blend equation is legal.
+ * \return GL_TRUE if legal, GL_FALSE otherwise.
+ */
+static GLboolean
+legal_blend_equation(const struct gl_context *ctx,
+                     GLenum mode, GLboolean is_separate)
+{
+   switch (mode) {
+   case GL_FUNC_ADD:
+      return GL_TRUE;
+   case GL_MIN:
+   case GL_MAX:
+      return ctx->Extensions.EXT_blend_minmax;
+   case GL_LOGIC_OP:
+      /* glBlendEquationSeparate cannot take GL_LOGIC_OP as a parameter.
+       */
+      return ctx->Extensions.EXT_blend_logic_op && !is_separate;
+   case GL_FUNC_SUBTRACT:
+   case GL_FUNC_REVERSE_SUBTRACT:
+      return ctx->Extensions.EXT_blend_subtract;
+   default:
+      return GL_FALSE;
+   }
 }
 
 
@@ -244,6 +311,8 @@
 void GLAPIENTRY
 _mesa_BlendEquation( GLenum mode )
 {
+   GLuint buf, numBuffers;
+   GLboolean changed;
    GET_CURRENT_CONTEXT(ctx);
    ASSERT_OUTSIDE_BEGIN_END(ctx);
 
@@ -251,27 +320,80 @@
       _mesa_debug(ctx, "glBlendEquation %s\n",
                   _mesa_lookup_enum_by_nr(mode));
 
-   if ( ! _mesa_validate_blend_equation( ctx, mode, GL_FALSE ) ) {
+   if (!legal_blend_equation(ctx, mode, GL_FALSE)) {
       _mesa_error(ctx, GL_INVALID_ENUM, "glBlendEquation");
       return;
    }
 
-   if ( (ctx->Color.BlendEquationRGB == mode) &&
-	(ctx->Color.BlendEquationA == mode) )
+   numBuffers = ctx->Extensions.ARB_draw_buffers_blend
+      ? ctx->Const.MaxDrawBuffers : 1;
+
+   changed = GL_FALSE;
+   for (buf = 0; buf < numBuffers; buf++) {
+      if (ctx->Color.Blend[buf].EquationRGB != mode ||
+          ctx->Color.Blend[buf].EquationA != mode) {
+         changed = GL_TRUE;
+         break;
+      }
+   }
+   if (!changed)
       return;
 
    FLUSH_VERTICES(ctx, _NEW_COLOR);
-   ctx->Color.BlendEquationRGB = mode;
-   ctx->Color.BlendEquationA = mode;
+   for (buf = 0; buf < numBuffers; buf++) {
+      ctx->Color.Blend[buf].EquationRGB = mode;
+      ctx->Color.Blend[buf].EquationA = mode;
+   }
+   ctx->Color._BlendEquationPerBuffer = GL_FALSE;
 
    if (ctx->Driver.BlendEquationSeparate)
       (*ctx->Driver.BlendEquationSeparate)( ctx, mode, mode );
 }
 
 
+/**
+ * Set blend equation for one color buffer/target.
+ */
+void GLAPIENTRY
+_mesa_BlendEquationi(GLuint buf, GLenum mode)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+   if (MESA_VERBOSE & VERBOSE_API)
+      _mesa_debug(ctx, "glBlendEquationi(%u, %s)\n",
+                  buf, _mesa_lookup_enum_by_nr(mode));
+
+   if (buf >= ctx->Const.MaxDrawBuffers) {
+      _mesa_error(ctx, GL_INVALID_VALUE, "glBlendFuncSeparatei(buffer=%u)",
+                  buf);
+      return;
+   }
+
+   if (!legal_blend_equation(ctx, mode, GL_FALSE)) {
+      _mesa_error(ctx, GL_INVALID_ENUM, "glBlendEquationi");
+      return;
+   }
+
+   if (ctx->Color.Blend[buf].EquationRGB == mode &&
+       ctx->Color.Blend[buf].EquationA == mode)
+      return;  /* no change */
+
+   FLUSH_VERTICES(ctx, _NEW_COLOR);
+   ctx->Color.Blend[buf].EquationRGB = mode;
+   ctx->Color.Blend[buf].EquationA = mode;
+   ctx->Color._BlendEquationPerBuffer = GL_TRUE;
+
+   if (ctx->Driver.BlendEquationSeparatei)
+      ctx->Driver.BlendEquationSeparatei(ctx, buf, mode, mode);
+}
+
+
 void GLAPIENTRY
 _mesa_BlendEquationSeparateEXT( GLenum modeRGB, GLenum modeA )
 {
+   GLuint buf, numBuffers;
+   GLboolean changed;
    GET_CURRENT_CONTEXT(ctx);
    ASSERT_OUTSIDE_BEGIN_END(ctx);
 
@@ -286,29 +408,88 @@
       return;
    }
 
-   if ( ! _mesa_validate_blend_equation( ctx, modeRGB, GL_TRUE ) ) {
+   if (!legal_blend_equation(ctx, modeRGB, GL_TRUE)) {
       _mesa_error(ctx, GL_INVALID_ENUM, "glBlendEquationSeparateEXT(modeRGB)");
       return;
    }
 
-   if ( ! _mesa_validate_blend_equation( ctx, modeA, GL_TRUE ) ) {
+   if (!legal_blend_equation(ctx, modeA, GL_TRUE)) {
       _mesa_error(ctx, GL_INVALID_ENUM, "glBlendEquationSeparateEXT(modeA)");
       return;
    }
 
+   numBuffers = ctx->Extensions.ARB_draw_buffers_blend
+      ? ctx->Const.MaxDrawBuffers : 1;
 
-   if ( (ctx->Color.BlendEquationRGB == modeRGB) &&
-	(ctx->Color.BlendEquationA == modeA) )
+   changed = GL_FALSE;
+   for (buf = 0; buf < numBuffers; buf++) {
+      if (ctx->Color.Blend[buf].EquationRGB != modeRGB ||
+          ctx->Color.Blend[buf].EquationA != modeA) {
+         changed = GL_TRUE;
+         break;
+      }
+   }
+   if (!changed)
       return;
 
    FLUSH_VERTICES(ctx, _NEW_COLOR);
-   ctx->Color.BlendEquationRGB = modeRGB;
-   ctx->Color.BlendEquationA = modeA;
+   for (buf = 0; buf < numBuffers; buf++) {
+      ctx->Color.Blend[buf].EquationRGB = modeRGB;
+      ctx->Color.Blend[buf].EquationA = modeA;
+   }
+   ctx->Color._BlendEquationPerBuffer = GL_FALSE;
 
    if (ctx->Driver.BlendEquationSeparate)
-      (*ctx->Driver.BlendEquationSeparate)( ctx, modeRGB, modeA );
+      ctx->Driver.BlendEquationSeparate(ctx, modeRGB, modeA);
 }
-#endif
+
+
+/**
+ * Set separate blend equations for one color buffer/target.
+ */
+void
+_mesa_BlendEquationSeparatei(GLuint buf, GLenum modeRGB, GLenum modeA)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+   if (MESA_VERBOSE & VERBOSE_API)
+      _mesa_debug(ctx, "glBlendEquationSeparatei %u, %s %s\n", buf,
+                  _mesa_lookup_enum_by_nr(modeRGB),
+                  _mesa_lookup_enum_by_nr(modeA));
+
+   if (buf >= ctx->Const.MaxDrawBuffers) {
+      _mesa_error(ctx, GL_INVALID_VALUE, "glBlendEquationSeparatei(buffer=%u)",
+                  buf);
+      return;
+   }
+
+   if (!legal_blend_equation(ctx, modeRGB, GL_TRUE)) {
+      _mesa_error(ctx, GL_INVALID_ENUM, "glBlendEquationSeparatei(modeRGB)");
+      return;
+   }
+
+   if (!legal_blend_equation(ctx, modeA, GL_TRUE)) {
+      _mesa_error(ctx, GL_INVALID_ENUM, "glBlendEquationSeparatei(modeA)");
+      return;
+   }
+
+   if (ctx->Color.Blend[buf].EquationRGB == modeRGB &&
+       ctx->Color.Blend[buf].EquationA == modeA)
+      return;  /* no change */
+
+   FLUSH_VERTICES(ctx, _NEW_COLOR);
+   ctx->Color.Blend[buf].EquationRGB = modeRGB;
+   ctx->Color.Blend[buf].EquationA = modeA;
+   ctx->Color._BlendEquationPerBuffer = GL_TRUE;
+
+   if (ctx->Driver.BlendEquationSeparatei)
+      ctx->Driver.BlendEquationSeparatei(ctx, buf, modeRGB, modeA);
+}
+
+
+
+#endif /* _HAVE_FULL_GL */
 
 
 /**
@@ -593,6 +774,8 @@
  */
 void _mesa_init_color( struct gl_context * ctx )
 {
+   GLuint i;
+
    /* Color buffer group */
    ctx->Color.IndexMask = ~0u;
    memset(ctx->Color.ColorMask, 0xff, sizeof(ctx->Color.ColorMask));
@@ -602,12 +785,14 @@
    ctx->Color.AlphaFunc = GL_ALWAYS;
    ctx->Color.AlphaRef = 0;
    ctx->Color.BlendEnabled = 0x0;
-   ctx->Color.BlendSrcRGB = GL_ONE;
-   ctx->Color.BlendDstRGB = GL_ZERO;
-   ctx->Color.BlendSrcA = GL_ONE;
-   ctx->Color.BlendDstA = GL_ZERO;
-   ctx->Color.BlendEquationRGB = GL_FUNC_ADD;
-   ctx->Color.BlendEquationA = GL_FUNC_ADD;
+   for (i = 0; i < Elements(ctx->Color.Blend); i++) {
+      ctx->Color.Blend[i].SrcRGB = GL_ONE;
+      ctx->Color.Blend[i].DstRGB = GL_ZERO;
+      ctx->Color.Blend[i].SrcA = GL_ONE;
+      ctx->Color.Blend[i].DstA = GL_ZERO;
+      ctx->Color.Blend[i].EquationRGB = GL_FUNC_ADD;
+      ctx->Color.Blend[i].EquationA = GL_FUNC_ADD;
+   }
    ASSIGN_4V( ctx->Color.BlendColor, 0.0, 0.0, 0.0, 0.0 );
    ctx->Color.IndexLogicOpEnabled = GL_FALSE;
    ctx->Color.ColorLogicOpEnabled = GL_FALSE;
diff --git a/src/mesa/main/blend.h b/src/mesa/main/blend.h
index f72c779..39e7c9f 100644
--- a/src/mesa/main/blend.h
+++ b/src/mesa/main/blend.h
@@ -48,13 +48,30 @@
 
 
 extern void GLAPIENTRY
+_mesa_BlendFunci(GLuint buf, GLenum sfactor, GLenum dfactor);
+
+
+extern void GLAPIENTRY
+_mesa_BlendFuncSeparatei(GLuint buf, GLenum sfactorRGB, GLenum dfactorRGB,
+                         GLenum sfactorA, GLenum dfactorA);
+
+
+extern void GLAPIENTRY
 _mesa_BlendEquation( GLenum mode );
 
 
 extern void GLAPIENTRY
+_mesa_BlendEquationi(GLuint buf, GLenum mode);
+
+
+extern void GLAPIENTRY
 _mesa_BlendEquationSeparateEXT( GLenum modeRGB, GLenum modeA );
 
 
+extern void
+_mesa_BlendEquationSeparatei(GLuint buf, GLenum modeRGB, GLenum modeA);
+
+
 extern void GLAPIENTRY
 _mesa_BlendColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
 
diff --git a/src/mesa/main/context.h b/src/mesa/main/context.h
index 42d98a3..8fb9b4c 100644
--- a/src/mesa/main/context.h
+++ b/src/mesa/main/context.h
@@ -320,7 +320,7 @@
  */
 #define RGBA_LOGICOP_ENABLED(CTX) \
   ((CTX)->Color.ColorLogicOpEnabled || \
-   ((CTX)->Color.BlendEnabled && (CTX)->Color.BlendEquationRGB == GL_LOGIC_OP))
+   ((CTX)->Color.BlendEnabled && (CTX)->Color.Blend[0].EquationRGB == GL_LOGIC_OP))
 
 
 #endif /* CONTEXT_H */
diff --git a/src/mesa/main/dd.h b/src/mesa/main/dd.h
index c62969e..2eede42 100644
--- a/src/mesa/main/dd.h
+++ b/src/mesa/main/dd.h
@@ -635,10 +635,15 @@
    void (*BlendColor)(struct gl_context *ctx, const GLfloat color[4]);
    /** Set the blend equation */
    void (*BlendEquationSeparate)(struct gl_context *ctx, GLenum modeRGB, GLenum modeA);
+   void (*BlendEquationSeparatei)(struct gl_context *ctx, GLuint buffer,
+                                  GLenum modeRGB, GLenum modeA);
    /** Specify pixel arithmetic */
    void (*BlendFuncSeparate)(struct gl_context *ctx,
                              GLenum sfactorRGB, GLenum dfactorRGB,
                              GLenum sfactorA, GLenum dfactorA);
+   void (*BlendFuncSeparatei)(struct gl_context *ctx, GLuint buffer,
+                              GLenum sfactorRGB, GLenum dfactorRGB,
+                              GLenum sfactorA, GLenum dfactorA);
    /** Specify clear values for the color buffers */
    void (*ClearColor)(struct gl_context *ctx, const GLfloat color[4]);
    /** Specify the clear value for the depth buffer */
diff --git a/src/mesa/main/extensions.c b/src/mesa/main/extensions.c
index 2440499..8ca1339 100644
--- a/src/mesa/main/extensions.c
+++ b/src/mesa/main/extensions.c
@@ -80,6 +80,7 @@
    { "GL_ARB_depth_clamp",                         o(ARB_depth_clamp),                         GL             },
    { "GL_ARB_depth_texture",                       o(ARB_depth_texture),                       GL             },
    { "GL_ARB_draw_buffers",                        o(ARB_draw_buffers),                        GL             },
+   { "GL_ARB_draw_buffers_blend",                  o(ARB_draw_buffers_blend),                  GL             },
    { "GL_ARB_draw_elements_base_vertex",           o(ARB_draw_elements_base_vertex),           GL             },
    { "GL_ARB_draw_instanced",                      o(ARB_draw_instanced),                      GL             },
    { "GL_ARB_explicit_attrib_location",            o(ARB_explicit_attrib_location),            GL             },
diff --git a/src/mesa/main/get.c b/src/mesa/main/get.c
index ba273ce..6f47eca 100644
--- a/src/mesa/main/get.c
+++ b/src/mesa/main/get.c
@@ -372,7 +372,7 @@
      API_OPENGL_BIT | API_OPENGLES_BIT | API_OPENGLES2_BIT, NO_EXTRA},
    { GL_ALPHA_BITS, BUFFER_INT(Visual.alphaBits), extra_new_buffers },
    { GL_BLEND, CONTEXT_BIT0(Color.BlendEnabled), NO_EXTRA },
-   { GL_BLEND_SRC, CONTEXT_ENUM(Color.BlendSrcRGB), NO_EXTRA },
+   { GL_BLEND_SRC, CONTEXT_ENUM(Color.Blend[0].SrcRGB), NO_EXTRA },
    { GL_BLUE_BITS, BUFFER_INT(Visual.blueBits), extra_new_buffers },
    { GL_COLOR_CLEAR_VALUE, CONTEXT_FIELD(Color.ClearColor[0], TYPE_FLOATN_4), NO_EXTRA },
    { GL_COLOR_WRITEMASK, LOC_CUSTOM, TYPE_INT_4, 0, NO_EXTRA },
@@ -435,15 +435,15 @@
      extra_ARB_texture_cube_map }, /* XXX: OES_texture_cube_map */
 
    /* XXX: OES_blend_subtract */
-   { GL_BLEND_SRC_RGB_EXT, CONTEXT_ENUM(Color.BlendSrcRGB), NO_EXTRA },
-   { GL_BLEND_DST_RGB_EXT, CONTEXT_ENUM(Color.BlendDstRGB), NO_EXTRA },
-   { GL_BLEND_SRC_ALPHA_EXT, CONTEXT_ENUM(Color.BlendSrcA), NO_EXTRA },
-   { GL_BLEND_DST_ALPHA_EXT, CONTEXT_ENUM(Color.BlendDstA), NO_EXTRA },
+   { GL_BLEND_SRC_RGB_EXT, CONTEXT_ENUM(Color.Blend[0].SrcRGB), NO_EXTRA },
+   { GL_BLEND_DST_RGB_EXT, CONTEXT_ENUM(Color.Blend[0].DstRGB), NO_EXTRA },
+   { GL_BLEND_SRC_ALPHA_EXT, CONTEXT_ENUM(Color.Blend[0].SrcA), NO_EXTRA },
+   { GL_BLEND_DST_ALPHA_EXT, CONTEXT_ENUM(Color.Blend[0].DstA), NO_EXTRA },
 
    /* GL_BLEND_EQUATION_RGB, which is what we're really after, is
     * defined identically to GL_BLEND_EQUATION. */
-   { GL_BLEND_EQUATION, CONTEXT_ENUM(Color.BlendEquationRGB), NO_EXTRA },
-   { GL_BLEND_EQUATION_ALPHA_EXT, CONTEXT_ENUM(Color.BlendEquationA), NO_EXTRA },
+   { GL_BLEND_EQUATION, CONTEXT_ENUM(Color.Blend[0].EquationRGB), NO_EXTRA },
+   { GL_BLEND_EQUATION_ALPHA_EXT, CONTEXT_ENUM(Color.Blend[0].EquationA), NO_EXTRA },
 
    /* GL_ARB_texture_compression */
    { GL_NUM_COMPRESSED_TEXTURE_FORMATS_ARB, LOC_CUSTOM, TYPE_INT, 0, NO_EXTRA },
@@ -512,7 +512,7 @@
    { GL_ALPHA_TEST, CONTEXT_BOOL(Color.AlphaEnabled), NO_EXTRA },
    { GL_ALPHA_TEST_FUNC, CONTEXT_ENUM(Color.AlphaFunc), NO_EXTRA },
    { GL_ALPHA_TEST_REF, CONTEXT_FIELD(Color.AlphaRef, TYPE_FLOATN), NO_EXTRA },
-   { GL_BLEND_DST, CONTEXT_ENUM(Color.BlendDstRGB), NO_EXTRA },
+   { GL_BLEND_DST, CONTEXT_ENUM(Color.Blend[0].DstRGB), NO_EXTRA },
    { GL_CLIP_PLANE0, CONTEXT_BIT0(Transform.ClipPlanesEnabled), NO_EXTRA },
    { GL_CLIP_PLANE1, CONTEXT_BIT1(Transform.ClipPlanesEnabled), NO_EXTRA },
    { GL_CLIP_PLANE2, CONTEXT_BIT2(Transform.ClipPlanesEnabled), NO_EXTRA },
diff --git a/src/mesa/main/mtypes.h b/src/mesa/main/mtypes.h
index 7b4c116..55c5fd2 100644
--- a/src/mesa/main/mtypes.h
+++ b/src/mesa/main/mtypes.h
@@ -719,13 +719,20 @@
     */
    /*@{*/
    GLbitfield BlendEnabled;		/**< Per-buffer blend enable flags */
-   GLenum BlendSrcRGB;			/**< Blending source operator */
-   GLenum BlendDstRGB;			/**< Blending destination operator */
-   GLenum BlendSrcA;			/**< GL_INGR_blend_func_separate */
-   GLenum BlendDstA;			/**< GL_INGR_blend_func_separate */
-   GLenum BlendEquationRGB;		/**< Blending equation */
-   GLenum BlendEquationA;		/**< GL_EXT_blend_equation_separate */
    GLfloat BlendColor[4];		/**< Blending color */
+   struct
+   {
+      GLenum SrcRGB;             /**< RGB blend source term */
+      GLenum DstRGB;             /**< RGB blend dest term */
+      GLenum SrcA;               /**< Alpha blend source term */
+      GLenum DstA;               /**< Alpha blend dest term */
+      GLenum EquationRGB;        /**< GL_ADD, GL_SUBTRACT, etc. */
+      GLenum EquationA;          /**< GL_ADD, GL_SUBTRACT, etc. */
+   } Blend[MAX_DRAW_BUFFERS];
+   /** Are the blend func terms currently different for each buffer/target? */
+   GLboolean _BlendFuncPerBuffer;
+   /** Are the blend equations currently different for each buffer/target? */
+   GLboolean _BlendEquationPerBuffer;
    /*@}*/
 
    /** 
@@ -2679,6 +2686,7 @@
    GLboolean ARB_depth_clamp;
    GLboolean ARB_depth_texture;
    GLboolean ARB_draw_buffers;
+   GLboolean ARB_draw_buffers_blend;
    GLboolean ARB_draw_elements_base_vertex;
    GLboolean ARB_draw_instanced;
    GLboolean ARB_fragment_coord_conventions;
diff --git a/src/mesa/state_tracker/st_atom_blend.c b/src/mesa/state_tracker/st_atom_blend.c
index a8ec4ad..8a3609e 100644
--- a/src/mesa/state_tracker/st_atom_blend.c
+++ b/src/mesa/state_tracker/st_atom_blend.c
@@ -169,13 +169,18 @@
 }
 
 /**
- * Figure out if blend enables are different per rt.
+ * Figure out if blend enables/state are different per rt.
  */
 static GLboolean
 blend_per_rt(struct gl_context *ctx)
 {
    if (ctx->Color.BlendEnabled &&
       (ctx->Color.BlendEnabled != ((1 << ctx->Const.MaxDrawBuffers) - 1))) {
+      /* This can only happen if GL_EXT_draw_buffers2 is enabled */
+      return GL_TRUE;
+   }
+   if (ctx->Color._BlendFuncPerBuffer || ctx->Color._BlendEquationPerBuffer) {
+      /* this can only happen if GL_ARB_draw_buffers_blend is enabled */
       return GL_TRUE;
    }
    return GL_FALSE;
@@ -202,7 +207,7 @@
       don't happen. */
    if (st->ctx->Color.ColorLogicOpEnabled ||
        (st->ctx->Color.BlendEnabled &&
-        st->ctx->Color.BlendEquationRGB == GL_LOGIC_OP)) {
+        st->ctx->Color.Blend[0].EquationRGB == GL_LOGIC_OP)) {
       /* logicop enabled */
       blend->logicop_enable = 1;
       blend->logicop_func = translate_logicop(st->ctx->Color.LogicOp);
@@ -213,28 +218,36 @@
 
          blend->rt[i].blend_enable = (st->ctx->Color.BlendEnabled >> i) & 0x1;
 
-         blend->rt[i].rgb_func = translate_blend(st->ctx->Color.BlendEquationRGB);
-         if (st->ctx->Color.BlendEquationRGB == GL_MIN ||
-             st->ctx->Color.BlendEquationRGB == GL_MAX) {
+         blend->rt[i].rgb_func =
+            translate_blend(st->ctx->Color.Blend[i].EquationRGB);
+
+         if (st->ctx->Color.Blend[i].EquationRGB == GL_MIN ||
+             st->ctx->Color.Blend[i].EquationRGB == GL_MAX) {
             /* Min/max are special */
             blend->rt[i].rgb_src_factor = PIPE_BLENDFACTOR_ONE;
             blend->rt[i].rgb_dst_factor = PIPE_BLENDFACTOR_ONE;
          }
          else {
-            blend->rt[i].rgb_src_factor = translate_blend(st->ctx->Color.BlendSrcRGB);
-            blend->rt[i].rgb_dst_factor = translate_blend(st->ctx->Color.BlendDstRGB);
+            blend->rt[i].rgb_src_factor =
+               translate_blend(st->ctx->Color.Blend[i].SrcRGB);
+            blend->rt[i].rgb_dst_factor =
+               translate_blend(st->ctx->Color.Blend[i].DstRGB);
          }
 
-         blend->rt[i].alpha_func = translate_blend(st->ctx->Color.BlendEquationA);
-         if (st->ctx->Color.BlendEquationA == GL_MIN ||
-             st->ctx->Color.BlendEquationA == GL_MAX) {
+         blend->rt[i].alpha_func =
+            translate_blend(st->ctx->Color.Blend[i].EquationA);
+
+         if (st->ctx->Color.Blend[i].EquationA == GL_MIN ||
+             st->ctx->Color.Blend[i].EquationA == GL_MAX) {
             /* Min/max are special */
             blend->rt[i].alpha_src_factor = PIPE_BLENDFACTOR_ONE;
             blend->rt[i].alpha_dst_factor = PIPE_BLENDFACTOR_ONE;
          }
          else {
-            blend->rt[i].alpha_src_factor = translate_blend(st->ctx->Color.BlendSrcA);
-            blend->rt[i].alpha_dst_factor = translate_blend(st->ctx->Color.BlendDstA);
+            blend->rt[i].alpha_src_factor =
+               translate_blend(st->ctx->Color.Blend[i].SrcA);
+            blend->rt[i].alpha_dst_factor =
+               translate_blend(st->ctx->Color.Blend[i].DstA);
          }
       }
    }
diff --git a/src/mesa/state_tracker/st_extensions.c b/src/mesa/state_tracker/st_extensions.c
index 6798675..aead592 100644
--- a/src/mesa/state_tracker/st_extensions.c
+++ b/src/mesa/state_tracker/st_extensions.c
@@ -438,11 +438,9 @@
       ctx->Extensions.ARB_half_float_vertex = GL_TRUE;
    }
 
-#if 0 /* not yet */
    if (screen->get_param(screen, PIPE_CAP_INDEP_BLEND_FUNC)) {
       ctx->Extensions.ARB_draw_buffers_blend = GL_TRUE;
    }
-#endif
 
    if (screen->get_shader_param(screen, PIPE_SHADER_GEOMETRY, PIPE_SHADER_CAP_MAX_INSTRUCTIONS) > 0) {
 #if 0 /* XXX re-enable when GLSL compiler again supports geometry shaders */
diff --git a/src/mesa/swrast/s_blend.c b/src/mesa/swrast/s_blend.c
index d61baba..7939212 100644
--- a/src/mesa/swrast/s_blend.c
+++ b/src/mesa/swrast/s_blend.c
@@ -75,10 +75,10 @@
 {
    GLint bytes;
 
-   ASSERT(ctx->Color.BlendEquationRGB == GL_FUNC_ADD);
-   ASSERT(ctx->Color.BlendEquationA == GL_FUNC_ADD);
-   ASSERT(ctx->Color.BlendSrcRGB == GL_ZERO);
-   ASSERT(ctx->Color.BlendDstRGB == GL_ONE);
+   ASSERT(ctx->Color.Blend[0].EquationRGB == GL_FUNC_ADD);
+   ASSERT(ctx->Color.Blend[0].EquationA == GL_FUNC_ADD);
+   ASSERT(ctx->Color.Blend[0].SrcRGB == GL_ZERO);
+   ASSERT(ctx->Color.Blend[0].DstRGB == GL_ONE);
    (void) ctx;
 
    /* just memcpy */
@@ -101,10 +101,10 @@
 blend_replace(struct gl_context *ctx, GLuint n, const GLubyte mask[],
               GLvoid *src, const GLvoid *dst, GLenum chanType)
 {
-   ASSERT(ctx->Color.BlendEquationRGB == GL_FUNC_ADD);
-   ASSERT(ctx->Color.BlendEquationA == GL_FUNC_ADD);
-   ASSERT(ctx->Color.BlendSrcRGB == GL_ONE);
-   ASSERT(ctx->Color.BlendDstRGB == GL_ZERO);
+   ASSERT(ctx->Color.Blend[0].EquationRGB == GL_FUNC_ADD);
+   ASSERT(ctx->Color.Blend[0].EquationA == GL_FUNC_ADD);
+   ASSERT(ctx->Color.Blend[0].SrcRGB == GL_ONE);
+   ASSERT(ctx->Color.Blend[0].DstRGB == GL_ZERO);
    (void) ctx;
    (void) n;
    (void) mask;
@@ -125,12 +125,12 @@
    const GLubyte (*dest)[4] = (const GLubyte (*)[4]) dst;
    GLuint i;
 
-   ASSERT(ctx->Color.BlendEquationRGB == GL_FUNC_ADD);
-   ASSERT(ctx->Color.BlendEquationA == GL_FUNC_ADD);
-   ASSERT(ctx->Color.BlendSrcRGB == GL_SRC_ALPHA);
-   ASSERT(ctx->Color.BlendSrcA == GL_SRC_ALPHA);
-   ASSERT(ctx->Color.BlendDstRGB == GL_ONE_MINUS_SRC_ALPHA);
-   ASSERT(ctx->Color.BlendDstA == GL_ONE_MINUS_SRC_ALPHA);
+   ASSERT(ctx->Color.Blend[0].EquationRGB == GL_FUNC_ADD);
+   ASSERT(ctx->Color.Blend[0].EquationA == GL_FUNC_ADD);
+   ASSERT(ctx->Color.Blend[0].SrcRGB == GL_SRC_ALPHA);
+   ASSERT(ctx->Color.Blend[0].SrcA == GL_SRC_ALPHA);
+   ASSERT(ctx->Color.Blend[0].DstRGB == GL_ONE_MINUS_SRC_ALPHA);
+   ASSERT(ctx->Color.Blend[0].DstA == GL_ONE_MINUS_SRC_ALPHA);
    ASSERT(chanType == GL_UNSIGNED_BYTE);
 
    (void) ctx;
@@ -170,12 +170,12 @@
    const GLushort (*dest)[4] = (const GLushort (*)[4]) dst;
    GLuint i;
 
-   ASSERT(ctx->Color.BlendEquationRGB == GL_FUNC_ADD);
-   ASSERT(ctx->Color.BlendEquationA == GL_FUNC_ADD);
-   ASSERT(ctx->Color.BlendSrcRGB == GL_SRC_ALPHA);
-   ASSERT(ctx->Color.BlendSrcA == GL_SRC_ALPHA);
-   ASSERT(ctx->Color.BlendDstRGB == GL_ONE_MINUS_SRC_ALPHA);
-   ASSERT(ctx->Color.BlendDstA == GL_ONE_MINUS_SRC_ALPHA);
+   ASSERT(ctx->Color.Blend[0].EquationRGB == GL_FUNC_ADD);
+   ASSERT(ctx->Color.Blend[0].EquationA == GL_FUNC_ADD);
+   ASSERT(ctx->Color.Blend[0].SrcRGB == GL_SRC_ALPHA);
+   ASSERT(ctx->Color.Blend[0].SrcA == GL_SRC_ALPHA);
+   ASSERT(ctx->Color.Blend[0].DstRGB == GL_ONE_MINUS_SRC_ALPHA);
+   ASSERT(ctx->Color.Blend[0].DstA == GL_ONE_MINUS_SRC_ALPHA);
    ASSERT(chanType == GL_UNSIGNED_SHORT);
 
    (void) ctx;
@@ -208,12 +208,12 @@
    const GLfloat (*dest)[4] = (const GLfloat (*)[4]) dst;
    GLuint i;
 
-   ASSERT(ctx->Color.BlendEquationRGB == GL_FUNC_ADD);
-   ASSERT(ctx->Color.BlendEquationA == GL_FUNC_ADD);
-   ASSERT(ctx->Color.BlendSrcRGB == GL_SRC_ALPHA);
-   ASSERT(ctx->Color.BlendSrcA == GL_SRC_ALPHA);
-   ASSERT(ctx->Color.BlendDstRGB == GL_ONE_MINUS_SRC_ALPHA);
-   ASSERT(ctx->Color.BlendDstA == GL_ONE_MINUS_SRC_ALPHA);
+   ASSERT(ctx->Color.Blend[0].EquationRGB == GL_FUNC_ADD);
+   ASSERT(ctx->Color.Blend[0].EquationA == GL_FUNC_ADD);
+   ASSERT(ctx->Color.Blend[0].SrcRGB == GL_SRC_ALPHA);
+   ASSERT(ctx->Color.Blend[0].SrcA == GL_SRC_ALPHA);
+   ASSERT(ctx->Color.Blend[0].DstRGB == GL_ONE_MINUS_SRC_ALPHA);
+   ASSERT(ctx->Color.Blend[0].DstA == GL_ONE_MINUS_SRC_ALPHA);
    ASSERT(chanType == GL_FLOAT);
 
    (void) ctx;
@@ -248,10 +248,10 @@
 {
    GLuint i;
 
-   ASSERT(ctx->Color.BlendEquationRGB == GL_FUNC_ADD);
-   ASSERT(ctx->Color.BlendEquationA == GL_FUNC_ADD);
-   ASSERT(ctx->Color.BlendSrcRGB == GL_ONE);
-   ASSERT(ctx->Color.BlendDstRGB == GL_ONE);
+   ASSERT(ctx->Color.Blend[0].EquationRGB == GL_FUNC_ADD);
+   ASSERT(ctx->Color.Blend[0].EquationA == GL_FUNC_ADD);
+   ASSERT(ctx->Color.Blend[0].SrcRGB == GL_ONE);
+   ASSERT(ctx->Color.Blend[0].DstRGB == GL_ONE);
    (void) ctx;
 
    if (chanType == GL_UNSIGNED_BYTE) {
@@ -313,8 +313,8 @@
           GLvoid *src, const GLvoid *dst, GLenum chanType)
 {
    GLuint i;
-   ASSERT(ctx->Color.BlendEquationRGB == GL_MIN);
-   ASSERT(ctx->Color.BlendEquationA == GL_MIN);
+   ASSERT(ctx->Color.Blend[0].EquationRGB == GL_MIN);
+   ASSERT(ctx->Color.Blend[0].EquationA == GL_MIN);
    (void) ctx;
 
    if (chanType == GL_UNSIGNED_BYTE) {
@@ -366,8 +366,8 @@
           GLvoid *src, const GLvoid *dst, GLenum chanType)
 {
    GLuint i;
-   ASSERT(ctx->Color.BlendEquationRGB == GL_MAX);
-   ASSERT(ctx->Color.BlendEquationA == GL_MAX);
+   ASSERT(ctx->Color.Blend[0].EquationRGB == GL_MAX);
+   ASSERT(ctx->Color.Blend[0].EquationA == GL_MAX);
    (void) ctx;
 
    if (chanType == GL_UNSIGNED_BYTE) {
@@ -500,7 +500,7 @@
           */
 
          /* Source RGB factor */
-         switch (ctx->Color.BlendSrcRGB) {
+         switch (ctx->Color.Blend[0].SrcRGB) {
             case GL_ZERO:
                sR = sG = sB = 0.0F;
                break;
@@ -570,7 +570,7 @@
          }
 
          /* Source Alpha factor */
-         switch (ctx->Color.BlendSrcA) {
+         switch (ctx->Color.Blend[0].SrcA) {
             case GL_ZERO:
                sA = 0.0F;
                break;
@@ -624,7 +624,7 @@
          }
 
          /* Dest RGB factor */
-         switch (ctx->Color.BlendDstRGB) {
+         switch (ctx->Color.Blend[0].DstRGB) {
             case GL_ZERO:
                dR = dG = dB = 0.0F;
                break;
@@ -687,7 +687,7 @@
          }
 
          /* Dest Alpha factor */
-         switch (ctx->Color.BlendDstA) {
+         switch (ctx->Color.Blend[0].DstA) {
             case GL_ZERO:
                dA = 0.0F;
                break;
@@ -738,7 +738,7 @@
          }
 
          /* compute the blended RGB */
-         switch (ctx->Color.BlendEquationRGB) {
+         switch (ctx->Color.Blend[0].EquationRGB) {
          case GL_FUNC_ADD:
             r = Rs * sR + Rd * dR;
             g = Gs * sG + Gd * dG;
@@ -775,7 +775,7 @@
          }
 
          /* compute the blended alpha */
-         switch (ctx->Color.BlendEquationA) {
+         switch (ctx->Color.Blend[0].EquationA) {
          case GL_FUNC_ADD:
             a = As * sA + Ad * dA;
             break;
@@ -907,13 +907,13 @@
 _swrast_choose_blend_func(struct gl_context *ctx, GLenum chanType)
 {
    SWcontext *swrast = SWRAST_CONTEXT(ctx);
-   const GLenum eq = ctx->Color.BlendEquationRGB;
-   const GLenum srcRGB = ctx->Color.BlendSrcRGB;
-   const GLenum dstRGB = ctx->Color.BlendDstRGB;
-   const GLenum srcA = ctx->Color.BlendSrcA;
-   const GLenum dstA = ctx->Color.BlendDstA;
+   const GLenum eq = ctx->Color.Blend[0].EquationRGB;
+   const GLenum srcRGB = ctx->Color.Blend[0].SrcRGB;
+   const GLenum dstRGB = ctx->Color.Blend[0].DstRGB;
+   const GLenum srcA = ctx->Color.Blend[0].SrcA;
+   const GLenum dstA = ctx->Color.Blend[0].DstA;
 
-   if (ctx->Color.BlendEquationRGB != ctx->Color.BlendEquationA) {
+   if (ctx->Color.Blend[0].EquationRGB != ctx->Color.Blend[0].EquationA) {
       swrast->BlendFunc = blend_general;
    }
    else if (eq == GL_MIN) {