lp_test_blend.c revision 272dadbe4ebeaeb4f942c0f3c2fd140285b0457c
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@vmware.com>
34 *
35 * Blend computation code derived from code written by
36 * @author Brian Paul <brian@vmware.com>
37 */
38
39
40#include <stdlib.h>
41#include <stdio.h>
42
43#include <llvm-c/Core.h>
44#include <llvm-c/Analysis.h>
45#include <llvm-c/ExecutionEngine.h>
46#include <llvm-c/Target.h>
47#include <llvm-c/BitWriter.h>
48#include <llvm-c/Transforms/Scalar.h>
49
50#include "pipe/p_state.h"
51#include "util/u_format.h"
52#include "util/u_math.h"
53
54#include "lp_bld.h"
55#include "lp_bld_arit.h"
56
57
58unsigned verbose = 0;
59
60
61typedef void (*blend_test_ptr_t)(const float *src, const float *dst, const float *const_, float *res);
62
63
64static LLVMValueRef
65add_blend_test(LLVMModuleRef module,
66               const struct pipe_blend_state *blend)
67{
68   union lp_type type;
69
70   LLVMTypeRef args[4];
71   LLVMValueRef func;
72   LLVMValueRef src_ptr;
73   LLVMValueRef dst_ptr;
74   LLVMValueRef const_ptr;
75   LLVMValueRef res_ptr;
76   LLVMBasicBlockRef block;
77   LLVMBuilderRef builder;
78   LLVMValueRef src;
79   LLVMValueRef dst;
80   LLVMValueRef const_;
81   LLVMValueRef res;
82
83   type.value = 0;
84   type.kind = LP_TYPE_FLOAT;
85   type.sign = TRUE;
86   type.norm = TRUE;
87   type.width = 32;
88   type.length = 4;
89
90   args[0] = LLVMPointerType(LLVMVectorType(LLVMFloatType(), 4), 0);
91   args[1] = LLVMPointerType(LLVMVectorType(LLVMFloatType(), 4), 0);
92   args[2] = LLVMPointerType(LLVMVectorType(LLVMFloatType(), 4), 0);
93   args[3] = LLVMPointerType(LLVMVectorType(LLVMFloatType(), 4), 0);
94   func = LLVMAddFunction(module, "test", LLVMFunctionType(LLVMVoidType(), args, 4, 0));
95   LLVMSetFunctionCallConv(func, LLVMCCallConv);
96   src_ptr = LLVMGetParam(func, 0);
97   dst_ptr = LLVMGetParam(func, 1);
98   const_ptr = LLVMGetParam(func, 2);
99   res_ptr = LLVMGetParam(func, 3);
100
101   block = LLVMAppendBasicBlock(func, "entry");
102   builder = LLVMCreateBuilder();
103   LLVMPositionBuilderAtEnd(builder, block);
104
105   src = LLVMBuildLoad(builder, src_ptr, "src");
106   dst = LLVMBuildLoad(builder, dst_ptr, "dst");
107   const_ = LLVMBuildLoad(builder, const_ptr, "const");
108
109   res = lp_build_blend(builder, blend, type, src, dst, const_, 3);
110
111   LLVMSetValueName(res, "res");
112
113   LLVMBuildStore(builder, res, res_ptr);
114
115   LLVMBuildRetVoid(builder);
116
117   LLVMDisposeBuilder(builder);
118   return func;
119}
120
121
122static void
123random_color(float *color)
124{
125    color[0] = (float)((double)random()/(double)RAND_MAX);
126    color[1] = (float)((double)random()/(double)RAND_MAX);
127    color[2] = (float)((double)random()/(double)RAND_MAX);
128    color[3] = (float)((double)random()/(double)RAND_MAX);
129}
130
131
132/** Add and limit result to ceiling of 1.0 */
133#define ADD_SAT(R, A, B) \
134do { \
135   R = (A) + (B);  if (R > 1.0f) R = 1.0f; \
136} while (0)
137
138/** Subtract and limit result to floor of 0.0 */
139#define SUB_SAT(R, A, B) \
140do { \
141   R = (A) - (B);  if (R < 0.0f) R = 0.0f; \
142} while (0)
143
144
145static void
146compute_blend_ref_term(unsigned rgb_factor,
147                       unsigned alpha_factor,
148                       const float *factor,
149                       const float *src,
150                       const float *dst,
151                       const float *const_,
152                       float *term)
153{
154   float temp;
155
156   switch (rgb_factor) {
157   case PIPE_BLENDFACTOR_ONE:
158      term[0] = factor[0]; /* R */
159      term[1] = factor[1]; /* G */
160      term[2] = factor[2]; /* B */
161      break;
162   case PIPE_BLENDFACTOR_SRC_COLOR:
163      term[0] = factor[0] * src[0]; /* R */
164      term[1] = factor[1] * src[1]; /* G */
165      term[2] = factor[2] * src[2]; /* B */
166      break;
167   case PIPE_BLENDFACTOR_SRC_ALPHA:
168      term[0] = factor[0] * src[3]; /* R */
169      term[1] = factor[1] * src[3]; /* G */
170      term[2] = factor[2] * src[3]; /* B */
171      break;
172   case PIPE_BLENDFACTOR_DST_COLOR:
173      term[0] = factor[0] * dst[0]; /* R */
174      term[1] = factor[1] * dst[1]; /* G */
175      term[2] = factor[2] * dst[2]; /* B */
176      break;
177   case PIPE_BLENDFACTOR_DST_ALPHA:
178      term[0] = factor[0] * dst[3]; /* R */
179      term[1] = factor[1] * dst[3]; /* G */
180      term[2] = factor[2] * dst[3]; /* B */
181      break;
182   case PIPE_BLENDFACTOR_SRC_ALPHA_SATURATE:
183      temp = MIN2(src[3], 1.0f - dst[3]);
184      term[0] = factor[0] * temp; /* R */
185      term[1] = factor[1] * temp; /* G */
186      term[2] = factor[2] * temp; /* B */
187      break;
188   case PIPE_BLENDFACTOR_CONST_COLOR:
189      term[0] = factor[0] * const_[0]; /* R */
190      term[1] = factor[1] * const_[1]; /* G */
191      term[2] = factor[2] * const_[2]; /* B */
192      break;
193   case PIPE_BLENDFACTOR_CONST_ALPHA:
194      term[0] = factor[0] * const_[3]; /* R */
195      term[1] = factor[1] * const_[3]; /* G */
196      term[2] = factor[2] * const_[3]; /* B */
197      break;
198   case PIPE_BLENDFACTOR_SRC1_COLOR:
199      assert(0); /* to do */
200      break;
201   case PIPE_BLENDFACTOR_SRC1_ALPHA:
202      assert(0); /* to do */
203      break;
204   case PIPE_BLENDFACTOR_ZERO:
205      term[0] = 0.0f; /* R */
206      term[1] = 0.0f; /* G */
207      term[2] = 0.0f; /* B */
208      break;
209   case PIPE_BLENDFACTOR_INV_SRC_COLOR:
210      term[0] = factor[0] * (1.0f - src[0]); /* R */
211      term[1] = factor[1] * (1.0f - src[1]); /* G */
212      term[2] = factor[2] * (1.0f - src[2]); /* B */
213      break;
214   case PIPE_BLENDFACTOR_INV_SRC_ALPHA:
215      term[0] = factor[0] * (1.0f - src[3]); /* R */
216      term[1] = factor[1] * (1.0f - src[3]); /* G */
217      term[2] = factor[2] * (1.0f - src[3]); /* B */
218      break;
219   case PIPE_BLENDFACTOR_INV_DST_ALPHA:
220      term[0] = factor[0] * (1.0f - dst[3]); /* R */
221      term[1] = factor[1] * (1.0f - dst[3]); /* G */
222      term[2] = factor[2] * (1.0f - dst[3]); /* B */
223      break;
224   case PIPE_BLENDFACTOR_INV_DST_COLOR:
225      term[0] = factor[0] * (1.0f - dst[0]); /* R */
226      term[1] = factor[1] * (1.0f - dst[1]); /* G */
227      term[2] = factor[2] * (1.0f - dst[2]); /* B */
228      break;
229   case PIPE_BLENDFACTOR_INV_CONST_COLOR:
230      term[0] = factor[0] * (1.0f - const_[0]); /* R */
231      term[1] = factor[1] * (1.0f - const_[1]); /* G */
232      term[2] = factor[2] * (1.0f - const_[2]); /* B */
233      break;
234   case PIPE_BLENDFACTOR_INV_CONST_ALPHA:
235      term[0] = factor[0] * (1.0f - const_[3]); /* R */
236      term[1] = factor[1] * (1.0f - const_[3]); /* G */
237      term[2] = factor[2] * (1.0f - const_[3]); /* B */
238      break;
239   case PIPE_BLENDFACTOR_INV_SRC1_COLOR:
240      assert(0); /* to do */
241      break;
242   case PIPE_BLENDFACTOR_INV_SRC1_ALPHA:
243      assert(0); /* to do */
244      break;
245   default:
246      assert(0);
247   }
248
249   /*
250    * Compute src/first term A
251    */
252   switch (alpha_factor) {
253   case PIPE_BLENDFACTOR_ONE:
254      term[3] = factor[3]; /* A */
255      break;
256   case PIPE_BLENDFACTOR_SRC_COLOR:
257   case PIPE_BLENDFACTOR_SRC_ALPHA:
258      term[3] = factor[3] * src[3]; /* A */
259      break;
260   case PIPE_BLENDFACTOR_DST_COLOR:
261   case PIPE_BLENDFACTOR_DST_ALPHA:
262      term[3] = factor[3] * dst[3]; /* A */
263      break;
264   case PIPE_BLENDFACTOR_SRC_ALPHA_SATURATE:
265      term[3] = src[3]; /* A */
266      break;
267   case PIPE_BLENDFACTOR_CONST_COLOR:
268   case PIPE_BLENDFACTOR_CONST_ALPHA:
269      term[3] = factor[3] * const_[3]; /* A */
270      break;
271   case PIPE_BLENDFACTOR_ZERO:
272      term[3] = 0.0f; /* A */
273      break;
274   case PIPE_BLENDFACTOR_INV_SRC_COLOR:
275   case PIPE_BLENDFACTOR_INV_SRC_ALPHA:
276      term[3] = factor[3] * (1.0f - src[3]); /* A */
277      break;
278   case PIPE_BLENDFACTOR_INV_DST_COLOR:
279   case PIPE_BLENDFACTOR_INV_DST_ALPHA:
280      term[3] = factor[3] * (1.0f - dst[3]); /* A */
281      break;
282   case PIPE_BLENDFACTOR_INV_CONST_COLOR:
283   case PIPE_BLENDFACTOR_INV_CONST_ALPHA:
284      term[3] = factor[3] * (1.0f - const_[3]);
285      break;
286   default:
287      assert(0);
288   }
289}
290
291
292static void
293compute_blend_ref(const struct pipe_blend_state *blend,
294                  const float *src,
295                  const float *dst,
296                  const float *const_,
297                  float *res)
298{
299   float src_term[4];
300   float dst_term[4];
301
302   compute_blend_ref_term(blend->rgb_src_factor, blend->alpha_src_factor, src, src, dst, const_, src_term);
303   compute_blend_ref_term(blend->rgb_dst_factor, blend->alpha_dst_factor, dst, src, dst, const_, dst_term);
304
305   /*
306    * Combine RGB terms
307    */
308   switch (blend->rgb_func) {
309   case PIPE_BLEND_ADD:
310      ADD_SAT(res[0], src_term[0], dst_term[0]); /* R */
311      ADD_SAT(res[1], src_term[1], dst_term[1]); /* G */
312      ADD_SAT(res[2], src_term[2], dst_term[2]); /* B */
313      break;
314   case PIPE_BLEND_SUBTRACT:
315      SUB_SAT(res[0], src_term[0], dst_term[0]); /* R */
316      SUB_SAT(res[1], src_term[1], dst_term[1]); /* G */
317      SUB_SAT(res[2], src_term[2], dst_term[2]); /* B */
318      break;
319   case PIPE_BLEND_REVERSE_SUBTRACT:
320      SUB_SAT(res[0], dst_term[0], src_term[0]); /* R */
321      SUB_SAT(res[1], dst_term[1], src_term[1]); /* G */
322      SUB_SAT(res[2], dst_term[2], src_term[2]); /* B */
323      break;
324   case PIPE_BLEND_MIN:
325      res[0] = MIN2(src_term[0], dst_term[0]); /* R */
326      res[1] = MIN2(src_term[1], dst_term[1]); /* G */
327      res[2] = MIN2(src_term[2], dst_term[2]); /* B */
328      break;
329   case PIPE_BLEND_MAX:
330      res[0] = MAX2(src_term[0], dst_term[0]); /* R */
331      res[1] = MAX2(src_term[1], dst_term[1]); /* G */
332      res[2] = MAX2(src_term[2], dst_term[2]); /* B */
333      break;
334   default:
335      assert(0);
336   }
337
338   /*
339    * Combine A terms
340    */
341   switch (blend->alpha_func) {
342   case PIPE_BLEND_ADD:
343      ADD_SAT(res[3], src_term[3], dst_term[3]); /* A */
344      break;
345   case PIPE_BLEND_SUBTRACT:
346      SUB_SAT(res[3], src_term[3], dst_term[3]); /* A */
347      break;
348   case PIPE_BLEND_REVERSE_SUBTRACT:
349      SUB_SAT(res[3], dst_term[3], src_term[3]); /* A */
350      break;
351   case PIPE_BLEND_MIN:
352      res[3] = MIN2(src_term[3], dst_term[3]); /* A */
353      break;
354   case PIPE_BLEND_MAX:
355      res[3] = MAX2(src_term[3], dst_term[3]); /* A */
356      break;
357   default:
358      assert(0);
359   }
360}
361
362
363static boolean
364test_one(const struct pipe_blend_state *blend)
365{
366   LLVMModuleRef module = NULL;
367   LLVMValueRef func = NULL;
368   LLVMExecutionEngineRef engine = NULL;
369   LLVMModuleProviderRef provider = NULL;
370   LLVMPassManagerRef pass = NULL;
371   char *error = NULL;
372   blend_test_ptr_t blend_test_ptr;
373   boolean success;
374   unsigned i, j;
375
376   module = LLVMModuleCreateWithName("test");
377
378   func = add_blend_test(module, blend);
379
380   if(LLVMVerifyModule(module, LLVMPrintMessageAction, &error)) {
381      LLVMDumpModule(module);
382      abort();
383   }
384   LLVMDisposeMessage(error);
385
386   provider = LLVMCreateModuleProviderForExistingModule(module);
387   if (LLVMCreateJITCompiler(&engine, provider, 1, &error)) {
388      fprintf(stderr, "%s\n", error);
389      LLVMDisposeMessage(error);
390      abort();
391   }
392
393#if 0
394   pass = LLVMCreatePassManager();
395   LLVMAddTargetData(LLVMGetExecutionEngineTargetData(engine), pass);
396   /* These are the passes currently listed in llvm-c/Transforms/Scalar.h,
397    * but there are more on SVN. */
398   LLVMAddConstantPropagationPass(pass);
399   LLVMAddInstructionCombiningPass(pass);
400   LLVMAddPromoteMemoryToRegisterPass(pass);
401   LLVMAddGVNPass(pass);
402   LLVMAddCFGSimplificationPass(pass);
403   LLVMRunPassManager(pass, module);
404#else
405   (void)pass;
406#endif
407
408   blend_test_ptr = (blend_test_ptr_t)LLVMGetPointerToGlobal(engine, func);
409
410   if(verbose >= 2)
411      LLVMDumpModule(module);
412
413   success = TRUE;
414   for(i = 0; i < 10; ++i) {
415      float src[4];
416      float dst[4];
417      float const_[4];
418      float ref[4];
419      float res[4];
420
421      random_color(src);
422      random_color(dst);
423      random_color(const_);
424
425      compute_blend_ref(blend, src, dst, const_, ref);
426
427      blend_test_ptr(src, dst, const_, res);
428
429      for(j = 0; j < 4; ++j)
430         if(res[j] != ref[j])
431            success = FALSE;
432
433      if (!success) {
434         fprintf(stderr, "FAILED\n");
435         fprintf(stderr, "  Result: %f %f %f %f\n", res[0], res[1], res[2], res[3]);
436         fprintf(stderr, "          %f %f %f %f\n", ref[0], ref[1], ref[2], ref[3]);
437         LLVMDumpModule(module);
438         LLVMWriteBitcodeToFile(module, "blend.bc");
439         fprintf(stderr, "blend.bc written\n");
440         abort();
441         break;
442      }
443   }
444
445   LLVMFreeMachineCodeForFunction(engine, func);
446
447   LLVMDisposeExecutionEngine(engine);
448   if(pass)
449      LLVMDisposePassManager(pass);
450
451   return success;
452}
453
454
455struct value_name_pair
456{
457   unsigned value;
458   const char *name;
459};
460
461
462const struct value_name_pair
463blend_factors[] = {
464   {PIPE_BLENDFACTOR_ZERO                , "zero"},
465   {PIPE_BLENDFACTOR_ONE                 , "one"},
466   {PIPE_BLENDFACTOR_SRC_COLOR           , "src_color"},
467   {PIPE_BLENDFACTOR_SRC_ALPHA           , "src_alpha"},
468   {PIPE_BLENDFACTOR_DST_COLOR           , "dst_color"},
469   {PIPE_BLENDFACTOR_DST_ALPHA           , "dst_alpha"},
470   {PIPE_BLENDFACTOR_CONST_COLOR         , "const_color"},
471   {PIPE_BLENDFACTOR_CONST_ALPHA         , "const_alpha"},
472#if 0
473   {PIPE_BLENDFACTOR_SRC1_COLOR          , "src1_color"},
474   {PIPE_BLENDFACTOR_SRC1_ALPHA          , "src1_alpha"},
475#endif
476   {PIPE_BLENDFACTOR_SRC_ALPHA_SATURATE  , "src_alpha_saturate"},
477   {PIPE_BLENDFACTOR_INV_SRC_COLOR       , "inv_src_color"},
478   {PIPE_BLENDFACTOR_INV_SRC_ALPHA       , "inv_src_alpha"},
479   {PIPE_BLENDFACTOR_INV_DST_COLOR       , "inv_dst_color"},
480   {PIPE_BLENDFACTOR_INV_DST_ALPHA       , "inv_dst_alpha"},
481   {PIPE_BLENDFACTOR_INV_CONST_COLOR     , "inv_const_color"},
482   {PIPE_BLENDFACTOR_INV_CONST_ALPHA     , "inv_const_alpha"},
483#if 0
484   {PIPE_BLENDFACTOR_INV_SRC1_COLOR      , "inv_src1_color"},
485   {PIPE_BLENDFACTOR_INV_SRC1_ALPHA      , "inv_src1_alpha"}
486#endif
487};
488
489
490const struct value_name_pair
491blend_funcs[] = {
492   {PIPE_BLEND_ADD               , "add"},
493   {PIPE_BLEND_SUBTRACT          , "sub"},
494   {PIPE_BLEND_REVERSE_SUBTRACT  , "rev_sub"},
495   {PIPE_BLEND_MIN               , "min"},
496   {PIPE_BLEND_MAX               , "max"}
497};
498
499
500const unsigned num_funcs = sizeof(blend_funcs)/sizeof(blend_funcs[0]);
501const unsigned num_factors = sizeof(blend_factors)/sizeof(blend_factors[0]);
502
503
504static boolean
505test_all(void)
506{
507   const struct value_name_pair *rgb_func;
508   const struct value_name_pair *rgb_src_factor;
509   const struct value_name_pair *rgb_dst_factor;
510   const struct value_name_pair *alpha_func;
511   const struct value_name_pair *alpha_src_factor;
512   const struct value_name_pair *alpha_dst_factor;
513   struct pipe_blend_state blend;
514   bool success = TRUE;
515
516   for(rgb_func = blend_funcs; rgb_func < &blend_funcs[num_funcs]; ++rgb_func) {
517      for(alpha_func = blend_funcs; alpha_func < &blend_funcs[num_funcs]; ++alpha_func) {
518         for(rgb_src_factor = blend_factors; rgb_src_factor < &blend_factors[num_factors]; ++rgb_src_factor) {
519            for(rgb_dst_factor = blend_factors; rgb_dst_factor <= rgb_src_factor; ++rgb_dst_factor) {
520               for(alpha_src_factor = blend_factors; alpha_src_factor < &blend_factors[num_factors]; ++alpha_src_factor) {
521                  for(alpha_dst_factor = blend_factors; alpha_dst_factor <= alpha_src_factor; ++alpha_dst_factor) {
522
523                     if(rgb_dst_factor->value == PIPE_BLENDFACTOR_SRC_ALPHA_SATURATE ||
524                        alpha_dst_factor->value == PIPE_BLENDFACTOR_SRC_ALPHA_SATURATE)
525                        continue;
526
527                     if(verbose >= 1)
528                        fprintf(stderr,
529                                "%s=%s %s=%s %s=%s %s=%s %s=%s %s=%s ...\n",
530                                "rgb_func",         rgb_func->name,
531                                "rgb_src_factor",   rgb_src_factor->name,
532                                "rgb_dst_factor",   rgb_dst_factor->name,
533                                "alpha_func",       alpha_func->name,
534                                "alpha_src_factor", alpha_src_factor->name,
535                                "alpha_dst_factor", alpha_dst_factor->name);
536
537                     memset(&blend, 0, sizeof blend);
538                     blend.blend_enable      = 1;
539                     blend.rgb_func          = rgb_func->value;
540                     blend.rgb_src_factor    = rgb_src_factor->value;
541                     blend.rgb_dst_factor    = rgb_dst_factor->value;
542                     blend.alpha_func        = alpha_func->value;
543                     blend.alpha_src_factor  = alpha_src_factor->value;
544                     blend.alpha_dst_factor  = alpha_dst_factor->value;
545
546                     if(!test_one(&blend))
547                       success = FALSE;
548
549                  }
550               }
551            }
552         }
553      }
554   }
555
556   return success;
557}
558
559
560static boolean
561test_some(unsigned long n)
562{
563   const struct value_name_pair *rgb_func;
564   const struct value_name_pair *rgb_src_factor;
565   const struct value_name_pair *rgb_dst_factor;
566   const struct value_name_pair *alpha_func;
567   const struct value_name_pair *alpha_src_factor;
568   const struct value_name_pair *alpha_dst_factor;
569   struct pipe_blend_state blend;
570   unsigned long i;
571   bool success = TRUE;
572
573   for(i = 0; i < n; ++i) {
574      rgb_func = &blend_funcs[random() % num_funcs];
575      alpha_func = &blend_funcs[random() % num_funcs];
576      rgb_src_factor = &blend_factors[random() % num_factors];
577      alpha_src_factor = &blend_factors[random() % num_factors];
578
579      do {
580         rgb_dst_factor = &blend_factors[random() % num_factors];
581      } while(rgb_dst_factor->value == PIPE_BLENDFACTOR_SRC_ALPHA_SATURATE);
582
583      do {
584         alpha_dst_factor = &blend_factors[random() % num_factors];
585      } while(alpha_dst_factor->value == PIPE_BLENDFACTOR_SRC_ALPHA_SATURATE);
586
587      if(verbose >= 1)
588         fprintf(stderr,
589                 "%s=%s %s=%s %s=%s %s=%s %s=%s %s=%s ...\n",
590                 "rgb_func",         rgb_func->name,
591                 "rgb_src_factor",   rgb_src_factor->name,
592                 "rgb_dst_factor",   rgb_dst_factor->name,
593                 "alpha_func",       alpha_func->name,
594                 "alpha_src_factor", alpha_src_factor->name,
595                 "alpha_dst_factor", alpha_dst_factor->name);
596
597      memset(&blend, 0, sizeof blend);
598      blend.blend_enable      = 1;
599      blend.rgb_func          = rgb_func->value;
600      blend.rgb_src_factor    = rgb_src_factor->value;
601      blend.rgb_dst_factor    = rgb_dst_factor->value;
602      blend.alpha_func        = alpha_func->value;
603      blend.alpha_src_factor  = alpha_src_factor->value;
604      blend.alpha_dst_factor  = alpha_dst_factor->value;
605
606      if(!test_one(&blend))
607        success = FALSE;
608
609   }
610
611   return success;
612}
613
614
615int main(int argc, char **argv)
616{
617   unsigned long n = 1000;
618   unsigned i;
619   boolean success;
620
621   for(i = 1; i < argc; ++i) {
622      if(strcmp(argv[i], "-v") == 0)
623         ++verbose;
624      else
625         n = atoi(argv[i]);
626   }
627
628   if(n)
629      success = test_some(n);
630   else
631      success = test_all();
632
633   return success ? 0 : 1;
634}
635