Home | History | Annotate | Download | only in llvmpipe
      1 /**************************************************************************
      2  *
      3  * Copyright 2009 VMware, Inc.
      4  * All Rights Reserved.
      5  *
      6  * Permission is hereby granted, free of charge, to any person obtaining a
      7  * copy of this software and associated documentation files (the
      8  * "Software"), to deal in the Software without restriction, including
      9  * without limitation the rights to use, copy, modify, merge, publish,
     10  * distribute, sub license, and/or sell copies of the Software, and to
     11  * permit persons to whom the Software is furnished to do so, subject to
     12  * the following conditions:
     13  *
     14  * The above copyright notice and this permission notice (including the
     15  * next paragraph) shall be included in all copies or substantial portions
     16  * of the Software.
     17  *
     18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
     19  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     20  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
     21  * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
     22  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
     23  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
     24  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     25  *
     26  **************************************************************************/
     27 
     28 
     29 /**
     30  * @file
     31  * Unit tests for blend LLVM IR generation
     32  *
     33  * @author Jose Fonseca <jfonseca (at) vmware.com>
     34  *
     35  * Blend computation code derived from code written by
     36  * @author Brian Paul <brian (at) vmware.com>
     37  */
     38 
     39 #include "util/u_memory.h"
     40 
     41 #include "gallivm/lp_bld_init.h"
     42 #include "gallivm/lp_bld_type.h"
     43 #include "gallivm/lp_bld_debug.h"
     44 #include "lp_bld_blend.h"
     45 #include "lp_test.h"
     46 
     47 
     48 typedef void (*blend_test_ptr_t)(const void *src, const void *src1,
     49                                  const void *dst, const void *con, void *res);
     50 
     51 
     52 void
     53 write_tsv_header(FILE *fp)
     54 {
     55    fprintf(fp,
     56            "result\t"
     57            "cycles_per_channel\t"
     58            "type\t"
     59            "sep_func\t"
     60            "sep_src_factor\t"
     61            "sep_dst_factor\t"
     62            "rgb_func\t"
     63            "rgb_src_factor\t"
     64            "rgb_dst_factor\t"
     65            "alpha_func\t"
     66            "alpha_src_factor\t"
     67            "alpha_dst_factor\n");
     68 
     69    fflush(fp);
     70 }
     71 
     72 
     73 static void
     74 write_tsv_row(FILE *fp,
     75               const struct pipe_blend_state *blend,
     76               struct lp_type type,
     77               double cycles,
     78               boolean success)
     79 {
     80    fprintf(fp, "%s\t", success ? "pass" : "fail");
     81 
     82    fprintf(fp, "%.1f\t", cycles / type.length);
     83 
     84    fprintf(fp, "%s%u%sx%u\t",
     85            type.floating ? "f" : (type.fixed ? "h" : (type.sign ? "s" : "u")),
     86            type.width,
     87            type.norm ? "n" : "",
     88            type.length);
     89 
     90    fprintf(fp,
     91            "%s\t%s\t%s\t",
     92            blend->rt[0].rgb_func != blend->rt[0].alpha_func ? "true" : "false",
     93            blend->rt[0].rgb_src_factor != blend->rt[0].alpha_src_factor ? "true" : "false",
     94            blend->rt[0].rgb_dst_factor != blend->rt[0].alpha_dst_factor ? "true" : "false");
     95 
     96    fprintf(fp,
     97            "%s\t%s\t%s\t%s\t%s\t%s\n",
     98            util_dump_blend_func(blend->rt[0].rgb_func, TRUE),
     99            util_dump_blend_factor(blend->rt[0].rgb_src_factor, TRUE),
    100            util_dump_blend_factor(blend->rt[0].rgb_dst_factor, TRUE),
    101            util_dump_blend_func(blend->rt[0].alpha_func, TRUE),
    102            util_dump_blend_factor(blend->rt[0].alpha_src_factor, TRUE),
    103            util_dump_blend_factor(blend->rt[0].alpha_dst_factor, TRUE));
    104 
    105    fflush(fp);
    106 }
    107 
    108 
    109 static void
    110 dump_blend_type(FILE *fp,
    111                 const struct pipe_blend_state *blend,
    112                 struct lp_type type)
    113 {
    114    fprintf(fp, " type=%s%u%sx%u",
    115            type.floating ? "f" : (type.fixed ? "h" : (type.sign ? "s" : "u")),
    116            type.width,
    117            type.norm ? "n" : "",
    118            type.length);
    119 
    120    fprintf(fp,
    121            " %s=%s %s=%s %s=%s %s=%s %s=%s %s=%s",
    122            "rgb_func",         util_dump_blend_func(blend->rt[0].rgb_func, TRUE),
    123            "rgb_src_factor",   util_dump_blend_factor(blend->rt[0].rgb_src_factor, TRUE),
    124            "rgb_dst_factor",   util_dump_blend_factor(blend->rt[0].rgb_dst_factor, TRUE),
    125            "alpha_func",       util_dump_blend_func(blend->rt[0].alpha_func, TRUE),
    126            "alpha_src_factor", util_dump_blend_factor(blend->rt[0].alpha_src_factor, TRUE),
    127            "alpha_dst_factor", util_dump_blend_factor(blend->rt[0].alpha_dst_factor, TRUE));
    128 
    129    fprintf(fp, " ...\n");
    130    fflush(fp);
    131 }
    132 
    133 
    134 static LLVMValueRef
    135 add_blend_test(struct gallivm_state *gallivm,
    136                const struct pipe_blend_state *blend,
    137                struct lp_type type)
    138 {
    139    LLVMModuleRef module = gallivm->module;
    140    LLVMContextRef context = gallivm->context;
    141    LLVMTypeRef vec_type;
    142    LLVMTypeRef args[5];
    143    LLVMValueRef func;
    144    LLVMValueRef src_ptr;
    145    LLVMValueRef src1_ptr;
    146    LLVMValueRef dst_ptr;
    147    LLVMValueRef const_ptr;
    148    LLVMValueRef res_ptr;
    149    LLVMBasicBlockRef block;
    150    LLVMBuilderRef builder;
    151    const enum pipe_format format = PIPE_FORMAT_R8G8B8A8_UNORM;
    152    const unsigned rt = 0;
    153    const unsigned char swizzle[4] = { 0, 1, 2, 3 };
    154    LLVMValueRef src;
    155    LLVMValueRef src1;
    156    LLVMValueRef dst;
    157    LLVMValueRef con;
    158    LLVMValueRef res;
    159 
    160    vec_type = lp_build_vec_type(gallivm, type);
    161 
    162    args[4] = args[3] = args[2] = args[1] = args[0] = LLVMPointerType(vec_type, 0);
    163    func = LLVMAddFunction(module, "test", LLVMFunctionType(LLVMVoidTypeInContext(context), args, 5, 0));
    164    LLVMSetFunctionCallConv(func, LLVMCCallConv);
    165    src_ptr = LLVMGetParam(func, 0);
    166    src1_ptr = LLVMGetParam(func, 1);
    167    dst_ptr = LLVMGetParam(func, 2);
    168    const_ptr = LLVMGetParam(func, 3);
    169    res_ptr = LLVMGetParam(func, 4);
    170 
    171    block = LLVMAppendBasicBlockInContext(context, func, "entry");
    172    builder = gallivm->builder;
    173    LLVMPositionBuilderAtEnd(builder, block);
    174 
    175    src = LLVMBuildLoad(builder, src_ptr, "src");
    176    src1 = LLVMBuildLoad(builder, src1_ptr, "src1");
    177    dst = LLVMBuildLoad(builder, dst_ptr, "dst");
    178    con = LLVMBuildLoad(builder, const_ptr, "const");
    179 
    180    res = lp_build_blend_aos(gallivm, blend, format, type, rt, src, NULL,
    181                             src1, NULL, dst, NULL, con, NULL, swizzle, 4);
    182 
    183    lp_build_name(res, "res");
    184 
    185    LLVMBuildStore(builder, res, res_ptr);
    186 
    187    LLVMBuildRetVoid(builder);
    188 
    189    gallivm_verify_function(gallivm, func);
    190 
    191    return func;
    192 }
    193 
    194 
    195 static void
    196 compute_blend_ref_term(unsigned rgb_factor,
    197                        unsigned alpha_factor,
    198                        const double *factor,
    199                        const double *src,
    200                        const double *src1,
    201                        const double *dst,
    202                        const double *con,
    203                        double *term)
    204 {
    205    double temp;
    206 
    207    switch (rgb_factor) {
    208    case PIPE_BLENDFACTOR_ONE:
    209       term[0] = factor[0]; /* R */
    210       term[1] = factor[1]; /* G */
    211       term[2] = factor[2]; /* B */
    212       break;
    213    case PIPE_BLENDFACTOR_SRC_COLOR:
    214       term[0] = factor[0] * src[0]; /* R */
    215       term[1] = factor[1] * src[1]; /* G */
    216       term[2] = factor[2] * src[2]; /* B */
    217       break;
    218    case PIPE_BLENDFACTOR_SRC_ALPHA:
    219       term[0] = factor[0] * src[3]; /* R */
    220       term[1] = factor[1] * src[3]; /* G */
    221       term[2] = factor[2] * src[3]; /* B */
    222       break;
    223    case PIPE_BLENDFACTOR_DST_COLOR:
    224       term[0] = factor[0] * dst[0]; /* R */
    225       term[1] = factor[1] * dst[1]; /* G */
    226       term[2] = factor[2] * dst[2]; /* B */
    227       break;
    228    case PIPE_BLENDFACTOR_DST_ALPHA:
    229       term[0] = factor[0] * dst[3]; /* R */
    230       term[1] = factor[1] * dst[3]; /* G */
    231       term[2] = factor[2] * dst[3]; /* B */
    232       break;
    233    case PIPE_BLENDFACTOR_SRC_ALPHA_SATURATE:
    234       temp = MIN2(src[3], 1.0f - dst[3]);
    235       term[0] = factor[0] * temp; /* R */
    236       term[1] = factor[1] * temp; /* G */
    237       term[2] = factor[2] * temp; /* B */
    238       break;
    239    case PIPE_BLENDFACTOR_CONST_COLOR:
    240       term[0] = factor[0] * con[0]; /* R */
    241       term[1] = factor[1] * con[1]; /* G */
    242       term[2] = factor[2] * con[2]; /* B */
    243       break;
    244    case PIPE_BLENDFACTOR_CONST_ALPHA:
    245       term[0] = factor[0] * con[3]; /* R */
    246       term[1] = factor[1] * con[3]; /* G */
    247       term[2] = factor[2] * con[3]; /* B */
    248       break;
    249    case PIPE_BLENDFACTOR_SRC1_COLOR:
    250       term[0] = factor[0] * src1[0]; /* R */
    251       term[1] = factor[1] * src1[1]; /* G */
    252       term[2] = factor[2] * src1[2]; /* B */
    253       break;
    254    case PIPE_BLENDFACTOR_SRC1_ALPHA:
    255       term[0] = factor[0] * src1[3]; /* R */
    256       term[1] = factor[1] * src1[3]; /* G */
    257       term[2] = factor[2] * src1[3]; /* B */
    258       break;
    259    case PIPE_BLENDFACTOR_ZERO:
    260       term[0] = 0.0f; /* R */
    261       term[1] = 0.0f; /* G */
    262       term[2] = 0.0f; /* B */
    263       break;
    264    case PIPE_BLENDFACTOR_INV_SRC_COLOR:
    265       term[0] = factor[0] * (1.0f - src[0]); /* R */
    266       term[1] = factor[1] * (1.0f - src[1]); /* G */
    267       term[2] = factor[2] * (1.0f - src[2]); /* B */
    268       break;
    269    case PIPE_BLENDFACTOR_INV_SRC_ALPHA:
    270       term[0] = factor[0] * (1.0f - src[3]); /* R */
    271       term[1] = factor[1] * (1.0f - src[3]); /* G */
    272       term[2] = factor[2] * (1.0f - src[3]); /* B */
    273       break;
    274    case PIPE_BLENDFACTOR_INV_DST_ALPHA:
    275       term[0] = factor[0] * (1.0f - dst[3]); /* R */
    276       term[1] = factor[1] * (1.0f - dst[3]); /* G */
    277       term[2] = factor[2] * (1.0f - dst[3]); /* B */
    278       break;
    279    case PIPE_BLENDFACTOR_INV_DST_COLOR:
    280       term[0] = factor[0] * (1.0f - dst[0]); /* R */
    281       term[1] = factor[1] * (1.0f - dst[1]); /* G */
    282       term[2] = factor[2] * (1.0f - dst[2]); /* B */
    283       break;
    284    case PIPE_BLENDFACTOR_INV_CONST_COLOR:
    285       term[0] = factor[0] * (1.0f - con[0]); /* R */
    286       term[1] = factor[1] * (1.0f - con[1]); /* G */
    287       term[2] = factor[2] * (1.0f - con[2]); /* B */
    288       break;
    289    case PIPE_BLENDFACTOR_INV_CONST_ALPHA:
    290       term[0] = factor[0] * (1.0f - con[3]); /* R */
    291       term[1] = factor[1] * (1.0f - con[3]); /* G */
    292       term[2] = factor[2] * (1.0f - con[3]); /* B */
    293       break;
    294    case PIPE_BLENDFACTOR_INV_SRC1_COLOR:
    295       term[0] = factor[0] * (1.0f - src1[0]); /* R */
    296       term[1] = factor[1] * (1.0f - src1[1]); /* G */
    297       term[2] = factor[2] * (1.0f - src1[2]); /* B */
    298       break;
    299    case PIPE_BLENDFACTOR_INV_SRC1_ALPHA:
    300       term[0] = factor[0] * (1.0f - src1[3]); /* R */
    301       term[1] = factor[1] * (1.0f - src1[3]); /* G */
    302       term[2] = factor[2] * (1.0f - src1[3]); /* B */
    303       break;
    304    default:
    305       assert(0);
    306    }
    307 
    308    /*
    309     * Compute src/first term A
    310     */
    311    switch (alpha_factor) {
    312    case PIPE_BLENDFACTOR_ONE:
    313       term[3] = factor[3]; /* A */
    314       break;
    315    case PIPE_BLENDFACTOR_SRC_COLOR:
    316    case PIPE_BLENDFACTOR_SRC_ALPHA:
    317       term[3] = factor[3] * src[3]; /* A */
    318       break;
    319    case PIPE_BLENDFACTOR_DST_COLOR:
    320    case PIPE_BLENDFACTOR_DST_ALPHA:
    321       term[3] = factor[3] * dst[3]; /* A */
    322       break;
    323    case PIPE_BLENDFACTOR_SRC_ALPHA_SATURATE:
    324       term[3] = src[3]; /* A */
    325       break;
    326    case PIPE_BLENDFACTOR_CONST_COLOR:
    327    case PIPE_BLENDFACTOR_CONST_ALPHA:
    328       term[3] = factor[3] * con[3]; /* A */
    329       break;
    330    case PIPE_BLENDFACTOR_SRC1_COLOR:
    331    case PIPE_BLENDFACTOR_SRC1_ALPHA:
    332       term[3] = factor[3] * src1[3]; /* A */
    333       break;
    334    case PIPE_BLENDFACTOR_ZERO:
    335       term[3] = 0.0f; /* A */
    336       break;
    337    case PIPE_BLENDFACTOR_INV_SRC_COLOR:
    338    case PIPE_BLENDFACTOR_INV_SRC_ALPHA:
    339       term[3] = factor[3] * (1.0f - src[3]); /* A */
    340       break;
    341    case PIPE_BLENDFACTOR_INV_DST_COLOR:
    342    case PIPE_BLENDFACTOR_INV_DST_ALPHA:
    343       term[3] = factor[3] * (1.0f - dst[3]); /* A */
    344       break;
    345    case PIPE_BLENDFACTOR_INV_CONST_COLOR:
    346    case PIPE_BLENDFACTOR_INV_CONST_ALPHA:
    347       term[3] = factor[3] * (1.0f - con[3]);
    348       break;
    349    case PIPE_BLENDFACTOR_INV_SRC1_COLOR:
    350    case PIPE_BLENDFACTOR_INV_SRC1_ALPHA:
    351       term[3] = factor[3] * (1.0f - src1[3]); /* A */
    352       break;
    353    default:
    354       assert(0);
    355    }
    356 }
    357 
    358 
    359 static void
    360 compute_blend_ref(const struct pipe_blend_state *blend,
    361                   const double *src,
    362                   const double *src1,
    363                   const double *dst,
    364                   const double *con,
    365                   double *res)
    366 {
    367    double src_term[4];
    368    double dst_term[4];
    369 
    370    compute_blend_ref_term(blend->rt[0].rgb_src_factor, blend->rt[0].alpha_src_factor,
    371                           src, src, src1, dst, con, src_term);
    372    compute_blend_ref_term(blend->rt[0].rgb_dst_factor, blend->rt[0].alpha_dst_factor,
    373                           dst, src, src1, dst, con, dst_term);
    374 
    375    /*
    376     * Combine RGB terms
    377     */
    378    switch (blend->rt[0].rgb_func) {
    379    case PIPE_BLEND_ADD:
    380       res[0] = src_term[0] + dst_term[0]; /* R */
    381       res[1] = src_term[1] + dst_term[1]; /* G */
    382       res[2] = src_term[2] + dst_term[2]; /* B */
    383       break;
    384    case PIPE_BLEND_SUBTRACT:
    385       res[0] = src_term[0] - dst_term[0]; /* R */
    386       res[1] = src_term[1] - dst_term[1]; /* G */
    387       res[2] = src_term[2] - dst_term[2]; /* B */
    388       break;
    389    case PIPE_BLEND_REVERSE_SUBTRACT:
    390       res[0] = dst_term[0] - src_term[0]; /* R */
    391       res[1] = dst_term[1] - src_term[1]; /* G */
    392       res[2] = dst_term[2] - src_term[2]; /* B */
    393       break;
    394    case PIPE_BLEND_MIN:
    395       res[0] = MIN2(src_term[0], dst_term[0]); /* R */
    396       res[1] = MIN2(src_term[1], dst_term[1]); /* G */
    397       res[2] = MIN2(src_term[2], dst_term[2]); /* B */
    398       break;
    399    case PIPE_BLEND_MAX:
    400       res[0] = MAX2(src_term[0], dst_term[0]); /* R */
    401       res[1] = MAX2(src_term[1], dst_term[1]); /* G */
    402       res[2] = MAX2(src_term[2], dst_term[2]); /* B */
    403       break;
    404    default:
    405       assert(0);
    406    }
    407 
    408    /*
    409     * Combine A terms
    410     */
    411    switch (blend->rt[0].alpha_func) {
    412    case PIPE_BLEND_ADD:
    413       res[3] = src_term[3] + dst_term[3]; /* A */
    414       break;
    415    case PIPE_BLEND_SUBTRACT:
    416       res[3] = src_term[3] - dst_term[3]; /* A */
    417       break;
    418    case PIPE_BLEND_REVERSE_SUBTRACT:
    419       res[3] = dst_term[3] - src_term[3]; /* A */
    420       break;
    421    case PIPE_BLEND_MIN:
    422       res[3] = MIN2(src_term[3], dst_term[3]); /* A */
    423       break;
    424    case PIPE_BLEND_MAX:
    425       res[3] = MAX2(src_term[3], dst_term[3]); /* A */
    426       break;
    427    default:
    428       assert(0);
    429    }
    430 }
    431 
    432 
    433 PIPE_ALIGN_STACK
    434 static boolean
    435 test_one(unsigned verbose,
    436          FILE *fp,
    437          const struct pipe_blend_state *blend,
    438          struct lp_type type)
    439 {
    440    LLVMContextRef context;
    441    struct gallivm_state *gallivm;
    442    LLVMValueRef func = NULL;
    443    blend_test_ptr_t blend_test_ptr;
    444    boolean success;
    445    const unsigned n = LP_TEST_NUM_SAMPLES;
    446    int64_t cycles[LP_TEST_NUM_SAMPLES];
    447    double cycles_avg = 0.0;
    448    unsigned i, j;
    449    const unsigned stride = lp_type_width(type)/8;
    450 
    451    if(verbose >= 1)
    452       dump_blend_type(stdout, blend, type);
    453 
    454    context = LLVMContextCreate();
    455    gallivm = gallivm_create("test_module", context);
    456 
    457    func = add_blend_test(gallivm, blend, type);
    458 
    459    gallivm_compile_module(gallivm);
    460 
    461    blend_test_ptr = (blend_test_ptr_t)gallivm_jit_function(gallivm, func);
    462 
    463    gallivm_free_ir(gallivm);
    464 
    465    success = TRUE;
    466 
    467    {
    468       uint8_t *src, *src1, *dst, *con, *res, *ref;
    469       src = align_malloc(stride, stride);
    470       src1 = align_malloc(stride, stride);
    471       dst = align_malloc(stride, stride);
    472       con = align_malloc(stride, stride);
    473       res = align_malloc(stride, stride);
    474       ref = align_malloc(stride, stride);
    475 
    476       for(i = 0; i < n && success; ++i) {
    477          int64_t start_counter = 0;
    478          int64_t end_counter = 0;
    479 
    480          random_vec(type, src);
    481          random_vec(type, src1);
    482          random_vec(type, dst);
    483          random_vec(type, con);
    484 
    485          {
    486             double fsrc[LP_MAX_VECTOR_LENGTH];
    487             double fsrc1[LP_MAX_VECTOR_LENGTH];
    488             double fdst[LP_MAX_VECTOR_LENGTH];
    489             double fcon[LP_MAX_VECTOR_LENGTH];
    490             double fref[LP_MAX_VECTOR_LENGTH];
    491 
    492             read_vec(type, src, fsrc);
    493             read_vec(type, src1, fsrc1);
    494             read_vec(type, dst, fdst);
    495             read_vec(type, con, fcon);
    496 
    497             for(j = 0; j < type.length; j += 4)
    498                compute_blend_ref(blend, fsrc + j, fsrc1 + j, fdst + j, fcon + j, fref + j);
    499 
    500             write_vec(type, ref, fref);
    501          }
    502 
    503          start_counter = rdtsc();
    504          blend_test_ptr(src, src1, dst, con, res);
    505          end_counter = rdtsc();
    506 
    507          cycles[i] = end_counter - start_counter;
    508 
    509          if(!compare_vec(type, res, ref)) {
    510             success = FALSE;
    511 
    512             if(verbose < 1)
    513                dump_blend_type(stderr, blend, type);
    514             fprintf(stderr, "MISMATCH\n");
    515 
    516             fprintf(stderr, "  Src: ");
    517             dump_vec(stderr, type, src);
    518             fprintf(stderr, "\n");
    519 
    520             fprintf(stderr, "  Src1: ");
    521             dump_vec(stderr, type, src1);
    522             fprintf(stderr, "\n");
    523 
    524             fprintf(stderr, "  Dst: ");
    525             dump_vec(stderr, type, dst);
    526             fprintf(stderr, "\n");
    527 
    528             fprintf(stderr, "  Con: ");
    529             dump_vec(stderr, type, con);
    530             fprintf(stderr, "\n");
    531 
    532             fprintf(stderr, "  Res: ");
    533             dump_vec(stderr, type, res);
    534             fprintf(stderr, "\n");
    535 
    536             fprintf(stderr, "  Ref: ");
    537             dump_vec(stderr, type, ref);
    538             fprintf(stderr, "\n");
    539          }
    540       }
    541       align_free(src);
    542       align_free(src1);
    543       align_free(dst);
    544       align_free(con);
    545       align_free(res);
    546       align_free(ref);
    547    }
    548 
    549    /*
    550     * Unfortunately the output of cycle counter is not very reliable as it comes
    551     * -- sometimes we get outliers (due IRQs perhaps?) which are
    552     * better removed to avoid random or biased data.
    553     */
    554    {
    555       double sum = 0.0, sum2 = 0.0;
    556       double avg, std;
    557       unsigned m;
    558 
    559       for(i = 0; i < n; ++i) {
    560          sum += cycles[i];
    561          sum2 += cycles[i]*cycles[i];
    562       }
    563 
    564       avg = sum/n;
    565       std = sqrtf((sum2 - n*avg*avg)/n);
    566 
    567       m = 0;
    568       sum = 0.0;
    569       for(i = 0; i < n; ++i) {
    570          if(fabs(cycles[i] - avg) <= 4.0*std) {
    571             sum += cycles[i];
    572             ++m;
    573          }
    574       }
    575 
    576       cycles_avg = sum/m;
    577 
    578    }
    579 
    580    if(fp)
    581       write_tsv_row(fp, blend, type, cycles_avg, success);
    582 
    583    gallivm_destroy(gallivm);
    584    LLVMContextDispose(context);
    585 
    586    return success;
    587 }
    588 
    589 
    590 const unsigned
    591 blend_factors[] = {
    592    PIPE_BLENDFACTOR_ZERO,
    593    PIPE_BLENDFACTOR_ONE,
    594    PIPE_BLENDFACTOR_SRC_COLOR,
    595    PIPE_BLENDFACTOR_SRC_ALPHA,
    596    PIPE_BLENDFACTOR_DST_COLOR,
    597    PIPE_BLENDFACTOR_DST_ALPHA,
    598    PIPE_BLENDFACTOR_CONST_COLOR,
    599    PIPE_BLENDFACTOR_CONST_ALPHA,
    600    PIPE_BLENDFACTOR_SRC1_COLOR,
    601    PIPE_BLENDFACTOR_SRC1_ALPHA,
    602    PIPE_BLENDFACTOR_SRC_ALPHA_SATURATE,
    603    PIPE_BLENDFACTOR_INV_SRC_COLOR,
    604    PIPE_BLENDFACTOR_INV_SRC_ALPHA,
    605    PIPE_BLENDFACTOR_INV_DST_COLOR,
    606    PIPE_BLENDFACTOR_INV_DST_ALPHA,
    607    PIPE_BLENDFACTOR_INV_CONST_COLOR,
    608    PIPE_BLENDFACTOR_INV_CONST_ALPHA,
    609    PIPE_BLENDFACTOR_INV_SRC1_COLOR,
    610    PIPE_BLENDFACTOR_INV_SRC1_ALPHA,
    611 };
    612 
    613 
    614 const unsigned
    615 blend_funcs[] = {
    616    PIPE_BLEND_ADD,
    617    PIPE_BLEND_SUBTRACT,
    618    PIPE_BLEND_REVERSE_SUBTRACT,
    619    PIPE_BLEND_MIN,
    620    PIPE_BLEND_MAX
    621 };
    622 
    623 
    624 const struct lp_type blend_types[] = {
    625    /* float, fixed,  sign,  norm, width, len */
    626    {   TRUE, FALSE,  TRUE, FALSE,    32,   4 }, /* f32 x 4 */
    627    {  FALSE, FALSE, FALSE,  TRUE,     8,  16 }, /* u8n x 16 */
    628 };
    629 
    630 
    631 const unsigned num_funcs = ARRAY_SIZE(blend_funcs);
    632 const unsigned num_factors = ARRAY_SIZE(blend_factors);
    633 const unsigned num_types = ARRAY_SIZE(blend_types);
    634 
    635 
    636 boolean
    637 test_all(unsigned verbose, FILE *fp)
    638 {
    639    const unsigned *rgb_func;
    640    const unsigned *rgb_src_factor;
    641    const unsigned *rgb_dst_factor;
    642    const unsigned *alpha_func;
    643    const unsigned *alpha_src_factor;
    644    const unsigned *alpha_dst_factor;
    645    struct pipe_blend_state blend;
    646    const struct lp_type *type;
    647    boolean success = TRUE;
    648 
    649    for(rgb_func = blend_funcs; rgb_func < &blend_funcs[num_funcs]; ++rgb_func) {
    650       for(alpha_func = blend_funcs; alpha_func < &blend_funcs[num_funcs]; ++alpha_func) {
    651          for(rgb_src_factor = blend_factors; rgb_src_factor < &blend_factors[num_factors]; ++rgb_src_factor) {
    652             for(rgb_dst_factor = blend_factors; rgb_dst_factor <= rgb_src_factor; ++rgb_dst_factor) {
    653                for(alpha_src_factor = blend_factors; alpha_src_factor < &blend_factors[num_factors]; ++alpha_src_factor) {
    654                   for(alpha_dst_factor = blend_factors; alpha_dst_factor <= alpha_src_factor; ++alpha_dst_factor) {
    655                      for(type = blend_types; type < &blend_types[num_types]; ++type) {
    656 
    657                         if(*rgb_dst_factor == PIPE_BLENDFACTOR_SRC_ALPHA_SATURATE ||
    658                            *alpha_dst_factor == PIPE_BLENDFACTOR_SRC_ALPHA_SATURATE)
    659                            continue;
    660 
    661                         memset(&blend, 0, sizeof blend);
    662                         blend.rt[0].blend_enable      = 1;
    663                         blend.rt[0].rgb_func          = *rgb_func;
    664                         blend.rt[0].rgb_src_factor    = *rgb_src_factor;
    665                         blend.rt[0].rgb_dst_factor    = *rgb_dst_factor;
    666                         blend.rt[0].alpha_func        = *alpha_func;
    667                         blend.rt[0].alpha_src_factor  = *alpha_src_factor;
    668                         blend.rt[0].alpha_dst_factor  = *alpha_dst_factor;
    669                         blend.rt[0].colormask         = PIPE_MASK_RGBA;
    670 
    671                         if(!test_one(verbose, fp, &blend, *type))
    672                           success = FALSE;
    673 
    674                      }
    675                   }
    676                }
    677             }
    678          }
    679       }
    680    }
    681 
    682    return success;
    683 }
    684 
    685 
    686 boolean
    687 test_some(unsigned verbose, FILE *fp,
    688           unsigned long n)
    689 {
    690    const unsigned *rgb_func;
    691    const unsigned *rgb_src_factor;
    692    const unsigned *rgb_dst_factor;
    693    const unsigned *alpha_func;
    694    const unsigned *alpha_src_factor;
    695    const unsigned *alpha_dst_factor;
    696    struct pipe_blend_state blend;
    697    const struct lp_type *type;
    698    unsigned long i;
    699    boolean success = TRUE;
    700 
    701    for(i = 0; i < n; ++i) {
    702       rgb_func = &blend_funcs[rand() % num_funcs];
    703       alpha_func = &blend_funcs[rand() % num_funcs];
    704       rgb_src_factor = &blend_factors[rand() % num_factors];
    705       alpha_src_factor = &blend_factors[rand() % num_factors];
    706 
    707       do {
    708          rgb_dst_factor = &blend_factors[rand() % num_factors];
    709       } while(*rgb_dst_factor == PIPE_BLENDFACTOR_SRC_ALPHA_SATURATE);
    710 
    711       do {
    712          alpha_dst_factor = &blend_factors[rand() % num_factors];
    713       } while(*alpha_dst_factor == PIPE_BLENDFACTOR_SRC_ALPHA_SATURATE);
    714 
    715       type = &blend_types[rand() % num_types];
    716 
    717       memset(&blend, 0, sizeof blend);
    718       blend.rt[0].blend_enable      = 1;
    719       blend.rt[0].rgb_func          = *rgb_func;
    720       blend.rt[0].rgb_src_factor    = *rgb_src_factor;
    721       blend.rt[0].rgb_dst_factor    = *rgb_dst_factor;
    722       blend.rt[0].alpha_func        = *alpha_func;
    723       blend.rt[0].alpha_src_factor  = *alpha_src_factor;
    724       blend.rt[0].alpha_dst_factor  = *alpha_dst_factor;
    725       blend.rt[0].colormask         = PIPE_MASK_RGBA;
    726 
    727       if(!test_one(verbose, fp, &blend, *type))
    728         success = FALSE;
    729    }
    730 
    731    return success;
    732 }
    733 
    734 
    735 boolean
    736 test_single(unsigned verbose, FILE *fp)
    737 {
    738    printf("no test_single()");
    739    return TRUE;
    740 }
    741