1 /**************************************************************************
3 * Copyright 2009 VMware, Inc.
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:
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
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.
26 **************************************************************************/
31 * Unit tests for blend LLVM IR generation
33 * @author Jose Fonseca <jfonseca@vmware.com>
35 * Blend computation code derived from code written by
36 * @author Brian Paul <brian@vmware.com>
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>
50 #include "pipe/p_state.h"
51 #include "util/u_format.h"
52 #include "util/u_math.h"
55 #include "lp_bld_arit.h"
61 typedef void (*blend_test_ptr_t
)(const float *src
, const float *dst
, const float *const_
, float *res
);
65 add_blend_test(LLVMModuleRef module
,
66 const struct pipe_blend_state
*blend
)
74 LLVMValueRef const_ptr
;
76 LLVMBasicBlockRef block
;
77 LLVMBuilderRef builder
;
84 type
.kind
= LP_TYPE_FLOAT
;
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);
101 block
= LLVMAppendBasicBlock(func
, "entry");
102 builder
= LLVMCreateBuilder();
103 LLVMPositionBuilderAtEnd(builder
, block
);
105 src
= LLVMBuildLoad(builder
, src_ptr
, "src");
106 dst
= LLVMBuildLoad(builder
, dst_ptr
, "dst");
107 const_
= LLVMBuildLoad(builder
, const_ptr
, "const");
109 res
= lp_build_blend(builder
, blend
, type
, src
, dst
, const_
, 3);
111 LLVMSetValueName(res
, "res");
113 LLVMBuildStore(builder
, res
, res_ptr
);
115 LLVMBuildRetVoid(builder
);
117 LLVMDisposeBuilder(builder
);
123 random_color(float *color
)
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
);
132 /** Add and limit result to ceiling of 1.0 */
133 #define ADD_SAT(R, A, B) \
135 R = (A) + (B); if (R > 1.0f) R = 1.0f; \
138 /** Subtract and limit result to floor of 0.0 */
139 #define SUB_SAT(R, A, B) \
141 R = (A) - (B); if (R < 0.0f) R = 0.0f; \
146 compute_blend_ref_term(unsigned rgb_factor
,
147 unsigned alpha_factor
,
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
198 case PIPE_BLENDFACTOR_SRC1_COLOR
:
199 assert(0); /* to do */
201 case PIPE_BLENDFACTOR_SRC1_ALPHA
:
202 assert(0); /* to do */
204 case PIPE_BLENDFACTOR_ZERO
:
205 term
[0] = 0.0f
; /* R */
206 term
[1] = 0.0f
; /* G */
207 term
[2] = 0.0f
; /* B */
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 */
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 */
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 */
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 */
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 */
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 */
239 case PIPE_BLENDFACTOR_INV_SRC1_COLOR
:
240 assert(0); /* to do */
242 case PIPE_BLENDFACTOR_INV_SRC1_ALPHA
:
243 assert(0); /* to do */
250 * Compute src/first term A
252 switch (alpha_factor
) {
253 case PIPE_BLENDFACTOR_ONE
:
254 term
[3] = factor
[3]; /* A */
256 case PIPE_BLENDFACTOR_SRC_COLOR
:
257 case PIPE_BLENDFACTOR_SRC_ALPHA
:
258 term
[3] = factor
[3] * src
[3]; /* A */
260 case PIPE_BLENDFACTOR_DST_COLOR
:
261 case PIPE_BLENDFACTOR_DST_ALPHA
:
262 term
[3] = factor
[3] * dst
[3]; /* A */
264 case PIPE_BLENDFACTOR_SRC_ALPHA_SATURATE
:
265 term
[3] = src
[3]; /* A */
267 case PIPE_BLENDFACTOR_CONST_COLOR
:
268 case PIPE_BLENDFACTOR_CONST_ALPHA
:
269 term
[3] = factor
[3] * const_
[3]; /* A */
271 case PIPE_BLENDFACTOR_ZERO
:
272 term
[3] = 0.0f
; /* A */
274 case PIPE_BLENDFACTOR_INV_SRC_COLOR
:
275 case PIPE_BLENDFACTOR_INV_SRC_ALPHA
:
276 term
[3] = factor
[3] * (1.0f
- src
[3]); /* A */
278 case PIPE_BLENDFACTOR_INV_DST_COLOR
:
279 case PIPE_BLENDFACTOR_INV_DST_ALPHA
:
280 term
[3] = factor
[3] * (1.0f
- dst
[3]); /* A */
282 case PIPE_BLENDFACTOR_INV_CONST_COLOR
:
283 case PIPE_BLENDFACTOR_INV_CONST_ALPHA
:
284 term
[3] = factor
[3] * (1.0f
- const_
[3]);
293 compute_blend_ref(const struct pipe_blend_state
*blend
,
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
);
308 switch (blend
->rgb_func
) {
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 */
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 */
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 */
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 */
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 */
341 switch (blend
->alpha_func
) {
343 ADD_SAT(res
[3], src_term
[3], dst_term
[3]); /* A */
345 case PIPE_BLEND_SUBTRACT
:
346 SUB_SAT(res
[3], src_term
[3], dst_term
[3]); /* A */
348 case PIPE_BLEND_REVERSE_SUBTRACT
:
349 SUB_SAT(res
[3], dst_term
[3], src_term
[3]); /* A */
352 res
[3] = MIN2(src_term
[3], dst_term
[3]); /* A */
355 res
[3] = MAX2(src_term
[3], dst_term
[3]); /* A */
364 test_one(const struct pipe_blend_state
*blend
)
366 LLVMModuleRef module
= NULL
;
367 LLVMValueRef func
= NULL
;
368 LLVMExecutionEngineRef engine
= NULL
;
369 LLVMModuleProviderRef provider
= NULL
;
370 LLVMPassManagerRef pass
= NULL
;
372 blend_test_ptr_t blend_test_ptr
;
376 module
= LLVMModuleCreateWithName("test");
378 func
= add_blend_test(module
, blend
);
380 if(LLVMVerifyModule(module
, LLVMPrintMessageAction
, &error
)) {
381 LLVMDumpModule(module
);
384 LLVMDisposeMessage(error
);
386 provider
= LLVMCreateModuleProviderForExistingModule(module
);
387 if (LLVMCreateJITCompiler(&engine
, provider
, 1, &error
)) {
388 fprintf(stderr
, "%s\n", error
);
389 LLVMDisposeMessage(error
);
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
);
408 blend_test_ptr
= (blend_test_ptr_t
)LLVMGetPointerToGlobal(engine
, func
);
411 LLVMDumpModule(module
);
414 for(i
= 0; i
< 10; ++i
) {
423 random_color(const_
);
425 compute_blend_ref(blend
, src
, dst
, const_
, ref
);
427 blend_test_ptr(src
, dst
, const_
, res
);
429 for(j
= 0; j
< 4; ++j
)
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");
445 LLVMFreeMachineCodeForFunction(engine
, func
);
447 LLVMDisposeExecutionEngine(engine
);
449 LLVMDisposePassManager(pass
);
455 struct value_name_pair
462 const struct value_name_pair
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"},
473 {PIPE_BLENDFACTOR_SRC1_COLOR
, "src1_color"},
474 {PIPE_BLENDFACTOR_SRC1_ALPHA
, "src1_alpha"},
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"},
484 {PIPE_BLENDFACTOR_INV_SRC1_COLOR
, "inv_src1_color"},
485 {PIPE_BLENDFACTOR_INV_SRC1_ALPHA
, "inv_src1_alpha"}
490 const struct value_name_pair
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"}
500 const unsigned num_funcs
= sizeof(blend_funcs
)/sizeof(blend_funcs
[0]);
501 const unsigned num_factors
= sizeof(blend_factors
)/sizeof(blend_factors
[0]);
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
;
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
) {
523 if(rgb_dst_factor
->value
== PIPE_BLENDFACTOR_SRC_ALPHA_SATURATE
||
524 alpha_dst_factor
->value
== PIPE_BLENDFACTOR_SRC_ALPHA_SATURATE
)
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
);
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
;
546 if(!test_one(&blend
))
561 test_some(unsigned long n
)
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
;
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
];
580 rgb_dst_factor
= &blend_factors
[random() % num_factors
];
581 } while(rgb_dst_factor
->value
== PIPE_BLENDFACTOR_SRC_ALPHA_SATURATE
);
584 alpha_dst_factor
= &blend_factors
[random() % num_factors
];
585 } while(alpha_dst_factor
->value
== PIPE_BLENDFACTOR_SRC_ALPHA_SATURATE
);
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
);
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
;
606 if(!test_one(&blend
))
615 int main(int argc
, char **argv
)
617 unsigned long n
= 1000;
621 for(i
= 1; i
< argc
; ++i
) {
622 if(strcmp(argv
[i
], "-v") == 0)
629 success
= test_some(n
);
631 success
= test_all();
633 return success
? 0 : 1;