mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2026-05-02 07:58:07 +02:00
llvmpipe: Blending.
The code
This commit is contained in:
parent
d2cf3e8dfd
commit
7d043162c5
5 changed files with 965 additions and 2 deletions
|
|
@ -14,6 +14,7 @@ C_SOURCES = \
|
|||
lp_bld_store.c \
|
||||
lp_bld_loop.c \
|
||||
lp_bld_logicop.c \
|
||||
lp_bld_blend.c \
|
||||
lp_clear.c \
|
||||
lp_flush.c \
|
||||
lp_query.c \
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ Import('*')
|
|||
|
||||
env = env.Clone()
|
||||
|
||||
env.ParseConfig('llvm-config --cflags --libs jit interpreter nativecodegen')
|
||||
env.ParseConfig('llvm-config --cflags')
|
||||
|
||||
llvmpipe = env.ConvenienceLibrary(
|
||||
target = 'llvmpipe',
|
||||
|
|
@ -17,6 +17,7 @@ llvmpipe = env.ConvenienceLibrary(
|
|||
'lp_bld_store.c',
|
||||
'lp_bld_loop.c',
|
||||
'lp_bld_logicop.c',
|
||||
'lp_bld_blend.c',
|
||||
'lp_clear.c',
|
||||
'lp_context.c',
|
||||
'lp_draw_arrays.c',
|
||||
|
|
@ -45,12 +46,21 @@ llvmpipe = env.ConvenienceLibrary(
|
|||
'lp_tile_cache.c',
|
||||
])
|
||||
|
||||
|
||||
env = env.Clone()
|
||||
|
||||
env['LINK'] = env['CXX']
|
||||
env.ParseConfig('llvm-config --libs jit interpreter nativecodegen bitwriter')
|
||||
env.Prepend(LIBS = [llvmpipe] + auxiliaries)
|
||||
|
||||
env.Program(
|
||||
target = 'lp_bld_test',
|
||||
source = ['lp_bld_test.c'],
|
||||
LIBS = [llvmpipe] + auxiliaries + env['LIBS'],
|
||||
)
|
||||
|
||||
env.Program(
|
||||
target = 'lp_test_blend',
|
||||
source = ['lp_test_blend.c'],
|
||||
)
|
||||
|
||||
Export('llvmpipe')
|
||||
|
|
|
|||
|
|
@ -45,6 +45,9 @@
|
|||
#include "pipe/p_format.h"
|
||||
|
||||
|
||||
struct pipe_blend_state;
|
||||
|
||||
|
||||
/**
|
||||
* Unpack a pixel into its RGBA components.
|
||||
*
|
||||
|
|
@ -128,4 +131,13 @@ lp_build_logicop(LLVMBuilderRef builder,
|
|||
LLVMValueRef dst);
|
||||
|
||||
|
||||
LLVMValueRef
|
||||
lp_build_blend(LLVMBuilderRef builder,
|
||||
const struct pipe_blend_state *blend,
|
||||
LLVMValueRef src,
|
||||
LLVMValueRef dst,
|
||||
LLVMValueRef const_,
|
||||
unsigned alpha_swizzle);
|
||||
|
||||
|
||||
#endif /* !LP_BLD_H */
|
||||
|
|
|
|||
319
src/gallium/drivers/llvmpipe/lp_bld_blend.c
Normal file
319
src/gallium/drivers/llvmpipe/lp_bld_blend.c
Normal file
|
|
@ -0,0 +1,319 @@
|
|||
/**************************************************************************
|
||||
*
|
||||
* Copyright 2009 VMware, Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sub license, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the
|
||||
* next paragraph) shall be included in all copies or substantial portions
|
||||
* of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
|
||||
* IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
|
||||
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
**************************************************************************/
|
||||
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Blend LLVM IR generation.
|
||||
*
|
||||
* This code is generic -- it should be able to cope both with floating point
|
||||
* and integer inputs in AOS form.
|
||||
*
|
||||
* @author Jose Fonseca <jfonseca@vmware.com>
|
||||
*/
|
||||
|
||||
|
||||
#include "pipe/p_state.h"
|
||||
|
||||
#include "lp_bld.h"
|
||||
#include "lp_bld_arit.h"
|
||||
|
||||
|
||||
/**
|
||||
* We may the same values several times, so we keep them here to avoid
|
||||
* recomputing them. Also reusing the values allows us to do simplifications
|
||||
* that LLVM optimization passes wouldn't normally be able to do.
|
||||
*/
|
||||
struct lp_build_blend_values
|
||||
{
|
||||
LLVMBuilderRef builder;
|
||||
|
||||
LLVMValueRef undef;
|
||||
LLVMValueRef zero;
|
||||
LLVMValueRef one;
|
||||
|
||||
LLVMValueRef src;
|
||||
LLVMValueRef dst;
|
||||
LLVMValueRef const_;
|
||||
|
||||
LLVMValueRef inv_src;
|
||||
LLVMValueRef inv_dst;
|
||||
LLVMValueRef inv_const;
|
||||
LLVMValueRef saturate;
|
||||
|
||||
LLVMValueRef rgb_src_factor;
|
||||
LLVMValueRef alpha_src_factor;
|
||||
LLVMValueRef rgb_dst_factor;
|
||||
LLVMValueRef alpha_dst_factor;
|
||||
};
|
||||
|
||||
|
||||
static LLVMValueRef
|
||||
lp_build_blend_factor_unswizzled(struct lp_build_blend_values *values,
|
||||
unsigned factor,
|
||||
boolean alpha)
|
||||
{
|
||||
switch (factor) {
|
||||
case PIPE_BLENDFACTOR_ZERO:
|
||||
return values->zero;
|
||||
case PIPE_BLENDFACTOR_ONE:
|
||||
return values->one;
|
||||
case PIPE_BLENDFACTOR_SRC_COLOR:
|
||||
case PIPE_BLENDFACTOR_SRC_ALPHA:
|
||||
return values->src;
|
||||
case PIPE_BLENDFACTOR_DST_COLOR:
|
||||
case PIPE_BLENDFACTOR_DST_ALPHA:
|
||||
return values->dst;
|
||||
case PIPE_BLENDFACTOR_SRC_ALPHA_SATURATE:
|
||||
if(alpha)
|
||||
return values->one;
|
||||
else {
|
||||
if(!values->inv_dst)
|
||||
values->inv_dst = lp_build_sub(values->builder, values->one, values->dst, values->zero);
|
||||
if(!values->saturate)
|
||||
values->saturate = lp_build_min_sat(values->builder, values->src, values->inv_dst, values->zero, values->one);
|
||||
return values->saturate;
|
||||
}
|
||||
case PIPE_BLENDFACTOR_CONST_COLOR:
|
||||
case PIPE_BLENDFACTOR_CONST_ALPHA:
|
||||
return values->const_;
|
||||
case PIPE_BLENDFACTOR_SRC1_COLOR:
|
||||
case PIPE_BLENDFACTOR_SRC1_ALPHA:
|
||||
/* TODO */
|
||||
assert(0);
|
||||
return values->zero;
|
||||
case PIPE_BLENDFACTOR_INV_SRC_COLOR:
|
||||
case PIPE_BLENDFACTOR_INV_SRC_ALPHA:
|
||||
if(!values->inv_src)
|
||||
values->inv_src = lp_build_sub(values->builder, values->one, values->src, values->zero);
|
||||
return values->inv_src;
|
||||
case PIPE_BLENDFACTOR_INV_DST_COLOR:
|
||||
case PIPE_BLENDFACTOR_INV_DST_ALPHA:
|
||||
if(!values->inv_dst)
|
||||
values->inv_dst = lp_build_sub(values->builder, values->one, values->dst, values->zero);
|
||||
return values->inv_dst;
|
||||
case PIPE_BLENDFACTOR_INV_CONST_COLOR:
|
||||
case PIPE_BLENDFACTOR_INV_CONST_ALPHA:
|
||||
if(!values->inv_const)
|
||||
values->inv_const = lp_build_sub(values->builder, values->one, values->const_, values->zero);
|
||||
return values->inv_const;
|
||||
case PIPE_BLENDFACTOR_INV_SRC1_COLOR:
|
||||
case PIPE_BLENDFACTOR_INV_SRC1_ALPHA:
|
||||
/* TODO */
|
||||
assert(0);
|
||||
return values->zero;
|
||||
default:
|
||||
assert(0);
|
||||
return values->zero;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
enum lp_build_blend_swizzle {
|
||||
LP_BUILD_BLEND_SWIZZLE_RGBA = 0,
|
||||
LP_BUILD_BLEND_SWIZZLE_AAAA = 1,
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* How should we shuffle the base factor.
|
||||
*/
|
||||
static enum lp_build_blend_swizzle
|
||||
lp_build_blend_factor_swizzle(unsigned factor)
|
||||
{
|
||||
switch (factor) {
|
||||
case PIPE_BLENDFACTOR_ONE:
|
||||
case PIPE_BLENDFACTOR_ZERO:
|
||||
case PIPE_BLENDFACTOR_SRC_COLOR:
|
||||
case PIPE_BLENDFACTOR_DST_COLOR:
|
||||
case PIPE_BLENDFACTOR_CONST_COLOR:
|
||||
case PIPE_BLENDFACTOR_SRC1_COLOR:
|
||||
case PIPE_BLENDFACTOR_INV_SRC_COLOR:
|
||||
case PIPE_BLENDFACTOR_INV_DST_COLOR:
|
||||
case PIPE_BLENDFACTOR_INV_CONST_COLOR:
|
||||
case PIPE_BLENDFACTOR_INV_SRC1_COLOR:
|
||||
return LP_BUILD_BLEND_SWIZZLE_RGBA;
|
||||
case PIPE_BLENDFACTOR_SRC_ALPHA:
|
||||
case PIPE_BLENDFACTOR_DST_ALPHA:
|
||||
case PIPE_BLENDFACTOR_SRC_ALPHA_SATURATE:
|
||||
case PIPE_BLENDFACTOR_SRC1_ALPHA:
|
||||
case PIPE_BLENDFACTOR_CONST_ALPHA:
|
||||
case PIPE_BLENDFACTOR_INV_SRC_ALPHA:
|
||||
case PIPE_BLENDFACTOR_INV_DST_ALPHA:
|
||||
case PIPE_BLENDFACTOR_INV_CONST_ALPHA:
|
||||
case PIPE_BLENDFACTOR_INV_SRC1_ALPHA:
|
||||
return LP_BUILD_BLEND_SWIZZLE_AAAA;
|
||||
default:
|
||||
assert(0);
|
||||
return LP_BUILD_BLEND_SWIZZLE_RGBA;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static LLVMValueRef
|
||||
lp_build_blend_swizzle(struct lp_build_blend_values *values,
|
||||
LLVMValueRef rgb,
|
||||
LLVMValueRef alpha,
|
||||
enum lp_build_blend_swizzle rgb_swizzle,
|
||||
unsigned alpha_swizzle,
|
||||
unsigned n)
|
||||
{
|
||||
LLVMValueRef swizzles[LP_MAX_VECTOR_SIZE];
|
||||
unsigned i, j;
|
||||
|
||||
if(rgb == alpha) {
|
||||
if(rgb_swizzle == LP_BUILD_BLEND_SWIZZLE_RGBA)
|
||||
return rgb;
|
||||
|
||||
alpha = values->undef;
|
||||
}
|
||||
|
||||
for(j = 0; j < n; j += 4) {
|
||||
for(i = 0; i < 4; ++i) {
|
||||
unsigned swizzle;
|
||||
|
||||
if(i == alpha_swizzle && alpha != values->undef) {
|
||||
/* Take the alpha from the second shuffle argument */
|
||||
swizzle = n + j + alpha_swizzle;
|
||||
}
|
||||
else if (rgb_swizzle == LP_BUILD_BLEND_SWIZZLE_AAAA) {
|
||||
/* Take the alpha from the first shuffle argument */
|
||||
swizzle = j + alpha_swizzle;
|
||||
}
|
||||
else {
|
||||
swizzle = j + i;
|
||||
}
|
||||
|
||||
swizzles[j + i] = LLVMConstInt(LLVMInt32Type(), swizzle, 0);
|
||||
}
|
||||
}
|
||||
|
||||
return LLVMBuildShuffleVector(values->builder, rgb, alpha, LLVMConstVector(swizzles, n), "");
|
||||
}
|
||||
|
||||
|
||||
static LLVMValueRef
|
||||
lp_build_blend_factor(struct lp_build_blend_values *values,
|
||||
LLVMValueRef factor1,
|
||||
unsigned rgb_factor,
|
||||
unsigned alpha_factor,
|
||||
unsigned alpha_swizzle,
|
||||
unsigned n)
|
||||
{
|
||||
LLVMValueRef rgb_factor_;
|
||||
LLVMValueRef alpha_factor_;
|
||||
LLVMValueRef factor2;
|
||||
enum lp_build_blend_swizzle rgb_swizzle;
|
||||
|
||||
rgb_factor_ = lp_build_blend_factor_unswizzled(values, rgb_factor, FALSE);
|
||||
alpha_factor_ = lp_build_blend_factor_unswizzled(values, alpha_factor, TRUE);
|
||||
|
||||
rgb_swizzle = lp_build_blend_factor_swizzle(rgb_factor);
|
||||
|
||||
factor2 = lp_build_blend_swizzle(values, rgb_factor_, alpha_factor_, rgb_swizzle, alpha_swizzle, n);
|
||||
|
||||
return lp_build_mul(values->builder, factor1, factor2, values->zero, values->one);
|
||||
}
|
||||
|
||||
|
||||
static LLVMValueRef
|
||||
lp_build_blend_func(struct lp_build_blend_values *values,
|
||||
unsigned func,
|
||||
LLVMValueRef term1,
|
||||
LLVMValueRef term2)
|
||||
{
|
||||
switch (func) {
|
||||
case PIPE_BLEND_ADD:
|
||||
return lp_build_add_sat(values->builder, term1, term2, values->zero, values->one);
|
||||
break;
|
||||
case PIPE_BLEND_SUBTRACT:
|
||||
return lp_build_sub_sat(values->builder, term1, term2, values->zero, values->one);
|
||||
case PIPE_BLEND_REVERSE_SUBTRACT:
|
||||
return lp_build_sub_sat(values->builder, term2, term1, values->zero, values->one);
|
||||
case PIPE_BLEND_MIN:
|
||||
return lp_build_min_sat(values->builder, term1, term2, values->zero, values->one);
|
||||
case PIPE_BLEND_MAX:
|
||||
return lp_build_max_sat(values->builder, term1, term2, values->zero, values->one);
|
||||
default:
|
||||
assert(0);
|
||||
return values->zero;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
LLVMValueRef
|
||||
lp_build_blend(LLVMBuilderRef builder,
|
||||
const struct pipe_blend_state *blend,
|
||||
LLVMValueRef src,
|
||||
LLVMValueRef dst,
|
||||
LLVMValueRef const_,
|
||||
unsigned alpha_swizzle)
|
||||
{
|
||||
struct lp_build_blend_values values;
|
||||
LLVMValueRef src_term;
|
||||
LLVMValueRef dst_term;
|
||||
LLVMTypeRef type;
|
||||
unsigned n;
|
||||
|
||||
type = LLVMTypeOf(src);
|
||||
n = LLVMGetVectorSize(type);
|
||||
|
||||
/*
|
||||
* Compute constants
|
||||
*/
|
||||
memset(&values, 0, sizeof values);
|
||||
values.builder = builder;
|
||||
values.undef = LLVMGetUndef(type);
|
||||
values.zero = LLVMConstNull(type);
|
||||
values.one = lp_build_const_aos(type, 1.0, 1.0, 1.0, 1.0, NULL);
|
||||
|
||||
values.src = src;
|
||||
values.dst = dst;
|
||||
values.const_ = const_;
|
||||
|
||||
/* TODO: There are still a few optimization oportunities here. For certain
|
||||
* combinations it is possible to reorder the operations and therefor saving
|
||||
* some instructions. */
|
||||
|
||||
src_term = lp_build_blend_factor(&values, src, blend->rgb_src_factor, blend->alpha_src_factor, alpha_swizzle, n);
|
||||
dst_term = lp_build_blend_factor(&values, dst, blend->rgb_dst_factor, blend->alpha_dst_factor, alpha_swizzle, n);
|
||||
|
||||
if(blend->rgb_func == blend->alpha_func) {
|
||||
return lp_build_blend_func(&values, blend->rgb_func, src_term, dst_term);
|
||||
}
|
||||
else {
|
||||
/* Seperate RGB / A functions */
|
||||
|
||||
LLVMValueRef rgb;
|
||||
LLVMValueRef alpha;
|
||||
|
||||
rgb = lp_build_blend_func(&values, blend->rgb_func, src_term, dst_term);
|
||||
alpha = lp_build_blend_func(&values, blend->alpha_func, src_term, dst_term);
|
||||
|
||||
return lp_build_blend_swizzle(&values, rgb, alpha, LP_BUILD_BLEND_SWIZZLE_RGBA, alpha_swizzle, n);
|
||||
}
|
||||
}
|
||||
621
src/gallium/drivers/llvmpipe/lp_test_blend.c
Normal file
621
src/gallium/drivers/llvmpipe/lp_test_blend.c
Normal file
|
|
@ -0,0 +1,621 @@
|
|||
/**************************************************************************
|
||||
*
|
||||
* Copyright 2009 VMware, Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sub license, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the
|
||||
* next paragraph) shall be included in all copies or substantial portions
|
||||
* of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
|
||||
* IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
|
||||
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
**************************************************************************/
|
||||
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Unit tests for blend LLVM IR generation
|
||||
*
|
||||
* @author Jose Fonseca <jfonseca@vmware.com>
|
||||
*
|
||||
* Blend computation code derived from code written by
|
||||
* @author Brian Paul <brian@vmware.com>
|
||||
*/
|
||||
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.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"
|
||||
|
||||
#include "lp_bld.h"
|
||||
|
||||
|
||||
unsigned verbose = 0;
|
||||
|
||||
|
||||
typedef void (*blend_test_ptr_t)(const float *src, const float *dst, const float *const_, float *res);
|
||||
|
||||
|
||||
static LLVMValueRef
|
||||
add_blend_test(LLVMModuleRef module,
|
||||
const struct pipe_blend_state *blend)
|
||||
{
|
||||
LLVMTypeRef args[4];
|
||||
LLVMValueRef func;
|
||||
LLVMValueRef src_ptr;
|
||||
LLVMValueRef dst_ptr;
|
||||
LLVMValueRef const_ptr;
|
||||
LLVMValueRef res_ptr;
|
||||
LLVMBasicBlockRef block;
|
||||
LLVMBuilderRef builder;
|
||||
LLVMValueRef src;
|
||||
LLVMValueRef dst;
|
||||
LLVMValueRef const_;
|
||||
LLVMValueRef res;
|
||||
|
||||
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);
|
||||
func = LLVMAddFunction(module, "test", LLVMFunctionType(LLVMVoidType(), args, 4, 0));
|
||||
LLVMSetFunctionCallConv(func, LLVMCCallConv);
|
||||
src_ptr = LLVMGetParam(func, 0);
|
||||
dst_ptr = LLVMGetParam(func, 1);
|
||||
const_ptr = LLVMGetParam(func, 2);
|
||||
res_ptr = LLVMGetParam(func, 3);
|
||||
|
||||
block = LLVMAppendBasicBlock(func, "entry");
|
||||
builder = LLVMCreateBuilder();
|
||||
LLVMPositionBuilderAtEnd(builder, block);
|
||||
|
||||
src = LLVMBuildLoad(builder, src_ptr, "src");
|
||||
dst = LLVMBuildLoad(builder, dst_ptr, "dst");
|
||||
const_ = LLVMBuildLoad(builder, const_ptr, "const");
|
||||
|
||||
res = lp_build_blend(builder, blend, src, dst, const_, 3);
|
||||
|
||||
LLVMSetValueName(res, "res");
|
||||
|
||||
LLVMBuildStore(builder, res, res_ptr);
|
||||
|
||||
LLVMBuildRetVoid(builder);
|
||||
|
||||
LLVMDisposeBuilder(builder);
|
||||
return func;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
random_color(float *color)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
/** Add and limit result to ceiling of 1.0 */
|
||||
#define ADD_SAT(R, A, B) \
|
||||
do { \
|
||||
R = (A) + (B); if (R > 1.0f) R = 1.0f; \
|
||||
} while (0)
|
||||
|
||||
/** Subtract and limit result to floor of 0.0 */
|
||||
#define SUB_SAT(R, A, B) \
|
||||
do { \
|
||||
R = (A) - (B); if (R < 0.0f) R = 0.0f; \
|
||||
} while (0)
|
||||
|
||||
|
||||
static void
|
||||
compute_blend_ref_term(unsigned rgb_factor,
|
||||
unsigned alpha_factor,
|
||||
const float *factor,
|
||||
const float *src,
|
||||
const float *dst,
|
||||
const float *const_,
|
||||
float *term)
|
||||
{
|
||||
float temp;
|
||||
|
||||
switch (rgb_factor) {
|
||||
case PIPE_BLENDFACTOR_ONE:
|
||||
term[0] = factor[0]; /* R */
|
||||
term[1] = factor[1]; /* G */
|
||||
term[2] = factor[2]; /* B */
|
||||
break;
|
||||
case PIPE_BLENDFACTOR_SRC_COLOR:
|
||||
term[0] = factor[0] * src[0]; /* R */
|
||||
term[1] = factor[1] * src[1]; /* G */
|
||||
term[2] = factor[2] * src[2]; /* B */
|
||||
break;
|
||||
case PIPE_BLENDFACTOR_SRC_ALPHA:
|
||||
term[0] = factor[0] * src[3]; /* R */
|
||||
term[1] = factor[1] * src[3]; /* G */
|
||||
term[2] = factor[2] * src[3]; /* B */
|
||||
break;
|
||||
case PIPE_BLENDFACTOR_DST_COLOR:
|
||||
term[0] = factor[0] * dst[0]; /* R */
|
||||
term[1] = factor[1] * dst[1]; /* G */
|
||||
term[2] = factor[2] * dst[2]; /* B */
|
||||
break;
|
||||
case PIPE_BLENDFACTOR_DST_ALPHA:
|
||||
term[0] = factor[0] * dst[3]; /* R */
|
||||
term[1] = factor[1] * dst[3]; /* G */
|
||||
term[2] = factor[2] * dst[3]; /* B */
|
||||
break;
|
||||
case PIPE_BLENDFACTOR_SRC_ALPHA_SATURATE:
|
||||
temp = MIN2(src[3], 1.0f - dst[3]);
|
||||
term[0] = factor[0] * temp; /* R */
|
||||
term[1] = factor[1] * temp; /* G */
|
||||
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 */
|
||||
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 */
|
||||
break;
|
||||
case PIPE_BLENDFACTOR_SRC1_COLOR:
|
||||
assert(0); /* to do */
|
||||
break;
|
||||
case PIPE_BLENDFACTOR_SRC1_ALPHA:
|
||||
assert(0); /* to do */
|
||||
break;
|
||||
case PIPE_BLENDFACTOR_ZERO:
|
||||
term[0] = 0.0f; /* R */
|
||||
term[1] = 0.0f; /* G */
|
||||
term[2] = 0.0f; /* B */
|
||||
break;
|
||||
case PIPE_BLENDFACTOR_INV_SRC_COLOR:
|
||||
term[0] = factor[0] * (1.0f - src[0]); /* R */
|
||||
term[1] = factor[1] * (1.0f - src[1]); /* G */
|
||||
term[2] = factor[2] * (1.0f - src[2]); /* B */
|
||||
break;
|
||||
case PIPE_BLENDFACTOR_INV_SRC_ALPHA:
|
||||
term[0] = factor[0] * (1.0f - src[3]); /* R */
|
||||
term[1] = factor[1] * (1.0f - src[3]); /* G */
|
||||
term[2] = factor[2] * (1.0f - src[3]); /* B */
|
||||
break;
|
||||
case PIPE_BLENDFACTOR_INV_DST_ALPHA:
|
||||
term[0] = factor[0] * (1.0f - dst[3]); /* R */
|
||||
term[1] = factor[1] * (1.0f - dst[3]); /* G */
|
||||
term[2] = factor[2] * (1.0f - dst[3]); /* B */
|
||||
break;
|
||||
case PIPE_BLENDFACTOR_INV_DST_COLOR:
|
||||
term[0] = factor[0] * (1.0f - dst[0]); /* R */
|
||||
term[1] = factor[1] * (1.0f - dst[1]); /* G */
|
||||
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 */
|
||||
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 */
|
||||
break;
|
||||
case PIPE_BLENDFACTOR_INV_SRC1_COLOR:
|
||||
assert(0); /* to do */
|
||||
break;
|
||||
case PIPE_BLENDFACTOR_INV_SRC1_ALPHA:
|
||||
assert(0); /* to do */
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Compute src/first term A
|
||||
*/
|
||||
switch (alpha_factor) {
|
||||
case PIPE_BLENDFACTOR_ONE:
|
||||
term[3] = factor[3]; /* A */
|
||||
break;
|
||||
case PIPE_BLENDFACTOR_SRC_COLOR:
|
||||
case PIPE_BLENDFACTOR_SRC_ALPHA:
|
||||
term[3] = factor[3] * src[3]; /* A */
|
||||
break;
|
||||
case PIPE_BLENDFACTOR_DST_COLOR:
|
||||
case PIPE_BLENDFACTOR_DST_ALPHA:
|
||||
term[3] = factor[3] * dst[3]; /* A */
|
||||
break;
|
||||
case PIPE_BLENDFACTOR_SRC_ALPHA_SATURATE:
|
||||
term[3] = src[3]; /* A */
|
||||
break;
|
||||
case PIPE_BLENDFACTOR_CONST_COLOR:
|
||||
case PIPE_BLENDFACTOR_CONST_ALPHA:
|
||||
term[3] = factor[3] * const_[3]; /* A */
|
||||
break;
|
||||
case PIPE_BLENDFACTOR_ZERO:
|
||||
term[3] = 0.0f; /* A */
|
||||
break;
|
||||
case PIPE_BLENDFACTOR_INV_SRC_COLOR:
|
||||
case PIPE_BLENDFACTOR_INV_SRC_ALPHA:
|
||||
term[3] = factor[3] * (1.0f - src[3]); /* A */
|
||||
break;
|
||||
case PIPE_BLENDFACTOR_INV_DST_COLOR:
|
||||
case PIPE_BLENDFACTOR_INV_DST_ALPHA:
|
||||
term[3] = factor[3] * (1.0f - dst[3]); /* A */
|
||||
break;
|
||||
case PIPE_BLENDFACTOR_INV_CONST_COLOR:
|
||||
case PIPE_BLENDFACTOR_INV_CONST_ALPHA:
|
||||
term[3] = factor[3] * (1.0f - const_[3]);
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
compute_blend_ref(const struct pipe_blend_state *blend,
|
||||
const float *src,
|
||||
const float *dst,
|
||||
const float *const_,
|
||||
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);
|
||||
|
||||
/*
|
||||
* Combine RGB terms
|
||||
*/
|
||||
switch (blend->rgb_func) {
|
||||
case PIPE_BLEND_ADD:
|
||||
ADD_SAT(res[0], src_term[0], dst_term[0]); /* R */
|
||||
ADD_SAT(res[1], src_term[1], dst_term[1]); /* G */
|
||||
ADD_SAT(res[2], src_term[2], dst_term[2]); /* B */
|
||||
break;
|
||||
case PIPE_BLEND_SUBTRACT:
|
||||
SUB_SAT(res[0], src_term[0], dst_term[0]); /* R */
|
||||
SUB_SAT(res[1], src_term[1], dst_term[1]); /* G */
|
||||
SUB_SAT(res[2], src_term[2], dst_term[2]); /* B */
|
||||
break;
|
||||
case PIPE_BLEND_REVERSE_SUBTRACT:
|
||||
SUB_SAT(res[0], dst_term[0], src_term[0]); /* R */
|
||||
SUB_SAT(res[1], dst_term[1], src_term[1]); /* G */
|
||||
SUB_SAT(res[2], dst_term[2], src_term[2]); /* B */
|
||||
break;
|
||||
case PIPE_BLEND_MIN:
|
||||
res[0] = MIN2(src_term[0], dst_term[0]); /* R */
|
||||
res[1] = MIN2(src_term[1], dst_term[1]); /* G */
|
||||
res[2] = MIN2(src_term[2], dst_term[2]); /* B */
|
||||
break;
|
||||
case PIPE_BLEND_MAX:
|
||||
res[0] = MAX2(src_term[0], dst_term[0]); /* R */
|
||||
res[1] = MAX2(src_term[1], dst_term[1]); /* G */
|
||||
res[2] = MAX2(src_term[2], dst_term[2]); /* B */
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Combine A terms
|
||||
*/
|
||||
switch (blend->alpha_func) {
|
||||
case PIPE_BLEND_ADD:
|
||||
ADD_SAT(res[3], src_term[3], dst_term[3]); /* A */
|
||||
break;
|
||||
case PIPE_BLEND_SUBTRACT:
|
||||
SUB_SAT(res[3], src_term[3], dst_term[3]); /* A */
|
||||
break;
|
||||
case PIPE_BLEND_REVERSE_SUBTRACT:
|
||||
SUB_SAT(res[3], dst_term[3], src_term[3]); /* A */
|
||||
break;
|
||||
case PIPE_BLEND_MIN:
|
||||
res[3] = MIN2(src_term[3], dst_term[3]); /* A */
|
||||
break;
|
||||
case PIPE_BLEND_MAX:
|
||||
res[3] = MAX2(src_term[3], dst_term[3]); /* A */
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static boolean
|
||||
test_one(const struct pipe_blend_state *blend)
|
||||
{
|
||||
LLVMModuleRef module = NULL;
|
||||
LLVMValueRef func = NULL;
|
||||
LLVMExecutionEngineRef engine = NULL;
|
||||
LLVMModuleProviderRef provider = NULL;
|
||||
LLVMPassManagerRef pass = NULL;
|
||||
char *error = NULL;
|
||||
blend_test_ptr_t blend_test_ptr;
|
||||
boolean success;
|
||||
unsigned i, j;
|
||||
|
||||
module = LLVMModuleCreateWithName("test");
|
||||
|
||||
func = add_blend_test(module, blend);
|
||||
|
||||
if(LLVMVerifyModule(module, LLVMPrintMessageAction, &error)) {
|
||||
LLVMDumpModule(module);
|
||||
LLVMDisposeMessage(error);
|
||||
abort();
|
||||
}
|
||||
|
||||
provider = LLVMCreateModuleProviderForExistingModule(module);
|
||||
if (LLVMCreateJITCompiler(&engine, provider, 1, &error)) {
|
||||
fprintf(stderr, "%s\n", error);
|
||||
LLVMDisposeMessage(error);
|
||||
abort();
|
||||
}
|
||||
|
||||
#if 0
|
||||
pass = LLVMCreatePassManager();
|
||||
LLVMAddTargetData(LLVMGetExecutionEngineTargetData(engine), pass);
|
||||
/* These are the passes currently listed in llvm-c/Transforms/Scalar.h,
|
||||
* but there are more on SVN. */
|
||||
LLVMAddConstantPropagationPass(pass);
|
||||
LLVMAddInstructionCombiningPass(pass);
|
||||
LLVMAddPromoteMemoryToRegisterPass(pass);
|
||||
LLVMAddGVNPass(pass);
|
||||
LLVMAddCFGSimplificationPass(pass);
|
||||
LLVMRunPassManager(pass, module);
|
||||
#else
|
||||
(void)pass;
|
||||
#endif
|
||||
|
||||
blend_test_ptr = (blend_test_ptr_t)LLVMGetPointerToGlobal(engine, func);
|
||||
|
||||
if(verbose >= 2)
|
||||
LLVMDumpModule(module);
|
||||
|
||||
success = TRUE;
|
||||
for(i = 0; i < 10; ++i) {
|
||||
float src[4];
|
||||
float dst[4];
|
||||
float const_[4];
|
||||
float ref[4];
|
||||
float res[4];
|
||||
|
||||
random_color(src);
|
||||
random_color(dst);
|
||||
random_color(const_);
|
||||
|
||||
compute_blend_ref(blend, src, dst, const_, ref);
|
||||
|
||||
blend_test_ptr(src, dst, const_, res);
|
||||
|
||||
for(j = 0; j < 4; ++j)
|
||||
if(res[j] != ref[j])
|
||||
success = FALSE;
|
||||
|
||||
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");
|
||||
abort();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
LLVMDisposeExecutionEngine(engine);
|
||||
//LLVMDisposeModule(module);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
struct value_name_pair
|
||||
{
|
||||
unsigned value;
|
||||
const char *name;
|
||||
};
|
||||
|
||||
|
||||
const struct value_name_pair
|
||||
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"},
|
||||
#if 0
|
||||
{PIPE_BLENDFACTOR_SRC1_COLOR , "src1_color"},
|
||||
{PIPE_BLENDFACTOR_SRC1_ALPHA , "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"},
|
||||
#if 0
|
||||
{PIPE_BLENDFACTOR_INV_SRC1_COLOR , "inv_src1_color"},
|
||||
{PIPE_BLENDFACTOR_INV_SRC1_ALPHA , "inv_src1_alpha"}
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
const struct value_name_pair
|
||||
blend_funcs[] = {
|
||||
{PIPE_BLEND_ADD , "add"},
|
||||
{PIPE_BLEND_SUBTRACT , "sub"},
|
||||
{PIPE_BLEND_REVERSE_SUBTRACT , "rev_sub"},
|
||||
{PIPE_BLEND_MIN , "min"},
|
||||
{PIPE_BLEND_MAX , "max"}
|
||||
};
|
||||
|
||||
|
||||
const unsigned num_funcs = sizeof(blend_funcs)/sizeof(blend_funcs[0]);
|
||||
const unsigned num_factors = sizeof(blend_factors)/sizeof(blend_factors[0]);
|
||||
|
||||
|
||||
static boolean
|
||||
test_all(void)
|
||||
{
|
||||
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;
|
||||
struct pipe_blend_state blend;
|
||||
bool success = TRUE;
|
||||
|
||||
for(rgb_func = blend_funcs; rgb_func < &blend_funcs[num_funcs]; ++rgb_func) {
|
||||
for(alpha_func = blend_funcs; alpha_func < &blend_funcs[num_funcs]; ++alpha_func) {
|
||||
for(rgb_src_factor = blend_factors; rgb_src_factor < &blend_factors[num_factors]; ++rgb_src_factor) {
|
||||
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;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
static boolean
|
||||
test_some(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;
|
||||
struct pipe_blend_state blend;
|
||||
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];
|
||||
|
||||
do {
|
||||
rgb_dst_factor = &blend_factors[random() % num_factors];
|
||||
} while(rgb_dst_factor->value == PIPE_BLENDFACTOR_SRC_ALPHA_SATURATE);
|
||||
|
||||
do {
|
||||
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;
|
||||
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
unsigned long n = 1000;
|
||||
unsigned i;
|
||||
boolean success;
|
||||
|
||||
for(i = 1; i < argc; ++i) {
|
||||
if(strcmp(argv[i], "-v") == 0)
|
||||
++verbose;
|
||||
else
|
||||
n = atoi(argv[i]);
|
||||
}
|
||||
|
||||
if(n)
|
||||
success = test_some(n);
|
||||
else
|
||||
success = test_all();
|
||||
|
||||
return success ? 0 : 1;
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue