Merge branch 'arb_half_float_vertex'
[mesa.git] / src / gallium / drivers / llvmpipe / lp_test_blend.c
index 1bd1846d3849e45774639ede0a9fb9374c548e09..7b65bab43a472de9e60113f2ec1afc4b0569bf5a 100644 (file)
  */
 
 
-#include <stdlib.h>
-#include <stdio.h>
-#include <float.h>
+#include "lp_bld_type.h"
+#include "lp_bld_blend.h"
+#include "lp_bld_debug.h"
+#include "lp_test.h"
 
-#include <llvm-c/Core.h>
-#include <llvm-c/Analysis.h>
-#include <llvm-c/ExecutionEngine.h>
-#include <llvm-c/Target.h>
-#include <llvm-c/BitWriter.h>
-#include <llvm-c/Transforms/Scalar.h>
 
-#include "pipe/p_state.h"
-#include "util/u_format.h"
-#include "util/u_math.h"
+enum vector_mode
+{
+   AoS = 0,
+   SoA = 1
+};
 
-#include "lp_bld.h"
-#include "lp_bld_arit.h"
 
+typedef void (*blend_test_ptr_t)(const void *src, const void *dst, const void *con, void *res);
 
-unsigned verbose = 0;
 
+void
+write_tsv_header(FILE *fp)
+{
+   fprintf(fp,
+           "result\t"
+           "cycles_per_channel\t"
+           "mode\t"
+           "type\t"
+           "sep_func\t"
+           "sep_src_factor\t"
+           "sep_dst_factor\t"
+           "rgb_func\t"
+           "rgb_src_factor\t"
+           "rgb_dst_factor\t"
+           "alpha_func\t"
+           "alpha_src_factor\t"
+           "alpha_dst_factor\n");
+
+   fflush(fp);
+}
 
-typedef void (*blend_test_ptr_t)(const void *src, const void *dst, const void *con, void *res);
+
+static void
+write_tsv_row(FILE *fp,
+              const struct pipe_blend_state *blend,
+              enum vector_mode mode,
+              struct lp_type type,
+              double cycles,
+              boolean success)
+{
+   fprintf(fp, "%s\t", success ? "pass" : "fail");
+
+   if (mode == AoS) {
+      fprintf(fp, "%.1f\t", cycles / type.length);
+      fprintf(fp, "aos\t");
+   }
+
+   if (mode == SoA) {
+      fprintf(fp, "%.1f\t", cycles / (4 * type.length));
+      fprintf(fp, "soa\t");
+   }
+
+   fprintf(fp, "%s%u%sx%u\t",
+           type.floating ? "f" : (type.fixed ? "h" : (type.sign ? "s" : "u")),
+           type.width,
+           type.norm ? "n" : "",
+           type.length);
+
+   fprintf(fp,
+           "%s\t%s\t%s\t",
+           blend->rgb_func != blend->alpha_func ? "true" : "false",
+           blend->rgb_src_factor != blend->alpha_src_factor ? "true" : "false",
+           blend->rgb_dst_factor != blend->alpha_dst_factor ? "true" : "false");
+
+   fprintf(fp,
+           "%s\t%s\t%s\t%s\t%s\t%s\n",
+           debug_dump_blend_func(blend->rgb_func, TRUE),
+           debug_dump_blend_factor(blend->rgb_src_factor, TRUE),
+           debug_dump_blend_factor(blend->rgb_dst_factor, TRUE),
+           debug_dump_blend_func(blend->alpha_func, TRUE),
+           debug_dump_blend_factor(blend->alpha_src_factor, TRUE),
+           debug_dump_blend_factor(blend->alpha_dst_factor, TRUE));
+
+   fflush(fp);
+}
+
+
+static void
+dump_blend_type(FILE *fp,
+                const struct pipe_blend_state *blend,
+                enum vector_mode mode,
+                struct lp_type type)
+{
+   fprintf(fp, "%s", mode ? "soa" : "aos");
+
+   fprintf(fp, " type=%s%u%sx%u",
+           type.floating ? "f" : (type.fixed ? "h" : (type.sign ? "s" : "u")),
+           type.width,
+           type.norm ? "n" : "",
+           type.length);
+
+   fprintf(fp,
+           " %s=%s %s=%s %s=%s %s=%s %s=%s %s=%s",
+           "rgb_func",         debug_dump_blend_func(blend->rgb_func, TRUE),
+           "rgb_src_factor",   debug_dump_blend_factor(blend->rgb_src_factor, TRUE),
+           "rgb_dst_factor",   debug_dump_blend_factor(blend->rgb_dst_factor, TRUE),
+           "alpha_func",       debug_dump_blend_func(blend->alpha_func, TRUE),
+           "alpha_src_factor", debug_dump_blend_factor(blend->alpha_src_factor, TRUE),
+           "alpha_dst_factor", debug_dump_blend_factor(blend->alpha_dst_factor, TRUE));
+
+   fprintf(fp, " ...\n");
+   fflush(fp);
+}
 
 
 static LLVMValueRef
 add_blend_test(LLVMModuleRef module,
                const struct pipe_blend_state *blend,
-               union lp_type type)
+               enum vector_mode mode,
+               struct lp_type type)
 {
+   LLVMTypeRef ret_type;
    LLVMTypeRef vec_type;
    LLVMTypeRef args[4];
    LLVMValueRef func;
@@ -76,11 +164,8 @@ add_blend_test(LLVMModuleRef module,
    LLVMValueRef res_ptr;
    LLVMBasicBlockRef block;
    LLVMBuilderRef builder;
-   LLVMValueRef src;
-   LLVMValueRef dst;
-   LLVMValueRef con;
-   LLVMValueRef res;
 
+   ret_type = LLVMInt64Type();
    vec_type = lp_build_vec_type(type);
 
    args[3] = args[2] = args[1] = args[0] = LLVMPointerType(vec_type, 0);
@@ -95,27 +180,53 @@ add_blend_test(LLVMModuleRef module,
    builder = LLVMCreateBuilder();
    LLVMPositionBuilderAtEnd(builder, block);
 
-   src = LLVMBuildLoad(builder, src_ptr, "src");
-   dst = LLVMBuildLoad(builder, dst_ptr, "dst");
-   con = LLVMBuildLoad(builder, const_ptr, "const");
+   if (mode == AoS) {
+      LLVMValueRef src;
+      LLVMValueRef dst;
+      LLVMValueRef con;
+      LLVMValueRef res;
+
+      src = LLVMBuildLoad(builder, src_ptr, "src");
+      dst = LLVMBuildLoad(builder, dst_ptr, "dst");
+      con = LLVMBuildLoad(builder, const_ptr, "const");
 
-   res = lp_build_blend(builder, blend, type, src, dst, con, 3);
+      res = lp_build_blend_aos(builder, blend, type, src, dst, con, 3);
 
-   LLVMSetValueName(res, "res");
+      lp_build_name(res, "res");
 
-   LLVMBuildStore(builder, res, res_ptr);
+      LLVMBuildStore(builder, res, res_ptr);
+   }
 
-   LLVMBuildRetVoid(builder);
+   if (mode == SoA) {
+      LLVMValueRef src[4];
+      LLVMValueRef dst[4];
+      LLVMValueRef con[4];
+      LLVMValueRef res[4];
+      unsigned i;
+
+      for(i = 0; i < 4; ++i) {
+         LLVMValueRef index = LLVMConstInt(LLVMInt32Type(), i, 0);
+         src[i] = LLVMBuildLoad(builder, LLVMBuildGEP(builder, src_ptr, &index, 1, ""), "");
+         dst[i] = LLVMBuildLoad(builder, LLVMBuildGEP(builder, dst_ptr, &index, 1, ""), "");
+         con[i] = LLVMBuildLoad(builder, LLVMBuildGEP(builder, const_ptr, &index, 1, ""), "");
+         lp_build_name(src[i], "src.%c", "rgba"[i]);
+         lp_build_name(con[i], "con.%c", "rgba"[i]);
+         lp_build_name(dst[i], "dst.%c", "rgba"[i]);
+      }
 
-   LLVMDisposeBuilder(builder);
-   return func;
-}
+      lp_build_blend_soa(builder, blend, type, src, dst, con, res);
 
+      for(i = 0; i < 4; ++i) {
+         LLVMValueRef index = LLVMConstInt(LLVMInt32Type(), i, 0);
+         lp_build_name(res[i], "res.%c", "rgba"[i]);
+         LLVMBuildStore(builder, res[i], LLVMBuildGEP(builder, res_ptr, &index, 1, ""));
+      }
+   }
 
-static float
-random_float(void)
-{
-    return (float)((double)random()/(double)RAND_MAX);
+   LLVMBuildRetVoid(builder);;
+
+   LLVMDisposeBuilder(builder);
+   return func;
 }
 
 
@@ -135,13 +246,13 @@ do { \
 static void
 compute_blend_ref_term(unsigned rgb_factor,
                        unsigned alpha_factor,
-                       const float *factor,
-                       const float *src, 
-                       const float *dst, 
-                       const float *con, 
-                       float *term)
+                       const double *factor,
+                       const double *src,
+                       const double *dst,
+                       const double *con,
+                       double *term)
 {
-   float temp;
+   double temp;
 
    switch (rgb_factor) {
    case PIPE_BLENDFACTOR_ONE:
@@ -281,13 +392,13 @@ compute_blend_ref_term(unsigned rgb_factor,
 
 static void
 compute_blend_ref(const struct pipe_blend_state *blend,
-                  const float *src, 
-                  const float *dst, 
-                  const float *con, 
-                  float *res)
+                  const double *src,
+                  const double *dst,
+                  const double *con,
+                  double *res)
 {
-   float src_term[4];
-   float dst_term[4];
+   double src_term[4];
+   double dst_term[4];
 
    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);
@@ -350,9 +461,13 @@ compute_blend_ref(const struct pipe_blend_state *blend,
 }
 
 
+PIPE_ALIGN_STACK
 static boolean
-test_one(const struct pipe_blend_state *blend,
-         union lp_type type)
+test_one(unsigned verbose,
+         FILE *fp,
+         const struct pipe_blend_state *blend,
+         enum vector_mode mode,
+         struct lp_type type)
 {
    LLVMModuleRef module = NULL;
    LLVMValueRef func = NULL;
@@ -362,11 +477,17 @@ test_one(const struct pipe_blend_state *blend,
    char *error = NULL;
    blend_test_ptr_t blend_test_ptr;
    boolean success;
-   unsigned i, j, k;
+   const unsigned n = LP_TEST_NUM_SAMPLES;
+   int64_t cycles[LP_TEST_NUM_SAMPLES];
+   double cycles_avg = 0.0;
+   unsigned i, j;
+
+   if(verbose >= 1)
+      dump_blend_type(stdout, blend, mode, type);
 
    module = LLVMModuleCreateWithName("test");
 
-   func = add_blend_test(module, blend, type);
+   func = add_blend_test(module, blend, mode, type);
 
    if(LLVMVerifyModule(module, LLVMPrintMessageAction, &error)) {
       LLVMDumpModule(module);
@@ -376,6 +497,8 @@ test_one(const struct pipe_blend_state *blend,
 
    provider = LLVMCreateModuleProviderForExistingModule(module);
    if (LLVMCreateJITCompiler(&engine, provider, 1, &error)) {
+      if(verbose < 1)
+         dump_blend_type(stderr, blend, mode, type);
       fprintf(stderr, "%s\n", error);
       LLVMDisposeMessage(error);
       abort();
@@ -396,110 +519,202 @@ test_one(const struct pipe_blend_state *blend,
    (void)pass;
 #endif
 
+   if(verbose >= 2)
+      LLVMDumpModule(module);
+
    blend_test_ptr = (blend_test_ptr_t)LLVMGetPointerToGlobal(engine, func);
 
    if(verbose >= 2)
-      LLVMDumpModule(module);
+      lp_disassemble(blend_test_ptr);
 
    success = TRUE;
-   for(i = 0; i < 10; ++i) { 
-      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(i = 0; i < n && success; ++i) {
+      if(mode == AoS) {
+         PIPE_ALIGN_VAR(16) uint8_t src[LP_NATIVE_VECTOR_WIDTH/8];
+         PIPE_ALIGN_VAR(16) uint8_t dst[LP_NATIVE_VECTOR_WIDTH/8];
+         PIPE_ALIGN_VAR(16) uint8_t con[LP_NATIVE_VECTOR_WIDTH/8];
+         PIPE_ALIGN_VAR(16) uint8_t res[LP_NATIVE_VECTOR_WIDTH/8];
+         PIPE_ALIGN_VAR(16) uint8_t ref[LP_NATIVE_VECTOR_WIDTH/8];
+         int64_t start_counter = 0;
+         int64_t end_counter = 0;
+
+         random_vec(type, src);
+         random_vec(type, dst);
+         random_vec(type, con);
+
+         {
+            double fsrc[LP_MAX_VECTOR_LENGTH];
+            double fdst[LP_MAX_VECTOR_LENGTH];
+            double fcon[LP_MAX_VECTOR_LENGTH];
+            double fref[LP_MAX_VECTOR_LENGTH];
+
+            read_vec(type, src, fsrc);
+            read_vec(type, dst, fdst);
+            read_vec(type, con, fcon);
+
+            for(j = 0; j < type.length; j += 4)
+               compute_blend_ref(blend, fsrc + j, fdst + j, fcon + j, fref + j);
+
+            write_vec(type, ref, fref);
          }
 
-         for(j = 0; j < type.length; j += 4)
-            compute_blend_ref(blend, src + j, dst + j, con + j, ref + j);
-
+         start_counter = rdtsc();
          blend_test_ptr(src, dst, con, res);
+         end_counter = rdtsc();
+
+         cycles[i] = end_counter - start_counter;
+
+         if(!compare_vec(type, res, ref)) {
+            success = FALSE;
 
-         for(j = 0; j < type.length; ++j)
-            if(fabs(res[j] - ref[j]) > FLT_EPSILON)
-               success = FALSE;
+            if(verbose < 1)
+               dump_blend_type(stderr, blend, mode, type);
+            fprintf(stderr, "MISMATCH\n");
 
-         if (!success) {
-            fprintf(stderr, "FAILED\n");
-            fprintf(stderr, "  Result:   ");
-            for(j = 0; j < type.length; ++j)
-               fprintf(stderr, " %f", res[j]);
+            fprintf(stderr, "  Src: ");
+            dump_vec(stderr, type, src);
             fprintf(stderr, "\n");
-            fprintf(stderr, "  Expected: ");
-            for(j = 0; j < type.length; ++j)
-               fprintf(stderr, " %f", ref[j]);
+
+            fprintf(stderr, "  Dst: ");
+            dump_vec(stderr, type, dst);
+            fprintf(stderr, "\n");
+
+            fprintf(stderr, "  Con: ");
+            dump_vec(stderr, type, con);
+            fprintf(stderr, "\n");
+
+            fprintf(stderr, "  Res: ");
+            dump_vec(stderr, type, res);
+            fprintf(stderr, "\n");
+
+            fprintf(stderr, "  Ref: ");
+            dump_vec(stderr, type, ref);
             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];
+      if(mode == SoA) {
+         const unsigned stride = type.length*type.width/8;
+         PIPE_ALIGN_VAR(16) uint8_t src[4*LP_NATIVE_VECTOR_WIDTH/8];
+         PIPE_ALIGN_VAR(16) uint8_t dst[4*LP_NATIVE_VECTOR_WIDTH/8];
+         PIPE_ALIGN_VAR(16) uint8_t con[4*LP_NATIVE_VECTOR_WIDTH/8];
+         PIPE_ALIGN_VAR(16) uint8_t res[4*LP_NATIVE_VECTOR_WIDTH/8];
+         PIPE_ALIGN_VAR(16) uint8_t ref[4*LP_NATIVE_VECTOR_WIDTH/8];
+         int64_t start_counter = 0;
+         int64_t end_counter = 0;
+         boolean mismatch;
+
+         for(j = 0; j < 4; ++j) {
+            random_vec(type, src + j*stride);
+            random_vec(type, dst + j*stride);
+            random_vec(type, con + j*stride);
+         }
 
-            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];
-            }
+         {
+            double fsrc[4];
+            double fdst[4];
+            double fcon[4];
+            double fref[4];
+            unsigned k;
+
+            for(k = 0; k < type.length; ++k) {
+               for(j = 0; j < 4; ++j) {
+                  fsrc[j] = read_elem(type, src + j*stride, k);
+                  fdst[j] = read_elem(type, dst + j*stride, k);
+                  fcon[j] = read_elem(type, con + j*stride, k);
+               }
 
-            compute_blend_ref(blend, srcf, dstf, conf, reff);
+               compute_blend_ref(blend, fsrc, fdst, fcon, fref);
 
-            for(k = 0; k < 4; ++k)
-               ref[j + k] = (uint8_t)(reff[k]*255.0f + 0.5f);
+               for(j = 0; j < 4; ++j)
+                  write_elem(type, ref + j*stride, k, fref[j]);
+            }
          }
 
+         start_counter = rdtsc();
          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;
+         end_counter = rdtsc();
+
+         cycles[i] = end_counter - start_counter;
+
+         mismatch = FALSE;
+         for (j = 0; j < 4; ++j)
+            if(!compare_vec(type, res + j*stride, ref + j*stride))
+               mismatch = TRUE;
+
+         if (mismatch) {
+            success = FALSE;
+
+            if(verbose < 1)
+               dump_blend_type(stderr, blend, mode, type);
+            fprintf(stderr, "MISMATCH\n");
+            for(j = 0; j < 4; ++j) {
+               char channel = "RGBA"[j];
+               fprintf(stderr, "  Src%c: ", channel);
+               dump_vec(stderr, type, src + j*stride);
+               fprintf(stderr, "\n");
+
+               fprintf(stderr, "  Dst%c: ", channel);
+               dump_vec(stderr, type, dst + j*stride);
+               fprintf(stderr, "\n");
+
+               fprintf(stderr, "  Con%c: ", channel);
+               dump_vec(stderr, type, con + j*stride);
+               fprintf(stderr, "\n");
+
+               fprintf(stderr, "  Res%c: ", channel);
+               dump_vec(stderr, type, res + j*stride);
+               fprintf(stderr, "\n");
+
+               fprintf(stderr, "  Ref%c: ", channel);
+               dump_vec(stderr, type, ref + j*stride);
+               fprintf(stderr, "\n");
+            }
          }
+      }
+   }
 
-         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");
+   /*
+    * Unfortunately the output of cycle counter is not very reliable as it comes
+    * -- sometimes we get outliers (due IRQs perhaps?) which are
+    * better removed to avoid random or biased data.
+    */
+   {
+      double sum = 0.0, sum2 = 0.0;
+      double avg, std;
+      unsigned m;
+
+      for(i = 0; i < n; ++i) {
+         sum += cycles[i];
+         sum2 += cycles[i]*cycles[i];
+      }
+
+      avg = sum/n;
+      std = sqrtf((sum2 - n*avg*avg)/n);
+
+      m = 0;
+      sum = 0.0;
+      for(i = 0; i < n; ++i) {
+         if(fabs(cycles[i] - avg) <= 4.0*std) {
+            sum += cycles[i];
+            ++m;
          }
       }
-      else
-         assert(0);
 
-      if (!success) {
+      cycles_avg = sum/m;
+
+   }
+
+   if(fp)
+      write_tsv_row(fp, blend, mode, type, cycles_avg, success);
+
+   if (!success) {
+      if(verbose < 2)
          LLVMDumpModule(module);
-         LLVMWriteBitcodeToFile(module, "blend.bc");
-         fprintf(stderr, "blend.bc written\n");
-         abort();
-         break;
-      }
+      LLVMWriteBitcodeToFile(module, "blend.bc");
+      fprintf(stderr, "blend.bc written\n");
+      fprintf(stderr, "Invoke as \"llc -o - blend.bc\"\n");
+      abort();
    }
 
    LLVMFreeMachineCodeForFunction(engine, func);
@@ -512,55 +727,48 @@ test_one(const struct pipe_blend_state *blend,
 }
 
 
-struct value_name_pair
-{
-   unsigned value;
-   const char *name;
-};
-
-
-const struct value_name_pair
+const unsigned
 blend_factors[] = {
-   {PIPE_BLENDFACTOR_ZERO                , "zero"},
-   {PIPE_BLENDFACTOR_ONE                 , "one"},
-   {PIPE_BLENDFACTOR_SRC_COLOR           , "src_color"},
-   {PIPE_BLENDFACTOR_SRC_ALPHA           , "src_alpha"},
-   {PIPE_BLENDFACTOR_DST_COLOR           , "dst_color"},
-   {PIPE_BLENDFACTOR_DST_ALPHA           , "dst_alpha"},
-   {PIPE_BLENDFACTOR_CONST_COLOR         , "const_color"},
-   {PIPE_BLENDFACTOR_CONST_ALPHA         , "const_alpha"},
+   PIPE_BLENDFACTOR_ZERO,
+   PIPE_BLENDFACTOR_ONE,
+   PIPE_BLENDFACTOR_SRC_COLOR,
+   PIPE_BLENDFACTOR_SRC_ALPHA,
+   PIPE_BLENDFACTOR_DST_COLOR,
+   PIPE_BLENDFACTOR_DST_ALPHA,
+   PIPE_BLENDFACTOR_CONST_COLOR,
+   PIPE_BLENDFACTOR_CONST_ALPHA,
 #if 0
-   {PIPE_BLENDFACTOR_SRC1_COLOR          , "src1_color"},
-   {PIPE_BLENDFACTOR_SRC1_ALPHA          , "src1_alpha"},
+   PIPE_BLENDFACTOR_SRC1_COLOR,
+   PIPE_BLENDFACTOR_SRC1_ALPHA,
 #endif
-   {PIPE_BLENDFACTOR_SRC_ALPHA_SATURATE  , "src_alpha_saturate"},
-   {PIPE_BLENDFACTOR_INV_SRC_COLOR       , "inv_src_color"},
-   {PIPE_BLENDFACTOR_INV_SRC_ALPHA       , "inv_src_alpha"},
-   {PIPE_BLENDFACTOR_INV_DST_COLOR       , "inv_dst_color"},
-   {PIPE_BLENDFACTOR_INV_DST_ALPHA       , "inv_dst_alpha"},
-   {PIPE_BLENDFACTOR_INV_CONST_COLOR     , "inv_const_color"},
-   {PIPE_BLENDFACTOR_INV_CONST_ALPHA     , "inv_const_alpha"},
+   PIPE_BLENDFACTOR_SRC_ALPHA_SATURATE,
+   PIPE_BLENDFACTOR_INV_SRC_COLOR,
+   PIPE_BLENDFACTOR_INV_SRC_ALPHA,
+   PIPE_BLENDFACTOR_INV_DST_COLOR,
+   PIPE_BLENDFACTOR_INV_DST_ALPHA,
+   PIPE_BLENDFACTOR_INV_CONST_COLOR,
+   PIPE_BLENDFACTOR_INV_CONST_ALPHA,
 #if 0
-   {PIPE_BLENDFACTOR_INV_SRC1_COLOR      , "inv_src1_color"},
-   {PIPE_BLENDFACTOR_INV_SRC1_ALPHA      , "inv_src1_alpha"}
+   PIPE_BLENDFACTOR_INV_SRC1_COLOR,
+   PIPE_BLENDFACTOR_INV_SRC1_ALPHA,
 #endif
 };
 
 
-const struct value_name_pair
+const unsigned
 blend_funcs[] = {
-   {PIPE_BLEND_ADD               , "add"},
-   {PIPE_BLEND_SUBTRACT          , "sub"},
-   {PIPE_BLEND_REVERSE_SUBTRACT  , "rev_sub"},
-   {PIPE_BLEND_MIN               , "min"},
-   {PIPE_BLEND_MAX               , "max"}
+   PIPE_BLEND_ADD,
+   PIPE_BLEND_SUBTRACT,
+   PIPE_BLEND_REVERSE_SUBTRACT,
+   PIPE_BLEND_MIN,
+   PIPE_BLEND_MAX
 };
 
 
-const union lp_type blend_types[] = {
+const struct 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 */
+   {   TRUE, FALSE, FALSE,  TRUE,    32,   4 }, /* f32 x 4 */
+   {  FALSE, FALSE, FALSE,  TRUE,     8,  16 }, /* u8n x 16 */
 };
 
 
@@ -569,17 +777,18 @@ const unsigned num_factors = sizeof(blend_factors)/sizeof(blend_factors[0]);
 const unsigned num_types = sizeof(blend_types)/sizeof(blend_types[0]);
 
 
-static boolean 
-test_all(void)
+boolean
+test_all(unsigned verbose, FILE *fp)
 {
-   const struct value_name_pair *rgb_func;
-   const struct value_name_pair *rgb_src_factor;
-   const struct value_name_pair *rgb_dst_factor;
-   const struct value_name_pair *alpha_func;
-   const struct value_name_pair *alpha_src_factor;
-   const struct value_name_pair *alpha_dst_factor;
+   const unsigned *rgb_func;
+   const unsigned *rgb_src_factor;
+   const unsigned *rgb_dst_factor;
+   const unsigned *alpha_func;
+   const unsigned *alpha_src_factor;
+   const unsigned *alpha_dst_factor;
    struct pipe_blend_state blend;
-   const union lp_type *type;
+   enum vector_mode mode;
+   const struct lp_type *type;
    bool success = TRUE;
 
    for(rgb_func = blend_funcs; rgb_func < &blend_funcs[num_funcs]; ++rgb_func) {
@@ -588,34 +797,27 @@ 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) {
-                     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;
-
+                     for(mode = 0; mode < 2; ++mode) {
+                        for(type = blend_types; type < &blend_types[num_types]; ++type) {
+
+                           if(*rgb_dst_factor == PIPE_BLENDFACTOR_SRC_ALPHA_SATURATE ||
+                              *alpha_dst_factor == PIPE_BLENDFACTOR_SRC_ALPHA_SATURATE)
+                              continue;
+
+                           memset(&blend, 0, sizeof blend);
+                           blend.blend_enable      = 1;
+                           blend.rgb_func          = *rgb_func;
+                           blend.rgb_src_factor    = *rgb_src_factor;
+                           blend.rgb_dst_factor    = *rgb_dst_factor;
+                           blend.alpha_func        = *alpha_func;
+                           blend.alpha_src_factor  = *alpha_src_factor;
+                           blend.alpha_dst_factor  = *alpha_dst_factor;
+                           blend.colormask         = PIPE_MASK_RGBA;
+
+                           if(!test_one(verbose, fp, &blend, mode, *type))
+                             success = FALSE;
+
+                        }
                      }
                   }
                }
@@ -628,82 +830,52 @@ test_all(void)
 }
 
 
-static boolean 
-test_some(unsigned long n)
+boolean
+test_some(unsigned verbose, FILE *fp, unsigned long n)
 {
-   const struct value_name_pair *rgb_func;
-   const struct value_name_pair *rgb_src_factor;
-   const struct value_name_pair *rgb_dst_factor;
-   const struct value_name_pair *alpha_func;
-   const struct value_name_pair *alpha_src_factor;
-   const struct value_name_pair *alpha_dst_factor;
+   const unsigned *rgb_func;
+   const unsigned *rgb_src_factor;
+   const unsigned *rgb_dst_factor;
+   const unsigned *alpha_func;
+   const unsigned *alpha_src_factor;
+   const unsigned *alpha_dst_factor;
    struct pipe_blend_state blend;
-   const union lp_type *type;
+   enum vector_mode mode;
+   const struct lp_type *type;
    unsigned long i;
    bool success = TRUE;
 
    for(i = 0; i < n; ++i) {
-      rgb_func = &blend_funcs[random() % num_funcs];
-      alpha_func = &blend_funcs[random() % num_funcs];
-      rgb_src_factor = &blend_factors[random() % num_factors];
-      alpha_src_factor = &blend_factors[random() % num_factors];
+      rgb_func = &blend_funcs[rand() % num_funcs];
+      alpha_func = &blend_funcs[rand() % num_funcs];
+      rgb_src_factor = &blend_factors[rand() % num_factors];
+      alpha_src_factor = &blend_factors[rand() % num_factors];
       
       do {
-         rgb_dst_factor = &blend_factors[random() % num_factors];
-      } while(rgb_dst_factor->value == PIPE_BLENDFACTOR_SRC_ALPHA_SATURATE);
+         rgb_dst_factor = &blend_factors[rand() % num_factors];
+      } while(*rgb_dst_factor == PIPE_BLENDFACTOR_SRC_ALPHA_SATURATE);
 
       do {
-         alpha_dst_factor = &blend_factors[random() % num_factors];
-      } while(alpha_dst_factor->value == PIPE_BLENDFACTOR_SRC_ALPHA_SATURATE);
-
-      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;
+         alpha_dst_factor = &blend_factors[rand() % num_factors];
+      } while(*alpha_dst_factor == PIPE_BLENDFACTOR_SRC_ALPHA_SATURATE);
 
-      }
-   }
-
-   return success;
-}
+      mode = rand() & 1;
 
+      type = &blend_types[rand() % num_types];
 
-int main(int argc, char **argv)
-{
-   unsigned long n = 1000;
-   unsigned i;
-   boolean success;
+      memset(&blend, 0, sizeof blend);
+      blend.blend_enable      = 1;
+      blend.rgb_func          = *rgb_func;
+      blend.rgb_src_factor    = *rgb_src_factor;
+      blend.rgb_dst_factor    = *rgb_dst_factor;
+      blend.alpha_func        = *alpha_func;
+      blend.alpha_src_factor  = *alpha_src_factor;
+      blend.alpha_dst_factor  = *alpha_dst_factor;
+      blend.colormask         = PIPE_MASK_RGBA;
 
-   for(i = 1; i < argc; ++i) {
-      if(strcmp(argv[i], "-v") == 0)
-         ++verbose;
-      else
-         n = atoi(argv[i]);
+      if(!test_one(verbose, fp, &blend, mode, *type))
+        success = FALSE;
    }
-      
-   if(n)
-      success = test_some(n);
-   else
-      success = test_all();
 
-   return success ? 0 : 1;
+   return success;
 }