llvmpipe: Get blending of normalized 8bit unsigned integers working.
authorJosé Fonseca <jfonseca@vmware.com>
Sun, 2 Aug 2009 23:01:27 +0000 (00:01 +0100)
committerJosé Fonseca <jfonseca@vmware.com>
Sat, 29 Aug 2009 08:21:22 +0000 (09:21 +0100)
src/gallium/drivers/llvmpipe/lp_bld_arit.c
src/gallium/drivers/llvmpipe/lp_test_blend.c

index f45b7d82f1455e4fd226dfa1900c4b187ed1cf96..ba272df296136a92dcf73b23ec1eabc7e3d4989d 100644 (file)
@@ -184,7 +184,7 @@ lp_build_one(union lp_type type)
    LLVMValueRef elems[LP_MAX_VECTOR_LENGTH];
    unsigned i;
 
-   assert(type.length < LP_MAX_VECTOR_LENGTH);
+   assert(type.length <= LP_MAX_VECTOR_LENGTH);
 
    elem_type = lp_build_elem_type(type);
 
@@ -224,7 +224,7 @@ lp_build_const_aos(union lp_type type,
    unsigned i;
 
    assert(type.length % 4 == 0);
-   assert(type.length < LP_MAX_VECTOR_LENGTH);
+   assert(type.length <= LP_MAX_VECTOR_LENGTH);
 
    elem_type = lp_build_elem_type(type);
 
@@ -421,9 +421,9 @@ lp_build_add(struct lp_build_context *bld,
       if(type.width * type.length == 128 &&
          !type.floating && !type.fixed) {
          if(type.width == 8)
-            intrinsic = type.sign ? "llvm.x86.sse2.adds.b" : "llvm.x86.sse2.addus.b";
+            intrinsic = type.sign ? "llvm.x86.sse2.padds.b" : "llvm.x86.sse2.paddus.b";
          if(type.width == 16)
-            intrinsic = type.sign ? "llvm.x86.sse2.adds.w" : "llvm.x86.sse2.addus.w";
+            intrinsic = type.sign ? "llvm.x86.sse2.padds.w" : "llvm.x86.sse2.paddus.w";
       }
 #endif
    
@@ -468,9 +468,9 @@ lp_build_sub(struct lp_build_context *bld,
       if(type.width * type.length == 128 &&
          !type.floating && !type.fixed) {
          if(type.width == 8)
-            intrinsic = type.sign ? "llvm.x86.sse2.subs.b" : "llvm.x86.sse2.subus.b";
+            intrinsic = type.sign ? "llvm.x86.sse2.psubs.b" : "llvm.x86.sse2.psubus.b";
          if(type.width == 16)
-            intrinsic = type.sign ? "llvm.x86.sse2.subs.w" : "llvm.x86.sse2.subus.w";
+            intrinsic = type.sign ? "llvm.x86.sse2.psubs.w" : "llvm.x86.sse2.psubus.w";
       }
 #endif
    
@@ -490,11 +490,124 @@ lp_build_sub(struct lp_build_context *bld,
 }
 
 
+/**
+ * Build shuffle vectors that match PUNPCKLxx and PUNPCKHxx instructions.
+ */
+static LLVMValueRef 
+lp_build_unpack_shuffle(unsigned n, unsigned lo_hi)
+{
+   LLVMValueRef elems[LP_MAX_VECTOR_LENGTH];
+   unsigned i, j;
+
+   assert(n <= LP_MAX_VECTOR_LENGTH);
+   assert(lo_hi < 2);
+
+   for(i = 0, j = lo_hi*n/2; i < n; i += 2, ++j) {
+      elems[i + 0] = LLVMConstInt(LLVMInt32Type(), 0 + j, 0);
+      elems[i + 1] = LLVMConstInt(LLVMInt32Type(), n + j, 0);
+   }
+
+   return LLVMConstVector(elems, n);
+}
+
+
+static LLVMValueRef 
+lp_build_const_vec(LLVMTypeRef type, unsigned n, long long c)
+{
+   LLVMValueRef elems[LP_MAX_VECTOR_LENGTH];
+   unsigned i;
+
+   assert(n <= LP_MAX_VECTOR_LENGTH);
+
+   for(i = 0; i < n; ++i)
+      elems[i] = LLVMConstInt(type, c, 0);
+
+   return LLVMConstVector(elems, n);
+}
+
+
+/**
+ * Normalized 8bit multiplication.
+ *
+ * - alpha plus one
+ *
+ *     makes the following approximation to the division (Sree)
+ *    
+ *       a*b/255 ~= (a*(b + 1)) >> 256
+ *    
+ *     which is the fastest method that satisfies the following OpenGL criteria
+ *    
+ *       0*0 = 0 and 255*255 = 255
+ *
+ * - geometric series
+ *
+ *     takes the geometric series approximation to the division
+ *
+ *       t/255 = (t >> 8) + (t >> 16) + (t >> 24) ..
+ *
+ *     in this case just the first two terms to fit in 16bit arithmetic
+ *
+ *       t/255 ~= (t + (t >> 8)) >> 8
+ *
+ *     note that just by itself it doesn't satisfies the OpenGL criteria, as
+ *     255*255 = 254, so the special case b = 255 must be accounted or roundoff
+ *     must be used
+ *
+ * - geometric series plus rounding
+ *
+ *     when using a geometric series division instead of truncating the result
+ *     use roundoff in the approximation (Jim Blinn)
+ *
+ *       t/255 ~= (t + (t >> 8) + 0x80) >> 8
+ *
+ *     achieving the exact results
+ *
+ * @sa Alvy Ray Smith, Image Compositing Fundamentals, Tech Memo 4, Aug 15, 1995, 
+ *     ftp://ftp.alvyray.com/Acrobat/4_Comp.pdf
+ * @sa Michael Herf, The "double blend trick", May 2000, 
+ *     http://www.stereopsis.com/doubleblend.html
+ */
+static LLVMValueRef
+lp_build_mul_u8n(LLVMBuilderRef builder,
+                 LLVMValueRef a, LLVMValueRef b)
+{
+   static LLVMValueRef c01 = NULL;
+   static LLVMValueRef c08 = NULL;
+   static LLVMValueRef c80 = NULL;
+   LLVMValueRef ab;
+
+   if(!c01) c01 = lp_build_const_vec(LLVMInt16Type(), 8, 0x01);
+   if(!c08) c08 = lp_build_const_vec(LLVMInt16Type(), 8, 0x08);
+   if(!c80) c80 = lp_build_const_vec(LLVMInt16Type(), 8, 0x80);
+   
+#if 0
+   
+   /* a*b/255 ~= (a*(b + 1)) >> 256 */
+   b = LLVMBuildAdd(builder, b, c01, "");
+   ab = LLVMBuildMul(builder, a, b, "");
+
+#else
+   
+   /* t/255 ~= (t + (t >> 8) + 0x80) >> 8 */
+   ab = LLVMBuildMul(builder, a, b, "");
+   ab = LLVMBuildAdd(builder, ab, LLVMBuildLShr(builder, ab, c08, ""), "");
+   ab = LLVMBuildAdd(builder, ab, c80, "");
+
+#endif
+   
+   ab = LLVMBuildLShr(builder, ab, c08, "");
+
+   return ab;
+}
+
+
 LLVMValueRef
 lp_build_mul(struct lp_build_context *bld,
              LLVMValueRef a,
              LLVMValueRef b)
 {
+   const union lp_type type = bld->type;
+
    if(a == bld->zero)
       return bld->zero;
    if(a == bld->one)
@@ -506,6 +619,50 @@ lp_build_mul(struct lp_build_context *bld,
    if(a == bld->undef || b == bld->undef)
       return bld->undef;
 
+   if(!type.floating && !type.fixed && type.norm) {
+#if defined(PIPE_ARCH_X86) || defined(PIPE_ARCH_X86_64)
+      if(type.width == 8 && type.length == 16) {
+         LLVMTypeRef i16x8 = LLVMVectorType(LLVMInt16Type(), 8);
+         LLVMTypeRef i8x16 = LLVMVectorType(LLVMInt8Type(), 16);
+         static LLVMValueRef ml = NULL;
+         static LLVMValueRef mh = NULL;
+         LLVMValueRef al, ah, bl, bh;
+         LLVMValueRef abl, abh;
+         LLVMValueRef ab;
+         
+         if(!ml) ml = lp_build_unpack_shuffle(16, 0);
+         if(!mh) mh = lp_build_unpack_shuffle(16, 1);
+
+         /*  PUNPCKLBW, PUNPCKHBW */
+         al = LLVMBuildShuffleVector(bld->builder, a, bld->zero, ml, "");
+         bl = LLVMBuildShuffleVector(bld->builder, b, bld->zero, ml, "");
+         ah = LLVMBuildShuffleVector(bld->builder, a, bld->zero, mh, "");
+         bh = LLVMBuildShuffleVector(bld->builder, b, bld->zero, mh, "");
+
+         /* NOP */
+         al = LLVMBuildBitCast(bld->builder, al, i16x8, "");
+         bl = LLVMBuildBitCast(bld->builder, bl, i16x8, "");
+         ah = LLVMBuildBitCast(bld->builder, ah, i16x8, "");
+         bh = LLVMBuildBitCast(bld->builder, bh, i16x8, "");
+
+         /* PMULLW, PSRLW, PADDW */
+         abl = lp_build_mul_u8n(bld->builder, al, bl);
+         abh = lp_build_mul_u8n(bld->builder, ah, bh);
+
+         /* PACKUSWB */
+         ab = lp_build_intrinsic_binary(bld->builder, "llvm.x86.sse2.packuswb.128" , abl, abh);
+
+         /* NOP */
+         ab = LLVMBuildBitCast(bld->builder, ab, i8x16, "");
+         
+         return ab;
+      }
+#endif
+
+      /* FIXME */
+      assert(0);
+   }
+
    if(LLVMIsConstant(a) && LLVMIsConstant(b))
       return LLVMConstMul(a, b);
 
index 5f46bb5f36f4f225c7731fbb457d74ddfba777ff..1bd1846d3849e45774639ede0a9fb9374c548e09 100644 (file)
@@ -39,6 +39,7 @@
 
 #include <stdlib.h>
 #include <stdio.h>
+#include <float.h>
 
 #include <llvm-c/Core.h>
 #include <llvm-c/Analysis.h>
 unsigned verbose = 0;
 
 
-typedef void (*blend_test_ptr_t)(const float *src, const float *dst, const float *const_, float *res);
+typedef void (*blend_test_ptr_t)(const void *src, const void *dst, const void *con, void *res);
 
 
 static LLVMValueRef
 add_blend_test(LLVMModuleRef module,
-               const struct pipe_blend_state *blend)
+               const struct pipe_blend_state *blend,
+               union lp_type type)
 {
-   union lp_type type;
-
+   LLVMTypeRef vec_type;
    LLVMTypeRef args[4];
    LLVMValueRef func;
    LLVMValueRef src_ptr;
@@ -77,20 +78,12 @@ add_blend_test(LLVMModuleRef module,
    LLVMBuilderRef builder;
    LLVMValueRef src;
    LLVMValueRef dst;
-   LLVMValueRef const_;
+   LLVMValueRef con;
    LLVMValueRef res;
 
-   type.value = 0;
-   type.floating = TRUE;
-   type.sign = TRUE;
-   type.norm = TRUE;
-   type.width = 32;
-   type.length = 4;
-
-   args[0] = LLVMPointerType(LLVMVectorType(LLVMFloatType(), 4), 0);
-   args[1] = LLVMPointerType(LLVMVectorType(LLVMFloatType(), 4), 0);
-   args[2] = LLVMPointerType(LLVMVectorType(LLVMFloatType(), 4), 0);
-   args[3] = LLVMPointerType(LLVMVectorType(LLVMFloatType(), 4), 0);
+   vec_type = lp_build_vec_type(type);
+
+   args[3] = args[2] = args[1] = args[0] = LLVMPointerType(vec_type, 0);
    func = LLVMAddFunction(module, "test", LLVMFunctionType(LLVMVoidType(), args, 4, 0));
    LLVMSetFunctionCallConv(func, LLVMCCallConv);
    src_ptr = LLVMGetParam(func, 0);
@@ -104,9 +97,9 @@ add_blend_test(LLVMModuleRef module,
 
    src = LLVMBuildLoad(builder, src_ptr, "src");
    dst = LLVMBuildLoad(builder, dst_ptr, "dst");
-   const_ = LLVMBuildLoad(builder, const_ptr, "const");
+   con = LLVMBuildLoad(builder, const_ptr, "const");
 
-   res = lp_build_blend(builder, blend, type, src, dst, const_, 3);
+   res = lp_build_blend(builder, blend, type, src, dst, con, 3);
 
    LLVMSetValueName(res, "res");
 
@@ -119,13 +112,10 @@ add_blend_test(LLVMModuleRef module,
 }
 
 
-static void
-random_color(float *color)
+static float
+random_float(void)
 {
-    color[0] = (float)((double)random()/(double)RAND_MAX);
-    color[1] = (float)((double)random()/(double)RAND_MAX);
-    color[2] = (float)((double)random()/(double)RAND_MAX);
-    color[3] = (float)((double)random()/(double)RAND_MAX);
+    return (float)((double)random()/(double)RAND_MAX);
 }
 
 
@@ -148,7 +138,7 @@ compute_blend_ref_term(unsigned rgb_factor,
                        const float *factor,
                        const float *src, 
                        const float *dst, 
-                       const float *const_
+                       const float *con, 
                        float *term)
 {
    float temp;
@@ -186,14 +176,14 @@ compute_blend_ref_term(unsigned rgb_factor,
       term[2] = factor[2] * temp; /* B */
       break;
    case PIPE_BLENDFACTOR_CONST_COLOR:
-      term[0] = factor[0] * const_[0]; /* R */
-      term[1] = factor[1] * const_[1]; /* G */
-      term[2] = factor[2] * const_[2]; /* B */
+      term[0] = factor[0] * con[0]; /* R */
+      term[1] = factor[1] * con[1]; /* G */
+      term[2] = factor[2] * con[2]; /* B */
       break;
    case PIPE_BLENDFACTOR_CONST_ALPHA:
-      term[0] = factor[0] * const_[3]; /* R */
-      term[1] = factor[1] * const_[3]; /* G */
-      term[2] = factor[2] * const_[3]; /* B */
+      term[0] = factor[0] * con[3]; /* R */
+      term[1] = factor[1] * con[3]; /* G */
+      term[2] = factor[2] * con[3]; /* B */
       break;
    case PIPE_BLENDFACTOR_SRC1_COLOR:
       assert(0); /* to do */
@@ -227,14 +217,14 @@ compute_blend_ref_term(unsigned rgb_factor,
       term[2] = factor[2] * (1.0f - dst[2]); /* B */
       break;
    case PIPE_BLENDFACTOR_INV_CONST_COLOR:
-      term[0] = factor[0] * (1.0f - const_[0]); /* R */
-      term[1] = factor[1] * (1.0f - const_[1]); /* G */
-      term[2] = factor[2] * (1.0f - const_[2]); /* B */
+      term[0] = factor[0] * (1.0f - con[0]); /* R */
+      term[1] = factor[1] * (1.0f - con[1]); /* G */
+      term[2] = factor[2] * (1.0f - con[2]); /* B */
       break;
    case PIPE_BLENDFACTOR_INV_CONST_ALPHA:
-      term[0] = factor[0] * (1.0f - const_[3]); /* R */
-      term[1] = factor[1] * (1.0f - const_[3]); /* G */
-      term[2] = factor[2] * (1.0f - const_[3]); /* B */
+      term[0] = factor[0] * (1.0f - con[3]); /* R */
+      term[1] = factor[1] * (1.0f - con[3]); /* G */
+      term[2] = factor[2] * (1.0f - con[3]); /* B */
       break;
    case PIPE_BLENDFACTOR_INV_SRC1_COLOR:
       assert(0); /* to do */
@@ -266,7 +256,7 @@ compute_blend_ref_term(unsigned rgb_factor,
       break;
    case PIPE_BLENDFACTOR_CONST_COLOR:
    case PIPE_BLENDFACTOR_CONST_ALPHA:
-      term[3] = factor[3] * const_[3]; /* A */
+      term[3] = factor[3] * con[3]; /* A */
       break;
    case PIPE_BLENDFACTOR_ZERO:
       term[3] = 0.0f; /* A */
@@ -281,7 +271,7 @@ compute_blend_ref_term(unsigned rgb_factor,
       break;
    case PIPE_BLENDFACTOR_INV_CONST_COLOR:
    case PIPE_BLENDFACTOR_INV_CONST_ALPHA:
-      term[3] = factor[3] * (1.0f - const_[3]);
+      term[3] = factor[3] * (1.0f - con[3]);
       break;
    default:
       assert(0);
@@ -293,14 +283,14 @@ static void
 compute_blend_ref(const struct pipe_blend_state *blend,
                   const float *src, 
                   const float *dst, 
-                  const float *const_
+                  const float *con, 
                   float *res)
 {
    float src_term[4];
    float dst_term[4];
 
-   compute_blend_ref_term(blend->rgb_src_factor, blend->alpha_src_factor, src, src, dst, const_, src_term);
-   compute_blend_ref_term(blend->rgb_dst_factor, blend->alpha_dst_factor, dst, src, dst, const_, dst_term);
+   compute_blend_ref_term(blend->rgb_src_factor, blend->alpha_src_factor, src, src, dst, con, src_term);
+   compute_blend_ref_term(blend->rgb_dst_factor, blend->alpha_dst_factor, dst, src, dst, con, dst_term);
 
    /*
     * Combine RGB terms
@@ -361,7 +351,8 @@ compute_blend_ref(const struct pipe_blend_state *blend,
 
 
 static boolean
-test_one(const struct pipe_blend_state *blend)
+test_one(const struct pipe_blend_state *blend,
+         union lp_type type)
 {
    LLVMModuleRef module = NULL;
    LLVMValueRef func = NULL;
@@ -371,11 +362,11 @@ test_one(const struct pipe_blend_state *blend)
    char *error = NULL;
    blend_test_ptr_t blend_test_ptr;
    boolean success;
-   unsigned i, j;
+   unsigned i, j, k;
 
    module = LLVMModuleCreateWithName("test");
 
-   func = add_blend_test(module, blend);
+   func = add_blend_test(module, blend, type);
 
    if(LLVMVerifyModule(module, LLVMPrintMessageAction, &error)) {
       LLVMDumpModule(module);
@@ -412,28 +403,97 @@ test_one(const struct pipe_blend_state *blend)
 
    success = TRUE;
    for(i = 0; i < 10; ++i) { 
-      float src[4];
-      float dst[4];
-      float const_[4];
-      float ref[4];
-      float res[4];
+      if(type.floating && type.width == 32) {
+         float src[LP_MAX_VECTOR_LENGTH];
+         float dst[LP_MAX_VECTOR_LENGTH];
+         float con[LP_MAX_VECTOR_LENGTH];
+         float ref[LP_MAX_VECTOR_LENGTH];
+         float res[LP_MAX_VECTOR_LENGTH];
+
+         for(j = 0; j < type.length; ++j) {
+            src[j] = random_float();
+            dst[j] = random_float();
+            con[j] = random_float();
+         }
+
+         for(j = 0; j < type.length; j += 4)
+            compute_blend_ref(blend, src + j, dst + j, con + j, ref + j);
+
+         blend_test_ptr(src, dst, con, res);
+
+         for(j = 0; j < type.length; ++j)
+            if(fabs(res[j] - ref[j]) > FLT_EPSILON)
+               success = FALSE;
+
+         if (!success) {
+            fprintf(stderr, "FAILED\n");
+            fprintf(stderr, "  Result:   ");
+            for(j = 0; j < type.length; ++j)
+               fprintf(stderr, " %f", res[j]);
+            fprintf(stderr, "\n");
+            fprintf(stderr, "  Expected: ");
+            for(j = 0; j < type.length; ++j)
+               fprintf(stderr, " %f", ref[j]);
+            fprintf(stderr, "\n");
+         }
+      }
+      else if(!type.floating && !type.fixed && !type.sign && type.norm && type.width == 8) {
+         uint8_t src[LP_MAX_VECTOR_LENGTH];
+         uint8_t dst[LP_MAX_VECTOR_LENGTH];
+         uint8_t con[LP_MAX_VECTOR_LENGTH];
+         uint8_t ref[LP_MAX_VECTOR_LENGTH];
+         uint8_t res[LP_MAX_VECTOR_LENGTH];
+
+         for(j = 0; j < type.length; ++j) {
+            src[j] = random() & 0xff;
+            dst[j] = random() & 0xff;
+            con[j] = random() & 0xff;
+         }
+
+         for(j = 0; j < type.length; j += 4) {
+            float srcf[4];
+            float dstf[4];
+            float conf[4];
+            float reff[4];
 
-      random_color(src);
-      random_color(dst);
-      random_color(const_);
+            for(k = 0; k < 4; ++k) {
+               srcf[k] = (1.0f/255.0f)*src[j + k];
+               dstf[k] = (1.0f/255.0f)*dst[j + k];
+               conf[k] = (1.0f/255.0f)*con[j + k];
+            }
 
-      compute_blend_ref(blend, src, dst, const_, ref);
+            compute_blend_ref(blend, srcf, dstf, conf, reff);
 
-      blend_test_ptr(src, dst, const_, res);
+            for(k = 0; k < 4; ++k)
+               ref[j + k] = (uint8_t)(reff[k]*255.0f + 0.5f);
+         }
 
-      for(j = 0; j < 4; ++j)
-         if(res[j] != ref[j])
-            success = FALSE;
+         blend_test_ptr(src, dst, con, res);
+
+         for(j = 0; j < type.length; ++j) {
+            int delta = (int)res[j] - (int)ref[j];
+            if (delta < 0)
+               delta = -delta;
+            if(delta > 1)
+               success = FALSE;
+         }
+
+         if (!success) {
+            fprintf(stderr, "FAILED\n");
+            fprintf(stderr, "  Result:   ");
+            for(j = 0; j < type.length; ++j)
+               fprintf(stderr, " %3u", res[j]);
+            fprintf(stderr, "\n");
+            fprintf(stderr, "  Expected: ");
+            for(j = 0; j < type.length; ++j)
+               fprintf(stderr, " %3u", ref[j]);
+            fprintf(stderr, "\n");
+         }
+      }
+      else
+         assert(0);
 
       if (!success) {
-         fprintf(stderr, "FAILED\n");
-         fprintf(stderr, "  Result: %f %f %f %f\n", res[0], res[1], res[2], res[3]);
-         fprintf(stderr, "          %f %f %f %f\n", ref[0], ref[1], ref[2], ref[3]);
          LLVMDumpModule(module);
          LLVMWriteBitcodeToFile(module, "blend.bc");
          fprintf(stderr, "blend.bc written\n");
@@ -497,8 +557,16 @@ blend_funcs[] = {
 };
 
 
+const union lp_type blend_types[] = {
+   /* float, fixed,  sign,  norm, width, len */
+   {{  TRUE, FALSE,  TRUE,  TRUE,    32,   4 }}, /* f32 x 4 */
+   {{ FALSE, FALSE, FALSE,  TRUE,     8,  16 }}, /* u8n x 16 */
+};
+
+
 const unsigned num_funcs = sizeof(blend_funcs)/sizeof(blend_funcs[0]);
 const unsigned num_factors = sizeof(blend_factors)/sizeof(blend_factors[0]);
+const unsigned num_types = sizeof(blend_types)/sizeof(blend_types[0]);
 
 
 static boolean 
@@ -511,6 +579,7 @@ test_all(void)
    const struct value_name_pair *alpha_src_factor;
    const struct value_name_pair *alpha_dst_factor;
    struct pipe_blend_state blend;
+   const union lp_type *type;
    bool success = TRUE;
 
    for(rgb_func = blend_funcs; rgb_func < &blend_funcs[num_funcs]; ++rgb_func) {
@@ -519,33 +588,35 @@ test_all(void)
             for(rgb_dst_factor = blend_factors; rgb_dst_factor <= rgb_src_factor; ++rgb_dst_factor) {
                for(alpha_src_factor = blend_factors; alpha_src_factor < &blend_factors[num_factors]; ++alpha_src_factor) {
                   for(alpha_dst_factor = blend_factors; alpha_dst_factor <= alpha_src_factor; ++alpha_dst_factor) {
-
-                     if(rgb_dst_factor->value == PIPE_BLENDFACTOR_SRC_ALPHA_SATURATE ||
-                        alpha_dst_factor->value == PIPE_BLENDFACTOR_SRC_ALPHA_SATURATE)
-                        continue;
-
-                     if(verbose >= 1)
-                        fprintf(stderr, 
-                                "%s=%s %s=%s %s=%s %s=%s %s=%s %s=%s ...\n",
-                                "rgb_func",         rgb_func->name,
-                                "rgb_src_factor",   rgb_src_factor->name,
-                                "rgb_dst_factor",   rgb_dst_factor->name,
-                                "alpha_func",       alpha_func->name,
-                                "alpha_src_factor", alpha_src_factor->name,
-                                "alpha_dst_factor", alpha_dst_factor->name);
-
-                     memset(&blend, 0, sizeof blend);
-                     blend.blend_enable      = 1;
-                     blend.rgb_func          = rgb_func->value;
-                     blend.rgb_src_factor    = rgb_src_factor->value;
-                     blend.rgb_dst_factor    = rgb_dst_factor->value;
-                     blend.alpha_func        = alpha_func->value;
-                     blend.alpha_src_factor  = alpha_src_factor->value;
-                     blend.alpha_dst_factor  = alpha_dst_factor->value;
-
-                     if(!test_one(&blend))
-                       success = FALSE;
-
+                     for(type = blend_types; type < &blend_types[num_types]; ++type) {
+
+                        if(rgb_dst_factor->value == PIPE_BLENDFACTOR_SRC_ALPHA_SATURATE ||
+                           alpha_dst_factor->value == PIPE_BLENDFACTOR_SRC_ALPHA_SATURATE)
+                           continue;
+
+                        if(verbose >= 1)
+                           fprintf(stderr, 
+                                   "%s=%s %s=%s %s=%s %s=%s %s=%s %s=%s ...\n",
+                                   "rgb_func",         rgb_func->name,
+                                   "rgb_src_factor",   rgb_src_factor->name,
+                                   "rgb_dst_factor",   rgb_dst_factor->name,
+                                   "alpha_func",       alpha_func->name,
+                                   "alpha_src_factor", alpha_src_factor->name,
+                                   "alpha_dst_factor", alpha_dst_factor->name);
+
+                        memset(&blend, 0, sizeof blend);
+                        blend.blend_enable      = 1;
+                        blend.rgb_func          = rgb_func->value;
+                        blend.rgb_src_factor    = rgb_src_factor->value;
+                        blend.rgb_dst_factor    = rgb_dst_factor->value;
+                        blend.alpha_func        = alpha_func->value;
+                        blend.alpha_src_factor  = alpha_src_factor->value;
+                        blend.alpha_dst_factor  = alpha_dst_factor->value;
+
+                        if(!test_one(&blend, *type))
+                          success = FALSE;
+
+                     }
                   }
                }
             }
@@ -567,6 +638,7 @@ test_some(unsigned long n)
    const struct value_name_pair *alpha_src_factor;
    const struct value_name_pair *alpha_dst_factor;
    struct pipe_blend_state blend;
+   const union lp_type *type;
    unsigned long i;
    bool success = TRUE;
 
@@ -584,28 +656,31 @@ test_some(unsigned long n)
          alpha_dst_factor = &blend_factors[random() % num_factors];
       } while(alpha_dst_factor->value == PIPE_BLENDFACTOR_SRC_ALPHA_SATURATE);
 
-      if(verbose >= 1)
-         fprintf(stderr, 
-                 "%s=%s %s=%s %s=%s %s=%s %s=%s %s=%s ...\n",
-                 "rgb_func",         rgb_func->name,
-                 "rgb_src_factor",   rgb_src_factor->name,
-                 "rgb_dst_factor",   rgb_dst_factor->name,
-                 "alpha_func",       alpha_func->name,
-                 "alpha_src_factor", alpha_src_factor->name,
-                 "alpha_dst_factor", alpha_dst_factor->name);
-
-      memset(&blend, 0, sizeof blend);
-      blend.blend_enable      = 1;
-      blend.rgb_func          = rgb_func->value;
-      blend.rgb_src_factor    = rgb_src_factor->value;
-      blend.rgb_dst_factor    = rgb_dst_factor->value;
-      blend.alpha_func        = alpha_func->value;
-      blend.alpha_src_factor  = alpha_src_factor->value;
-      blend.alpha_dst_factor  = alpha_dst_factor->value;
-
-      if(!test_one(&blend))
-        success = FALSE;
+      for(type = blend_types; type < &blend_types[num_types]; ++type) {
+
+         if(verbose >= 1)
+            fprintf(stderr, 
+                    "%s=%s %s=%s %s=%s %s=%s %s=%s %s=%s ...\n",
+                    "rgb_func",         rgb_func->name,
+                    "rgb_src_factor",   rgb_src_factor->name,
+                    "rgb_dst_factor",   rgb_dst_factor->name,
+                    "alpha_func",       alpha_func->name,
+                    "alpha_src_factor", alpha_src_factor->name,
+                    "alpha_dst_factor", alpha_dst_factor->name);
+
+         memset(&blend, 0, sizeof blend);
+         blend.blend_enable      = 1;
+         blend.rgb_func          = rgb_func->value;
+         blend.rgb_src_factor    = rgb_src_factor->value;
+         blend.rgb_dst_factor    = rgb_dst_factor->value;
+         blend.alpha_func        = alpha_func->value;
+         blend.alpha_src_factor  = alpha_src_factor->value;
+         blend.alpha_dst_factor  = alpha_dst_factor->value;
+
+         if(!test_one(&blend, *type))
+           success = FALSE;
 
+      }
    }
 
    return success;