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