diff options
Diffstat (limited to 'src/gallium/auxiliary/gallivm')
-rw-r--r-- | src/gallium/auxiliary/gallivm/lp_bld_arit.c | 56 | ||||
-rw-r--r-- | src/gallium/auxiliary/gallivm/lp_bld_arit.h | 12 | ||||
-rw-r--r-- | src/gallium/auxiliary/gallivm/lp_bld_init.cpp (renamed from src/gallium/auxiliary/gallivm/lp_bld_misc.cpp) | 46 | ||||
-rw-r--r-- | src/gallium/auxiliary/gallivm/lp_bld_init.h (renamed from src/gallium/auxiliary/gallivm/lp_bld_misc.h) | 17 | ||||
-rw-r--r-- | src/gallium/auxiliary/gallivm/lp_bld_logic.c | 5 | ||||
-rw-r--r-- | src/gallium/auxiliary/gallivm/lp_bld_pack.c | 15 | ||||
-rw-r--r-- | src/gallium/auxiliary/gallivm/lp_bld_sample.c | 30 | ||||
-rw-r--r-- | src/gallium/auxiliary/gallivm/lp_bld_sample.h | 14 | ||||
-rw-r--r-- | src/gallium/auxiliary/gallivm/lp_bld_sample_soa.c | 860 | ||||
-rw-r--r-- | src/gallium/auxiliary/gallivm/lp_bld_tgsi_soa.c | 121 | ||||
-rw-r--r-- | src/gallium/auxiliary/gallivm/lp_bld_type.c | 20 | ||||
-rw-r--r-- | src/gallium/auxiliary/gallivm/lp_bld_type.h | 4 |
12 files changed, 1074 insertions, 126 deletions
diff --git a/src/gallium/auxiliary/gallivm/lp_bld_arit.c b/src/gallium/auxiliary/gallivm/lp_bld_arit.c index bbce31f9eb..32f9e5201c 100644 --- a/src/gallium/auxiliary/gallivm/lp_bld_arit.c +++ b/src/gallium/auxiliary/gallivm/lp_bld_arit.c @@ -669,6 +669,14 @@ lp_build_abs(struct lp_build_context *bld, LLVMValueRef +lp_build_negate(struct lp_build_context *bld, + LLVMValueRef a) +{ + return LLVMBuildNeg(bld->builder, a, ""); +} + + +LLVMValueRef lp_build_sgn(struct lp_build_context *bld, LLVMValueRef a) { @@ -710,6 +718,41 @@ lp_build_sgn(struct lp_build_context *bld, /** + * Set the sign of float vector 'a' according to 'sign'. + * If sign==0, return abs(a). + * If sign==1, return -abs(a); + * Other values for sign produce undefined results. + */ +LLVMValueRef +lp_build_set_sign(struct lp_build_context *bld, + LLVMValueRef a, LLVMValueRef sign) +{ + const struct lp_type type = bld->type; + LLVMTypeRef int_vec_type = lp_build_int_vec_type(type); + LLVMTypeRef vec_type = lp_build_vec_type(type); + LLVMValueRef shift = lp_build_int_const_scalar(type, type.width - 1); + LLVMValueRef mask = lp_build_int_const_scalar(type, + ~((unsigned long long) 1 << (type.width - 1))); + LLVMValueRef val, res; + + assert(type.floating); + + /* val = reinterpret_cast<int>(a) */ + val = LLVMBuildBitCast(bld->builder, a, int_vec_type, ""); + /* val = val & mask */ + val = LLVMBuildAnd(bld->builder, val, mask, ""); + /* sign = sign << shift */ + sign = LLVMBuildShl(bld->builder, sign, shift, ""); + /* res = val | sign */ + res = LLVMBuildOr(bld->builder, val, sign, ""); + /* res = reinterpret_cast<float>(res) */ + res = LLVMBuildBitCast(bld->builder, res, vec_type, ""); + + return res; +} + + +/** * Convert vector of int to vector of float. */ LLVMValueRef @@ -857,6 +900,19 @@ lp_build_ceil(struct lp_build_context *bld, /** + * Return fractional part of 'a' computed as a - floor(f) + * Typically used in texture coord arithmetic. + */ +LLVMValueRef +lp_build_fract(struct lp_build_context *bld, + LLVMValueRef a) +{ + assert(bld->type.floating); + return lp_build_sub(bld, a, lp_build_floor(bld, a)); +} + + +/** * Convert to integer, through whichever rounding method that's fastest, * typically truncating toward zero. */ diff --git a/src/gallium/auxiliary/gallivm/lp_bld_arit.h b/src/gallium/auxiliary/gallivm/lp_bld_arit.h index da84b7ca02..55385e3a66 100644 --- a/src/gallium/auxiliary/gallivm/lp_bld_arit.h +++ b/src/gallium/auxiliary/gallivm/lp_bld_arit.h @@ -117,10 +117,18 @@ lp_build_abs(struct lp_build_context *bld, LLVMValueRef a); LLVMValueRef +lp_build_negate(struct lp_build_context *bld, + LLVMValueRef a); + +LLVMValueRef lp_build_sgn(struct lp_build_context *bld, LLVMValueRef a); LLVMValueRef +lp_build_set_sign(struct lp_build_context *bld, + LLVMValueRef a, LLVMValueRef sign); + +LLVMValueRef lp_build_int_to_float(struct lp_build_context *bld, LLVMValueRef a); @@ -141,6 +149,10 @@ lp_build_trunc(struct lp_build_context *bld, LLVMValueRef a); LLVMValueRef +lp_build_fract(struct lp_build_context *bld, + LLVMValueRef a); + +LLVMValueRef lp_build_ifloor(struct lp_build_context *bld, LLVMValueRef a); LLVMValueRef diff --git a/src/gallium/auxiliary/gallivm/lp_bld_misc.cpp b/src/gallium/auxiliary/gallivm/lp_bld_init.cpp index 6e79438ead..067397a520 100644 --- a/src/gallium/auxiliary/gallivm/lp_bld_misc.cpp +++ b/src/gallium/auxiliary/gallivm/lp_bld_init.cpp @@ -26,39 +26,34 @@ **************************************************************************/ -#include "pipe/p_config.h" +#include <llvm/Config/config.h> +#include <llvm/Target/TargetSelect.h> +#include <llvm/Target/TargetOptions.h> -#include "lp_bld_misc.h" +#include "pipe/p_config.h" +#include "lp_bld_init.h" -#ifndef LLVM_NATIVE_ARCH -namespace llvm { - extern void LinkInJIT(); -} +extern "C" void LLVMLinkInJIT(); -void -LLVMLinkInJIT(void) +extern "C" void +lp_build_init(void) { - llvm::LinkInJIT(); -} - - -extern "C" int X86TargetMachineModule; - - -int -LLVMInitializeNativeTarget(void) -{ -#if defined(PIPE_ARCH_X86) || defined(PIPE_ARCH_X86_64) - X86TargetMachineModule = 1; +#if defined(PIPE_OS_WINDOWS) && defined(PIPE_ARCH_X86) + /* + * This is mis-detected on some hardware / software combinations. + */ + llvm::StackAlignment = 4; + llvm::RealignStack = true; #endif - return 0; -} + /* Same as LLVMInitializeNativeTarget(); */ + llvm::InitializeNativeTarget(); -#endif + LLVMLinkInJIT(); +} /* @@ -69,7 +64,6 @@ LLVMInitializeNativeTarget(void) */ #if defined(_MSC_VER) && defined(_DEBUG) #include <crtdefs.h> -extern "C" { - _CRTIMP void __cdecl _invalid_parameter_noinfo(void) {} -} +extern "C" _CRTIMP void __cdecl +_invalid_parameter_noinfo(void) {} #endif diff --git a/src/gallium/auxiliary/gallivm/lp_bld_misc.h b/src/gallium/auxiliary/gallivm/lp_bld_init.h index 0e787e0b9c..07f50d1c43 100644 --- a/src/gallium/auxiliary/gallivm/lp_bld_misc.h +++ b/src/gallium/auxiliary/gallivm/lp_bld_init.h @@ -26,26 +26,17 @@ **************************************************************************/ -#ifndef LP_BLD_MISC_H -#define LP_BLD_MISC_H +#ifndef LP_BLD_INIT_H +#define LP_BLD_INIT_H -#include "llvm/Config/config.h" - #ifdef __cplusplus extern "C" { #endif -#ifndef LLVM_NATIVE_ARCH - void -LLVMLinkInJIT(void); - -int -LLVMInitializeNativeTarget(void); - -#endif /* !LLVM_NATIVE_ARCH */ +lp_build_init(void); #ifdef __cplusplus @@ -53,4 +44,4 @@ LLVMInitializeNativeTarget(void); #endif -#endif /* !LP_BLD_MISC_H */ +#endif /* !LP_BLD_INIT_H */ diff --git a/src/gallium/auxiliary/gallivm/lp_bld_logic.c b/src/gallium/auxiliary/gallivm/lp_bld_logic.c index 41ac81b744..2726747eae 100644 --- a/src/gallium/auxiliary/gallivm/lp_bld_logic.c +++ b/src/gallium/auxiliary/gallivm/lp_bld_logic.c @@ -45,6 +45,7 @@ /** * Build code to compare two values 'a' and 'b' of 'type' using the given func. * \param func one of PIPE_FUNC_x + * The result values will be 0 for false or ~0 for true. */ LLVMValueRef lp_build_compare(LLVMBuilderRef builder, @@ -311,6 +312,7 @@ lp_build_compare(LLVMBuilderRef builder, /** * Build code to compare two values 'a' and 'b' using the given func. * \param func one of PIPE_FUNC_x + * The result values will be 0 for false or ~0 for true. */ LLVMValueRef lp_build_cmp(struct lp_build_context *bld, @@ -322,6 +324,9 @@ lp_build_cmp(struct lp_build_context *bld, } +/** + * Return mask ? a : b; + */ LLVMValueRef lp_build_select(struct lp_build_context *bld, LLVMValueRef mask, diff --git a/src/gallium/auxiliary/gallivm/lp_bld_pack.c b/src/gallium/auxiliary/gallivm/lp_bld_pack.c index bc360ad77a..4c61d10749 100644 --- a/src/gallium/auxiliary/gallivm/lp_bld_pack.c +++ b/src/gallium/auxiliary/gallivm/lp_bld_pack.c @@ -256,7 +256,9 @@ lp_build_pack2(LLVMBuilderRef builder, LLVMValueRef lo, LLVMValueRef hi) { +#if !(HAVE_LLVM >= 0x0207) LLVMTypeRef src_vec_type = lp_build_vec_type(src_type); +#endif LLVMTypeRef dst_vec_type = lp_build_vec_type(dst_type); LLVMValueRef shuffle; LLVMValueRef res; @@ -272,11 +274,14 @@ lp_build_pack2(LLVMBuilderRef builder, switch(src_type.width) { case 32: if(dst_type.sign) { +#if HAVE_LLVM >= 0x0207 + res = lp_build_intrinsic_binary(builder, "llvm.x86.sse2.packssdw.128", dst_vec_type, lo, hi); +#else res = lp_build_intrinsic_binary(builder, "llvm.x86.sse2.packssdw.128", src_vec_type, lo, hi); +#endif } else { if (util_cpu_caps.has_sse4_1) { - /* PACKUSDW is the only instrinsic with a consistent signature */ return lp_build_intrinsic_binary(builder, "llvm.x86.sse41.packusdw", dst_vec_type, lo, hi); } else { @@ -288,9 +293,17 @@ lp_build_pack2(LLVMBuilderRef builder, case 16: if(dst_type.sign) +#if HAVE_LLVM >= 0x0207 + res = lp_build_intrinsic_binary(builder, "llvm.x86.sse2.packsswb.128", dst_vec_type, lo, hi); +#else res = lp_build_intrinsic_binary(builder, "llvm.x86.sse2.packsswb.128", src_vec_type, lo, hi); +#endif else +#if HAVE_LLVM >= 0x0207 + res = lp_build_intrinsic_binary(builder, "llvm.x86.sse2.packuswb.128", dst_vec_type, lo, hi); +#else res = lp_build_intrinsic_binary(builder, "llvm.x86.sse2.packuswb.128", src_vec_type, lo, hi); +#endif break; default: diff --git a/src/gallium/auxiliary/gallivm/lp_bld_sample.c b/src/gallium/auxiliary/gallivm/lp_bld_sample.c index a133b56ac5..29cadcc15a 100644 --- a/src/gallium/auxiliary/gallivm/lp_bld_sample.c +++ b/src/gallium/auxiliary/gallivm/lp_bld_sample.c @@ -44,6 +44,11 @@ #include "lp_bld_sample.h" +/** + * Initialize lp_sampler_static_state object with the gallium sampler + * and texture state. + * The former is considered to be static and the later dynamic. + */ void lp_sampler_static_state(struct lp_sampler_static_state *state, const struct pipe_texture *texture, @@ -57,6 +62,18 @@ lp_sampler_static_state(struct lp_sampler_static_state *state, if(!sampler) return; + /* + * We don't copy sampler state over unless it is actually enabled, to avoid + * spurious recompiles, as the sampler static state is part of the shader + * key. + * + * Ideally the state tracker or cso_cache module would make all state + * canonical, but until that happens it's better to be safe than sorry here. + * + * XXX: Actually there's much more than can be done here, especially + * regarding 1D/2D/3D/CUBE textures, wrap modes, etc. + */ + state->format = texture->format; state->target = texture->target; state->pot_width = util_is_pot(texture->width0); @@ -69,11 +86,20 @@ lp_sampler_static_state(struct lp_sampler_static_state *state, state->min_img_filter = sampler->min_img_filter; state->min_mip_filter = sampler->min_mip_filter; state->mag_img_filter = sampler->mag_img_filter; + state->compare_mode = sampler->compare_mode; - if(sampler->compare_mode != PIPE_TEX_COMPARE_NONE) { - state->compare_func = sampler->compare_func; + if (sampler->compare_mode != PIPE_TEX_COMPARE_NONE) { + state->compare_func = sampler->compare_func; } + state->normalized_coords = sampler->normalized_coords; + state->lod_bias = sampler->lod_bias; + state->min_lod = sampler->min_lod; + state->max_lod = sampler->max_lod; + state->border_color[0] = sampler->border_color[0]; + state->border_color[1] = sampler->border_color[1]; + state->border_color[2] = sampler->border_color[2]; + state->border_color[3] = sampler->border_color[3]; } diff --git a/src/gallium/auxiliary/gallivm/lp_bld_sample.h b/src/gallium/auxiliary/gallivm/lp_bld_sample.h index 39edcf13d1..5ba0925bb6 100644 --- a/src/gallium/auxiliary/gallivm/lp_bld_sample.h +++ b/src/gallium/auxiliary/gallivm/lp_bld_sample.h @@ -70,6 +70,8 @@ struct lp_sampler_static_state unsigned compare_mode:1; unsigned compare_func:3; unsigned normalized_coords:1; + float lod_bias, min_lod, max_lod; + float border_color[4]; }; @@ -98,6 +100,18 @@ struct lp_sampler_dynamic_state LLVMBuilderRef builder, unsigned unit); + /** Obtain the base texture depth. */ + LLVMValueRef + (*depth)( struct lp_sampler_dynamic_state *state, + LLVMBuilderRef builder, + unsigned unit); + + /** Obtain the number of mipmap levels (minus one). */ + LLVMValueRef + (*last_level)( struct lp_sampler_dynamic_state *state, + LLVMBuilderRef builder, + unsigned unit); + LLVMValueRef (*stride)( struct lp_sampler_dynamic_state *state, LLVMBuilderRef builder, diff --git a/src/gallium/auxiliary/gallivm/lp_bld_sample_soa.c b/src/gallium/auxiliary/gallivm/lp_bld_sample_soa.c index e268862282..bc2f307c33 100644 --- a/src/gallium/auxiliary/gallivm/lp_bld_sample_soa.c +++ b/src/gallium/auxiliary/gallivm/lp_bld_sample_soa.c @@ -69,7 +69,11 @@ struct lp_build_sample_context struct lp_type coord_type; struct lp_build_context coord_bld; - /** Integer coordinates */ + /** Unsigned integer coordinates */ + struct lp_type uint_coord_type; + struct lp_build_context uint_coord_bld; + + /** Signed integer coordinates */ struct lp_type int_coord_type; struct lp_build_context int_coord_bld; @@ -79,18 +83,93 @@ struct lp_build_sample_context }; +/** + * Does the given texture wrap mode allow sampling the texture border color? + * XXX maybe move this into gallium util code. + */ +static boolean +wrap_mode_uses_border_color(unsigned mode) +{ + switch (mode) { + case PIPE_TEX_WRAP_REPEAT: + case PIPE_TEX_WRAP_CLAMP_TO_EDGE: + case PIPE_TEX_WRAP_MIRROR_REPEAT: + case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE: + return FALSE; + case PIPE_TEX_WRAP_CLAMP: + case PIPE_TEX_WRAP_CLAMP_TO_BORDER: + case PIPE_TEX_WRAP_MIRROR_CLAMP: + case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER: + return TRUE; + default: + assert(0 && "unexpected wrap mode"); + return FALSE; + } +} + + + +/** + * Gen code to fetch a texel from a texture at int coords (x, y). + * The result, texel, will be: + * texel[0] = red values + * texel[1] = green values + * texel[2] = blue values + * texel[3] = alpha values + */ static void lp_build_sample_texel_soa(struct lp_build_sample_context *bld, + LLVMValueRef width, + LLVMValueRef height, LLVMValueRef x, LLVMValueRef y, LLVMValueRef y_stride, LLVMValueRef data_ptr, LLVMValueRef *texel) { + struct lp_build_context *int_coord_bld = &bld->int_coord_bld; LLVMValueRef offset; LLVMValueRef packed; + LLVMValueRef use_border = NULL; + + /* use_border = x < 0 || x >= width || y < 0 || y >= height */ + if (wrap_mode_uses_border_color(bld->static_state->wrap_s)) { + LLVMValueRef b1, b2; + b1 = lp_build_cmp(int_coord_bld, PIPE_FUNC_LESS, x, int_coord_bld->zero); + b2 = lp_build_cmp(int_coord_bld, PIPE_FUNC_GEQUAL, x, width); + use_border = LLVMBuildOr(bld->builder, b1, b2, "b1_or_b2"); + } - offset = lp_build_sample_offset(&bld->int_coord_bld, + if (wrap_mode_uses_border_color(bld->static_state->wrap_t)) { + LLVMValueRef b1, b2; + b1 = lp_build_cmp(int_coord_bld, PIPE_FUNC_LESS, y, int_coord_bld->zero); + b2 = lp_build_cmp(int_coord_bld, PIPE_FUNC_GEQUAL, y, height); + if (use_border) { + use_border = LLVMBuildOr(bld->builder, use_border, b1, "ub_or_b1"); + use_border = LLVMBuildOr(bld->builder, use_border, b2, "ub_or_b2"); + } + else { + use_border = LLVMBuildOr(bld->builder, b1, b2, "b1_or_b2"); + } + } + + /* + * Note: if we find an app which frequently samples the texture border + * we might want to implement a true conditional here to avoid sampling + * the texture whenever possible (since that's quite a bit of code). + * Ex: + * if (use_border) { + * texel = border_color; + * } + * else { + * texel = sample_texture(coord); + * } + * As it is now, we always sample the texture, then selectively replace + * the texel color results with the border color. + */ + + /* convert x,y coords to linear offset from start of texture, in bytes */ + offset = lp_build_sample_offset(&bld->uint_coord_bld, bld->format_desc, x, y, y_stride, data_ptr); @@ -99,16 +178,30 @@ lp_build_sample_texel_soa(struct lp_build_sample_context *bld, assert(bld->format_desc->block.height == 1); assert(bld->format_desc->block.bits <= bld->texel_type.width); + /* gather the texels from the texture */ packed = lp_build_gather(bld->builder, bld->texel_type.length, bld->format_desc->block.bits, bld->texel_type.width, data_ptr, offset); + /* convert texels to float rgba */ lp_build_unpack_rgba_soa(bld->builder, bld->format_desc, bld->texel_type, packed, texel); + + if (use_border) { + /* select texel color or border color depending on use_border */ + int chan; + for (chan = 0; chan < 4; chan++) { + LLVMValueRef border_chan = + lp_build_const_scalar(bld->texel_type, + bld->static_state->border_color[chan]); + texel[chan] = lp_build_select(&bld->texel_bld, use_border, + border_chan, texel[chan]); + } + } } @@ -121,7 +214,7 @@ lp_build_sample_packed(struct lp_build_sample_context *bld, { LLVMValueRef offset; - offset = lp_build_sample_offset(&bld->int_coord_bld, + offset = lp_build_sample_offset(&bld->uint_coord_bld, bld->format_desc, x, y, y_stride, data_ptr); @@ -138,17 +231,77 @@ lp_build_sample_packed(struct lp_build_sample_context *bld, } +/** + * Helper to compute the mirror function for the PIPE_WRAP_MIRROR modes. + */ +static LLVMValueRef +lp_build_coord_mirror(struct lp_build_sample_context *bld, + LLVMValueRef coord) +{ + struct lp_build_context *coord_bld = &bld->coord_bld; + struct lp_build_context *int_coord_bld = &bld->int_coord_bld; + LLVMValueRef fract, flr, isOdd; + + /* fract = coord - floor(coord) */ + fract = lp_build_sub(coord_bld, coord, lp_build_floor(coord_bld, coord)); + + /* flr = ifloor(coord); */ + flr = lp_build_ifloor(coord_bld, coord); + + /* isOdd = flr & 1 */ + isOdd = LLVMBuildAnd(bld->builder, flr, int_coord_bld->one, ""); + + /* make coord positive or negative depending on isOdd */ + coord = lp_build_set_sign(coord_bld, fract, isOdd); + + /* convert isOdd to float */ + isOdd = lp_build_int_to_float(coord_bld, isOdd); + + /* add isOdd to coord */ + coord = lp_build_add(coord_bld, coord, isOdd); + + return coord; +} + + +/** + * We only support a few wrap modes in lp_build_sample_wrap_int() at this time. + * Return whether the given mode is supported by that function. + */ +static boolean +is_simple_wrap_mode(unsigned mode) +{ + switch (mode) { + case PIPE_TEX_WRAP_REPEAT: + case PIPE_TEX_WRAP_CLAMP: + case PIPE_TEX_WRAP_CLAMP_TO_EDGE: + return TRUE; + case PIPE_TEX_WRAP_CLAMP_TO_BORDER: + default: + return FALSE; + } +} + + +/** + * Build LLVM code for texture wrap mode, for scaled integer texcoords. + * \param coord the incoming texcoord (s,t,r or q) scaled to the texture size + * \param length the texture size along one dimension + * \param is_pot if TRUE, length is a power of two + * \param wrap_mode one of PIPE_TEX_WRAP_x + */ static LLVMValueRef -lp_build_sample_wrap(struct lp_build_sample_context *bld, - LLVMValueRef coord, - LLVMValueRef length, - boolean is_pot, - unsigned wrap_mode) +lp_build_sample_wrap_int(struct lp_build_sample_context *bld, + LLVMValueRef coord, + LLVMValueRef length, + boolean is_pot, + unsigned wrap_mode) { + struct lp_build_context *uint_coord_bld = &bld->uint_coord_bld; struct lp_build_context *int_coord_bld = &bld->int_coord_bld; LLVMValueRef length_minus_one; - length_minus_one = lp_build_sub(int_coord_bld, length, int_coord_bld->one); + length_minus_one = lp_build_sub(uint_coord_bld, length, uint_coord_bld->one); switch(wrap_mode) { case PIPE_TEX_WRAP_REPEAT: @@ -161,12 +314,12 @@ lp_build_sample_wrap(struct lp_build_sample_context *bld, break; case PIPE_TEX_WRAP_CLAMP: + case PIPE_TEX_WRAP_CLAMP_TO_EDGE: + case PIPE_TEX_WRAP_CLAMP_TO_BORDER: coord = lp_build_max(int_coord_bld, coord, int_coord_bld->zero); coord = lp_build_min(int_coord_bld, coord, length_minus_one); break; - case PIPE_TEX_WRAP_CLAMP_TO_EDGE: - case PIPE_TEX_WRAP_CLAMP_TO_BORDER: case PIPE_TEX_WRAP_MIRROR_REPEAT: case PIPE_TEX_WRAP_MIRROR_CLAMP: case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE: @@ -174,8 +327,8 @@ lp_build_sample_wrap(struct lp_build_sample_context *bld, /* FIXME */ _debug_printf("llvmpipe: failed to translate texture wrap mode %s\n", util_dump_tex_wrap(wrap_mode, TRUE)); - coord = lp_build_max(int_coord_bld, coord, int_coord_bld->zero); - coord = lp_build_min(int_coord_bld, coord, length_minus_one); + coord = lp_build_max(uint_coord_bld, coord, uint_coord_bld->zero); + coord = lp_build_min(uint_coord_bld, coord, length_minus_one); break; default: @@ -186,6 +339,376 @@ lp_build_sample_wrap(struct lp_build_sample_context *bld, } +/** + * Build LLVM code for texture wrap mode for linear filtering. + * \param x0_out returns first integer texcoord + * \param x1_out returns second integer texcoord + * \param weight_out returns linear interpolation weight + */ +static void +lp_build_sample_wrap_linear(struct lp_build_sample_context *bld, + LLVMValueRef coord, + LLVMValueRef length, + boolean is_pot, + unsigned wrap_mode, + LLVMValueRef *x0_out, + LLVMValueRef *x1_out, + LLVMValueRef *weight_out) +{ + struct lp_build_context *coord_bld = &bld->coord_bld; + struct lp_build_context *int_coord_bld = &bld->int_coord_bld; + struct lp_build_context *uint_coord_bld = &bld->uint_coord_bld; + LLVMValueRef two = lp_build_const_scalar(coord_bld->type, 2.0); + LLVMValueRef half = lp_build_const_scalar(coord_bld->type, 0.5); + LLVMValueRef length_f = lp_build_int_to_float(coord_bld, length); + LLVMValueRef length_minus_one = lp_build_sub(uint_coord_bld, length, uint_coord_bld->one); + LLVMValueRef length_f_minus_one = lp_build_sub(coord_bld, length_f, coord_bld->one); + LLVMValueRef coord0, coord1, weight; + + switch(wrap_mode) { + case PIPE_TEX_WRAP_REPEAT: + /* mul by size and subtract 0.5 */ + coord = lp_build_mul(coord_bld, coord, length_f); + coord = lp_build_sub(coord_bld, coord, half); + /* convert to int */ + coord0 = lp_build_ifloor(coord_bld, coord); + coord1 = lp_build_add(uint_coord_bld, coord0, uint_coord_bld->one); + /* compute lerp weight */ + weight = lp_build_fract(coord_bld, coord); + /* repeat wrap */ + if (is_pot) { + coord0 = LLVMBuildAnd(bld->builder, coord0, length_minus_one, ""); + coord1 = LLVMBuildAnd(bld->builder, coord1, length_minus_one, ""); + } + else { + /* Signed remainder won't give the right results for negative + * dividends but unsigned remainder does.*/ + coord0 = LLVMBuildURem(bld->builder, coord0, length, ""); + coord1 = LLVMBuildURem(bld->builder, coord1, length, ""); + } + break; + + case PIPE_TEX_WRAP_CLAMP: + if (bld->static_state->normalized_coords) { + coord = lp_build_mul(coord_bld, coord, length_f); + } + weight = lp_build_fract(coord_bld, coord); + coord0 = lp_build_clamp(coord_bld, coord, coord_bld->zero, + length_f_minus_one); + coord1 = lp_build_add(coord_bld, coord, coord_bld->one); + coord1 = lp_build_clamp(coord_bld, coord1, coord_bld->zero, + length_f_minus_one); + coord0 = lp_build_ifloor(coord_bld, coord0); + coord1 = lp_build_ifloor(coord_bld, coord1); + break; + + case PIPE_TEX_WRAP_CLAMP_TO_EDGE: + if (bld->static_state->normalized_coords) { + /* clamp to [0,1] */ + coord = lp_build_clamp(coord_bld, coord, coord_bld->zero, coord_bld->one); + /* mul by tex size and subtract 0.5 */ + coord = lp_build_mul(coord_bld, coord, length_f); + coord = lp_build_sub(coord_bld, coord, half); + } + else { + LLVMValueRef min, max; + /* clamp to [0.5, length - 0.5] */ + min = lp_build_const_scalar(coord_bld->type, 0.5F); + max = lp_build_sub(coord_bld, length_f, min); + coord = lp_build_clamp(coord_bld, coord, min, max); + } + /* compute lerp weight */ + weight = lp_build_fract(coord_bld, coord); + /* coord0 = floor(coord); */ + coord0 = lp_build_ifloor(coord_bld, coord); + coord1 = lp_build_add(int_coord_bld, coord0, int_coord_bld->one); + /* coord0 = max(coord0, 0) */ + coord0 = lp_build_max(int_coord_bld, coord0, int_coord_bld->zero); + /* coord1 = min(coord1, length-1) */ + coord1 = lp_build_min(int_coord_bld, coord1, length_minus_one); + break; + + case PIPE_TEX_WRAP_CLAMP_TO_BORDER: + { + LLVMValueRef min, max; + if (bld->static_state->normalized_coords) { + /* min = -1.0 / (2 * length) = -0.5 / length */ + min = lp_build_mul(coord_bld, + lp_build_const_scalar(coord_bld->type, -0.5F), + lp_build_rcp(coord_bld, length_f)); + /* max = 1.0 - min */ + max = lp_build_sub(coord_bld, coord_bld->one, min); + /* coord = clamp(coord, min, max) */ + coord = lp_build_clamp(coord_bld, coord, min, max); + /* scale coord to length (and sub 0.5?) */ + coord = lp_build_mul(coord_bld, coord, length_f); + coord = lp_build_sub(coord_bld, coord, half); + } + else { + /* clamp to [-0.5, length + 0.5] */ + min = lp_build_const_scalar(coord_bld->type, -0.5F); + max = lp_build_sub(coord_bld, length_f, min); + coord = lp_build_clamp(coord_bld, coord, min, max); + coord = lp_build_sub(coord_bld, coord, half); + } + /* compute lerp weight */ + weight = lp_build_fract(coord_bld, coord); + /* convert to int */ + coord0 = lp_build_ifloor(coord_bld, coord); + coord1 = lp_build_add(int_coord_bld, coord0, int_coord_bld->one); + } + break; + + case PIPE_TEX_WRAP_MIRROR_REPEAT: + /* compute mirror function */ + coord = lp_build_coord_mirror(bld, coord); + + /* scale coord to length */ + coord = lp_build_mul(coord_bld, coord, length_f); + coord = lp_build_sub(coord_bld, coord, half); + + /* compute lerp weight */ + weight = lp_build_fract(coord_bld, coord); + + /* convert to int coords */ + coord0 = lp_build_ifloor(coord_bld, coord); + coord1 = lp_build_add(int_coord_bld, coord0, int_coord_bld->one); + + /* coord0 = max(coord0, 0) */ + coord0 = lp_build_max(int_coord_bld, coord0, int_coord_bld->zero); + /* coord1 = min(coord1, length-1) */ + coord1 = lp_build_min(int_coord_bld, coord1, length_minus_one); + break; + + case PIPE_TEX_WRAP_MIRROR_CLAMP: + { + LLVMValueRef min, max; + /* min = 1.0 / (2 * length) */ + min = lp_build_rcp(coord_bld, lp_build_mul(coord_bld, two, length_f)); + /* max = 1.0 - min */ + max = lp_build_sub(coord_bld, coord_bld->one, min); + + coord = lp_build_abs(coord_bld, coord); + coord = lp_build_clamp(coord_bld, coord, min, max); + coord = lp_build_mul(coord_bld, coord, length_f); + if(0)coord = lp_build_sub(coord_bld, coord, half); + weight = lp_build_fract(coord_bld, coord); + coord0 = lp_build_ifloor(coord_bld, coord); + coord1 = lp_build_add(int_coord_bld, coord0, int_coord_bld->one); + } + break; + + case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE: + { + LLVMValueRef min, max; + /* min = 1.0 / (2 * length) */ + min = lp_build_rcp(coord_bld, lp_build_mul(coord_bld, two, length_f)); + /* max = 1.0 - min */ + max = lp_build_sub(coord_bld, coord_bld->one, min); + + coord = lp_build_abs(coord_bld, coord); + coord = lp_build_clamp(coord_bld, coord, min, max); + coord = lp_build_mul(coord_bld, coord, length_f); + coord = lp_build_sub(coord_bld, coord, half); + weight = lp_build_fract(coord_bld, coord); + coord0 = lp_build_ifloor(coord_bld, coord); + coord1 = lp_build_add(int_coord_bld, coord0, int_coord_bld->one); + } + break; + + case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER: + { + LLVMValueRef min, max; + /* min = -1.0 / (2 * length) = -0.5 / length */ + min = lp_build_mul(coord_bld, + lp_build_const_scalar(coord_bld->type, -0.5F), + lp_build_rcp(coord_bld, length_f)); + /* max = 1.0 - min */ + max = lp_build_sub(coord_bld, coord_bld->one, min); + + coord = lp_build_abs(coord_bld, coord); + coord = lp_build_clamp(coord_bld, coord, min, max); + coord = lp_build_mul(coord_bld, coord, length_f); + coord = lp_build_sub(coord_bld, coord, half); + weight = lp_build_fract(coord_bld, coord); + coord0 = lp_build_ifloor(coord_bld, coord); + coord1 = lp_build_add(int_coord_bld, coord0, int_coord_bld->one); + } + break; + + default: + assert(0); + } + + *x0_out = coord0; + *x1_out = coord1; + *weight_out = weight; +} + + +/** + * Build LLVM code for texture wrap mode for nearest filtering. + * \param coord the incoming texcoord (nominally in [0,1]) + * \param length the texture size along one dimension, as int + * \param is_pot if TRUE, length is a power of two + * \param wrap_mode one of PIPE_TEX_WRAP_x + */ +static LLVMValueRef +lp_build_sample_wrap_nearest(struct lp_build_sample_context *bld, + LLVMValueRef coord, + LLVMValueRef length, + boolean is_pot, + unsigned wrap_mode) +{ + struct lp_build_context *coord_bld = &bld->coord_bld; + struct lp_build_context *int_coord_bld = &bld->int_coord_bld; + struct lp_build_context *uint_coord_bld = &bld->uint_coord_bld; + LLVMValueRef two = lp_build_const_scalar(coord_bld->type, 2.0); + LLVMValueRef length_f = lp_build_int_to_float(coord_bld, length); + LLVMValueRef length_minus_one = lp_build_sub(uint_coord_bld, length, uint_coord_bld->one); + LLVMValueRef length_f_minus_one = lp_build_sub(coord_bld, length_f, coord_bld->one); + LLVMValueRef icoord; + + switch(wrap_mode) { + case PIPE_TEX_WRAP_REPEAT: + coord = lp_build_mul(coord_bld, coord, length_f); + icoord = lp_build_ifloor(coord_bld, coord); + if (is_pot) + icoord = LLVMBuildAnd(bld->builder, icoord, length_minus_one, ""); + else + /* Signed remainder won't give the right results for negative + * dividends but unsigned remainder does.*/ + icoord = LLVMBuildURem(bld->builder, icoord, length, ""); + break; + + case PIPE_TEX_WRAP_CLAMP: + /* mul by size */ + if (bld->static_state->normalized_coords) { + coord = lp_build_mul(coord_bld, coord, length_f); + } + /* floor */ + icoord = lp_build_ifloor(coord_bld, coord); + /* clamp to [0, size-1]. Note: int coord builder type */ + icoord = lp_build_clamp(int_coord_bld, icoord, int_coord_bld->zero, + length_minus_one); + break; + + case PIPE_TEX_WRAP_CLAMP_TO_EDGE: + { + LLVMValueRef min, max; + if (bld->static_state->normalized_coords) { + /* min = 1.0 / (2 * length) */ + min = lp_build_rcp(coord_bld, lp_build_mul(coord_bld, two, length_f)); + /* max = length - min */ + max = lp_build_sub(coord_bld, length_f, min); + /* scale coord to length */ + coord = lp_build_mul(coord_bld, coord, length_f); + } + else { + /* clamp to [0.5, length - 0.5] */ + min = lp_build_const_scalar(coord_bld->type, 0.5F); + max = lp_build_sub(coord_bld, length_f, min); + } + /* coord = clamp(coord, min, max) */ + coord = lp_build_clamp(coord_bld, coord, min, max); + icoord = lp_build_ifloor(coord_bld, coord); + } + break; + + case PIPE_TEX_WRAP_CLAMP_TO_BORDER: + /* Note: this is the same as CLAMP_TO_EDGE, except min = -min */ + { + LLVMValueRef min, max; + if (bld->static_state->normalized_coords) { + /* min = -1.0 / (2 * length) = -0.5 / length */ + min = lp_build_mul(coord_bld, + lp_build_const_scalar(coord_bld->type, -0.5F), + lp_build_rcp(coord_bld, length_f)); + /* max = length - min */ + max = lp_build_sub(coord_bld, length_f, min); + /* scale coord to length */ + coord = lp_build_mul(coord_bld, coord, length_f); + } + else { + /* clamp to [-0.5, length + 0.5] */ + min = lp_build_const_scalar(coord_bld->type, -0.5F); + max = lp_build_sub(coord_bld, length_f, min); + } + /* coord = clamp(coord, min, max) */ + coord = lp_build_clamp(coord_bld, coord, min, max); + icoord = lp_build_ifloor(coord_bld, coord); + } + break; + + case PIPE_TEX_WRAP_MIRROR_REPEAT: + { + LLVMValueRef min, max; + /* min = 1.0 / (2 * length) */ + min = lp_build_rcp(coord_bld, lp_build_mul(coord_bld, two, length_f)); + /* max = length - min */ + max = lp_build_sub(coord_bld, length_f, min); + + /* compute mirror function */ + coord = lp_build_coord_mirror(bld, coord); + + /* scale coord to length */ + coord = lp_build_mul(coord_bld, coord, length_f); + + /* coord = clamp(coord, min, max) */ + coord = lp_build_clamp(coord_bld, coord, min, max); + icoord = lp_build_ifloor(coord_bld, coord); + } + break; + + case PIPE_TEX_WRAP_MIRROR_CLAMP: + coord = lp_build_abs(coord_bld, coord); + coord = lp_build_mul(coord_bld, coord, length_f); + coord = lp_build_clamp(coord_bld, coord, coord_bld->zero, length_f_minus_one); + icoord = lp_build_ifloor(coord_bld, coord); + break; + + case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE: + { + LLVMValueRef min, max; + /* min = 1.0 / (2 * length) */ + min = lp_build_rcp(coord_bld, lp_build_mul(coord_bld, two, length_f)); + /* max = length - min */ + max = lp_build_sub(coord_bld, length_f, min); + + coord = lp_build_abs(coord_bld, coord); + coord = lp_build_mul(coord_bld, coord, length_f); + coord = lp_build_clamp(coord_bld, coord, min, max); + icoord = lp_build_ifloor(coord_bld, coord); + } + break; + + case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER: + { + LLVMValueRef min, max; + /* min = 1.0 / (2 * length) */ + min = lp_build_rcp(coord_bld, lp_build_mul(coord_bld, two, length_f)); + min = lp_build_negate(coord_bld, min); + /* max = length - min */ + max = lp_build_sub(coord_bld, length_f, min); + + coord = lp_build_abs(coord_bld, coord); + coord = lp_build_mul(coord_bld, coord, length_f); + coord = lp_build_clamp(coord_bld, coord, min, max); + icoord = lp_build_ifloor(coord_bld, coord); + } + break; + + default: + assert(0); + } + + return icoord; +} + + +/** + * Sample 2D texture with nearest filtering. + */ static void lp_build_sample_2d_nearest_soa(struct lp_build_sample_context *bld, LLVMValueRef s, @@ -196,23 +719,25 @@ lp_build_sample_2d_nearest_soa(struct lp_build_sample_context *bld, LLVMValueRef data_ptr, LLVMValueRef *texel) { - LLVMValueRef x; - LLVMValueRef y; + LLVMValueRef x, y; - x = lp_build_ifloor(&bld->coord_bld, s); - y = lp_build_ifloor(&bld->coord_bld, t); - lp_build_name(x, "tex.x.floor"); - lp_build_name(y, "tex.y.floor"); + x = lp_build_sample_wrap_nearest(bld, s, width, + bld->static_state->pot_width, + bld->static_state->wrap_s); + y = lp_build_sample_wrap_nearest(bld, t, height, + bld->static_state->pot_height, + bld->static_state->wrap_t); - x = lp_build_sample_wrap(bld, x, width, bld->static_state->pot_width, bld->static_state->wrap_s); - y = lp_build_sample_wrap(bld, y, height, bld->static_state->pot_height, bld->static_state->wrap_t); lp_build_name(x, "tex.x.wrapped"); lp_build_name(y, "tex.y.wrapped"); - lp_build_sample_texel_soa(bld, x, y, stride, data_ptr, texel); + lp_build_sample_texel_soa(bld, width, height, x, y, stride, data_ptr, texel); } +/** + * Sample 2D texture with bilinear filtering. + */ static void lp_build_sample_2d_linear_soa(struct lp_build_sample_context *bld, LLVMValueRef s, @@ -223,9 +748,6 @@ lp_build_sample_2d_linear_soa(struct lp_build_sample_context *bld, LLVMValueRef data_ptr, LLVMValueRef *texel) { - LLVMValueRef half; - LLVMValueRef s_ipart; - LLVMValueRef t_ipart; LLVMValueRef s_fpart; LLVMValueRef t_fpart; LLVMValueRef x0, x1; @@ -233,32 +755,15 @@ lp_build_sample_2d_linear_soa(struct lp_build_sample_context *bld, LLVMValueRef neighbors[2][2][4]; unsigned chan; - half = lp_build_const_scalar(bld->coord_type, 0.5); - s = lp_build_sub(&bld->coord_bld, s, half); - t = lp_build_sub(&bld->coord_bld, t, half); - - s_ipart = lp_build_floor(&bld->coord_bld, s); - t_ipart = lp_build_floor(&bld->coord_bld, t); - - s_fpart = lp_build_sub(&bld->coord_bld, s, s_ipart); - t_fpart = lp_build_sub(&bld->coord_bld, t, t_ipart); + lp_build_sample_wrap_linear(bld, s, width, bld->static_state->pot_width, + bld->static_state->wrap_s, &x0, &x1, &s_fpart); + lp_build_sample_wrap_linear(bld, t, height, bld->static_state->pot_height, + bld->static_state->wrap_t, &y0, &y1, &t_fpart); - x0 = lp_build_itrunc(&bld->coord_bld, s_ipart); - y0 = lp_build_itrunc(&bld->coord_bld, t_ipart); - - x0 = lp_build_sample_wrap(bld, x0, width, bld->static_state->pot_width, bld->static_state->wrap_s); - y0 = lp_build_sample_wrap(bld, y0, height, bld->static_state->pot_height, bld->static_state->wrap_t); - - x1 = lp_build_add(&bld->int_coord_bld, x0, bld->int_coord_bld.one); - y1 = lp_build_add(&bld->int_coord_bld, y0, bld->int_coord_bld.one); - - x1 = lp_build_sample_wrap(bld, x1, width, bld->static_state->pot_width, bld->static_state->wrap_s); - y1 = lp_build_sample_wrap(bld, y1, height, bld->static_state->pot_height, bld->static_state->wrap_t); - - lp_build_sample_texel_soa(bld, x0, y0, stride, data_ptr, neighbors[0][0]); - lp_build_sample_texel_soa(bld, x1, y0, stride, data_ptr, neighbors[0][1]); - lp_build_sample_texel_soa(bld, x0, y1, stride, data_ptr, neighbors[1][0]); - lp_build_sample_texel_soa(bld, x1, y1, stride, data_ptr, neighbors[1][1]); + lp_build_sample_texel_soa(bld, width, height, x0, y0, stride, data_ptr, neighbors[0][0]); + lp_build_sample_texel_soa(bld, width, height, x1, y0, stride, data_ptr, neighbors[0][1]); + lp_build_sample_texel_soa(bld, width, height, x0, y1, stride, data_ptr, neighbors[1][0]); + lp_build_sample_texel_soa(bld, width, height, x1, y1, stride, data_ptr, neighbors[1][1]); /* TODO: Don't interpolate missing channels */ for(chan = 0; chan < 4; ++chan) { @@ -334,20 +839,33 @@ lp_build_sample_2d_linear_aos(struct lp_build_sample_context *bld, h16_vec_type = lp_build_vec_type(h16.type); u8n_vec_type = lp_build_vec_type(u8n.type); + if (bld->static_state->normalized_coords) { + LLVMTypeRef coord_vec_type = lp_build_vec_type(bld->coord_type); + LLVMValueRef fp_width = LLVMBuildSIToFP(bld->builder, width, coord_vec_type, ""); + LLVMValueRef fp_height = LLVMBuildSIToFP(bld->builder, height, coord_vec_type, ""); + s = lp_build_mul(&bld->coord_bld, s, fp_width); + t = lp_build_mul(&bld->coord_bld, t, fp_height); + } + + /* scale coords by 256 (8 fractional bits) */ s = lp_build_mul_imm(&bld->coord_bld, s, 256); t = lp_build_mul_imm(&bld->coord_bld, t, 256); + /* convert float to int */ s = LLVMBuildFPToSI(builder, s, i32_vec_type, ""); t = LLVMBuildFPToSI(builder, t, i32_vec_type, ""); + /* subtract 0.5 (add -128) */ i32_c128 = lp_build_int_const_scalar(i32.type, -128); s = LLVMBuildAdd(builder, s, i32_c128, ""); t = LLVMBuildAdd(builder, t, i32_c128, ""); + /* compute floor (shift right 8) */ i32_c8 = lp_build_int_const_scalar(i32.type, 8); s_ipart = LLVMBuildAShr(builder, s, i32_c8, ""); t_ipart = LLVMBuildAShr(builder, t, i32_c8, ""); + /* compute fractional part (AND with 0xff) */ i32_c255 = lp_build_int_const_scalar(i32.type, 255); s_fpart = LLVMBuildAnd(builder, s, i32_c255, ""); t_fpart = LLVMBuildAnd(builder, t, i32_c255, ""); @@ -355,14 +873,18 @@ lp_build_sample_2d_linear_aos(struct lp_build_sample_context *bld, x0 = s_ipart; y0 = t_ipart; - x0 = lp_build_sample_wrap(bld, x0, width, bld->static_state->pot_width, bld->static_state->wrap_s); - y0 = lp_build_sample_wrap(bld, y0, height, bld->static_state->pot_height, bld->static_state->wrap_t); - x1 = lp_build_add(&bld->int_coord_bld, x0, bld->int_coord_bld.one); y1 = lp_build_add(&bld->int_coord_bld, y0, bld->int_coord_bld.one); - x1 = lp_build_sample_wrap(bld, x1, width, bld->static_state->pot_width, bld->static_state->wrap_s); - y1 = lp_build_sample_wrap(bld, y1, height, bld->static_state->pot_height, bld->static_state->wrap_t); + x0 = lp_build_sample_wrap_int(bld, x0, width, bld->static_state->pot_width, + bld->static_state->wrap_s); + y0 = lp_build_sample_wrap_int(bld, y0, height, bld->static_state->pot_height, + bld->static_state->wrap_t); + + x1 = lp_build_sample_wrap_int(bld, x1, width, bld->static_state->pot_width, + bld->static_state->wrap_s); + y1 = lp_build_sample_wrap_int(bld, y1, height, bld->static_state->pot_height, + bld->static_state->wrap_t); /* * Transform 4 x i32 in @@ -518,6 +1040,195 @@ lp_build_sample_compare(struct lp_build_sample_context *bld, } +static int +texture_dims(enum pipe_texture_target tex) +{ + switch (tex) { + case PIPE_TEXTURE_1D: + return 1; + case PIPE_TEXTURE_2D: + case PIPE_TEXTURE_CUBE: + return 2; + case PIPE_TEXTURE_3D: + return 3; + default: + assert(0 && "bad texture target in texture_dims()"); + return 2; + } +} + + +/** + * Generate code to compute texture level of detail (lambda). + * \param s vector of texcoord s values + * \param t vector of texcoord t values + * \param r vector of texcoord r values + * \param width scalar int texture width + * \param height scalar int texture height + * \param depth scalar int texture depth + */ +static LLVMValueRef +lp_build_lod_selector(struct lp_build_sample_context *bld, + LLVMValueRef s, + LLVMValueRef t, + LLVMValueRef r, + LLVMValueRef width, + LLVMValueRef height, + LLVMValueRef depth) + +{ + const int dims = texture_dims(bld->static_state->target); + struct lp_build_context *coord_bld = &bld->coord_bld; + + LLVMValueRef lod_bias = lp_build_const_scalar(bld->coord_bld.type, + bld->static_state->lod_bias); + LLVMValueRef min_lod = lp_build_const_scalar(bld->coord_bld.type, + bld->static_state->min_lod); + LLVMValueRef max_lod = lp_build_const_scalar(bld->coord_bld.type, + bld->static_state->max_lod); + + LLVMValueRef index0 = LLVMConstInt(LLVMInt32Type(), 0, 0); + LLVMValueRef index1 = LLVMConstInt(LLVMInt32Type(), 1, 0); + LLVMValueRef index2 = LLVMConstInt(LLVMInt32Type(), 2, 0); + + LLVMValueRef s0, s1, s2; + LLVMValueRef t0, t1, t2; + LLVMValueRef r0, r1, r2; + LLVMValueRef dsdx, dsdy, dtdx, dtdy, drdx, drdy; + LLVMValueRef rho, lod; + + /* + * dsdx = abs(s[1] - s[0]); + * dsdy = abs(s[2] - s[0]); + * dtdx = abs(t[1] - t[0]); + * dtdy = abs(t[2] - t[0]); + * drdx = abs(r[1] - r[0]); + * drdy = abs(r[2] - r[0]); + * XXX we're assuming a four-element quad in 2x2 layout here. + */ + s0 = LLVMBuildExtractElement(bld->builder, s, index0, "s0"); + s1 = LLVMBuildExtractElement(bld->builder, s, index1, "s1"); + s2 = LLVMBuildExtractElement(bld->builder, s, index2, "s2"); + dsdx = lp_build_abs(coord_bld, lp_build_sub(coord_bld, s1, s0)); + dsdy = lp_build_abs(coord_bld, lp_build_sub(coord_bld, s2, s0)); + if (dims > 1) { + t0 = LLVMBuildExtractElement(bld->builder, t, index0, "t0"); + t1 = LLVMBuildExtractElement(bld->builder, t, index1, "t1"); + t2 = LLVMBuildExtractElement(bld->builder, t, index2, "t2"); + dtdx = lp_build_abs(coord_bld, lp_build_sub(coord_bld, t1, t0)); + dtdy = lp_build_abs(coord_bld, lp_build_sub(coord_bld, t2, t0)); + if (dims > 2) { + r0 = LLVMBuildExtractElement(bld->builder, r, index0, "r0"); + r1 = LLVMBuildExtractElement(bld->builder, r, index1, "r1"); + r2 = LLVMBuildExtractElement(bld->builder, r, index2, "r2"); + drdx = lp_build_abs(coord_bld, lp_build_sub(coord_bld, r1, r0)); + drdy = lp_build_abs(coord_bld, lp_build_sub(coord_bld, r2, r0)); + } + } + + /* Compute rho = max of all partial derivatives scaled by texture size. + * XXX this can be vectorized somewhat + */ + rho = lp_build_mul(coord_bld, + lp_build_max(coord_bld, dsdx, dsdy), + lp_build_int_to_float(coord_bld, width)); + if (dims > 1) { + LLVMValueRef max; + max = lp_build_mul(coord_bld, + lp_build_max(coord_bld, dtdx, dtdy), + lp_build_int_to_float(coord_bld, height)); + rho = lp_build_max(coord_bld, rho, max); + if (dims > 2) { + max = lp_build_mul(coord_bld, + lp_build_max(coord_bld, drdx, drdy), + lp_build_int_to_float(coord_bld, depth)); + rho = lp_build_max(coord_bld, rho, max); + } + } + + /* compute lod = log2(rho) */ + lod = lp_build_log2(coord_bld, rho); + + /* add lod bias */ + lod = lp_build_add(coord_bld, lod, lod_bias); + + /* clamp lod */ + lod = lp_build_clamp(coord_bld, lod, min_lod, max_lod); + + return lod; +} + + +/** + * For PIPE_TEX_MIPFILTER_NEAREST, convert float LOD to integer + * mipmap level index. + * \param lod scalar float texture level of detail + * \param level_out returns integer + */ +static void +lp_build_nearest_mip_level(struct lp_build_sample_context *bld, + unsigned unit, + LLVMValueRef lod, + LLVMValueRef *level_out) +{ + struct lp_build_context *coord_bld = &bld->coord_bld; + struct lp_build_context *int_coord_bld = &bld->int_coord_bld; + LLVMValueRef last_level, level; + + last_level = bld->dynamic_state->last_level(bld->dynamic_state, + bld->builder, unit); + + /* convert float lod to integer */ + level = lp_build_iround(coord_bld, lod); + + /* clamp level to legal range of levels */ + *level_out = lp_build_clamp(int_coord_bld, level, + int_coord_bld->zero, + last_level); +} + + +/** + * For PIPE_TEX_MIPFILTER_LINEAR, convert float LOD to integer to + * two (adjacent) mipmap level indexes. Later, we'll sample from those + * two mipmap levels and interpolate between them. + */ +static void +lp_build_linear_mip_levels(struct lp_build_sample_context *bld, + unsigned unit, + LLVMValueRef lod, + LLVMValueRef *level0_out, + LLVMValueRef *level1_out, + LLVMValueRef *weight_out) +{ + struct lp_build_context *coord_bld = &bld->coord_bld; + struct lp_build_context *int_coord_bld = &bld->int_coord_bld; + LLVMValueRef last_level, level; + + last_level = bld->dynamic_state->last_level(bld->dynamic_state, + bld->builder, unit); + + /* convert float lod to integer */ + level = lp_build_ifloor(coord_bld, lod); + + /* compute level 0 and clamp to legal range of levels */ + *level0_out = lp_build_clamp(int_coord_bld, level, + int_coord_bld->zero, + last_level); + /* compute level 1 and clamp to legal range of levels */ + *level1_out = lp_build_add(int_coord_bld, *level0_out, int_coord_bld->one); + *level1_out = lp_build_min(int_coord_bld, *level1_out, int_coord_bld->zero); + + *weight_out = lp_build_fract(coord_bld, lod); +} + + + +/** + * Build texture sampling code. + * 'texel' will return a vector of four LLVMValueRefs corresponding to + * R, G, B, A. + */ void lp_build_sample_soa(LLVMBuilderRef builder, const struct lp_sampler_static_state *static_state, @@ -536,7 +1247,11 @@ lp_build_sample_soa(LLVMBuilderRef builder, LLVMValueRef data_ptr; LLVMValueRef s; LLVMValueRef t; - LLVMValueRef p; + LLVMValueRef r; + + (void) lp_build_lod_selector; /* temporary to silence warning */ + (void) lp_build_nearest_mip_level; + (void) lp_build_linear_mip_levels; /* Setup our build context */ memset(&bld, 0, sizeof bld); @@ -545,9 +1260,11 @@ lp_build_sample_soa(LLVMBuilderRef builder, bld.dynamic_state = dynamic_state; bld.format_desc = util_format_description(static_state->format); bld.coord_type = type; + bld.uint_coord_type = lp_uint_type(type); bld.int_coord_type = lp_int_type(type); bld.texel_type = type; lp_build_context_init(&bld.coord_bld, builder, bld.coord_type); + lp_build_context_init(&bld.uint_coord_bld, builder, bld.uint_coord_type); lp_build_context_init(&bld.int_coord_bld, builder, bld.int_coord_type); lp_build_context_init(&bld.texel_bld, builder, bld.texel_type); @@ -559,32 +1276,29 @@ lp_build_sample_soa(LLVMBuilderRef builder, s = coords[0]; t = coords[1]; - p = coords[2]; + r = coords[2]; - width = lp_build_broadcast_scalar(&bld.int_coord_bld, width); - height = lp_build_broadcast_scalar(&bld.int_coord_bld, height); - stride = lp_build_broadcast_scalar(&bld.int_coord_bld, stride); + width = lp_build_broadcast_scalar(&bld.uint_coord_bld, width); + height = lp_build_broadcast_scalar(&bld.uint_coord_bld, height); + stride = lp_build_broadcast_scalar(&bld.uint_coord_bld, stride); if(static_state->target == PIPE_TEXTURE_1D) t = bld.coord_bld.zero; - if(static_state->normalized_coords) { - LLVMTypeRef coord_vec_type = lp_build_vec_type(bld.coord_type); - LLVMValueRef fp_width = LLVMBuildSIToFP(builder, width, coord_vec_type, ""); - LLVMValueRef fp_height = LLVMBuildSIToFP(builder, height, coord_vec_type, ""); - s = lp_build_mul(&bld.coord_bld, s, fp_width); - t = lp_build_mul(&bld.coord_bld, t, fp_height); - } - switch (static_state->min_img_filter) { case PIPE_TEX_FILTER_NEAREST: - lp_build_sample_2d_nearest_soa(&bld, s, t, width, height, stride, data_ptr, texel); + lp_build_sample_2d_nearest_soa(&bld, s, t, width, height, + stride, data_ptr, texel); break; case PIPE_TEX_FILTER_LINEAR: - if(lp_format_is_rgba8(bld.format_desc)) - lp_build_sample_2d_linear_aos(&bld, s, t, width, height, stride, data_ptr, texel); + if(lp_format_is_rgba8(bld.format_desc) && + is_simple_wrap_mode(static_state->wrap_s) && + is_simple_wrap_mode(static_state->wrap_t)) + lp_build_sample_2d_linear_aos(&bld, s, t, width, height, + stride, data_ptr, texel); else - lp_build_sample_2d_linear_soa(&bld, s, t, width, height, stride, data_ptr, texel); + lp_build_sample_2d_linear_soa(&bld, s, t, width, height, + stride, data_ptr, texel); break; default: assert(0); @@ -593,5 +1307,5 @@ lp_build_sample_soa(LLVMBuilderRef builder, /* FIXME: respect static_state->min_mip_filter */; /* FIXME: respect static_state->mag_img_filter */; - lp_build_sample_compare(&bld, p, texel); + lp_build_sample_compare(&bld, r, texel); } diff --git a/src/gallium/auxiliary/gallivm/lp_bld_tgsi_soa.c b/src/gallium/auxiliary/gallivm/lp_bld_tgsi_soa.c index 4cf28a9f93..28ff362cac 100644 --- a/src/gallium/auxiliary/gallivm/lp_bld_tgsi_soa.c +++ b/src/gallium/auxiliary/gallivm/lp_bld_tgsi_soa.c @@ -52,6 +52,7 @@ #include "lp_bld_swizzle.h" #include "lp_bld_flow.h" #include "lp_bld_tgsi.h" +#include "lp_bld_debug.h" #define LP_MAX_TEMPS 256 @@ -81,6 +82,21 @@ #define QUAD_BOTTOM_LEFT 2 #define QUAD_BOTTOM_RIGHT 3 +#define LP_TGSI_MAX_NESTING 16 + +struct lp_exec_mask { + struct lp_build_context *bld; + + boolean has_mask; + + LLVMTypeRef int_vec_type; + + LLVMValueRef cond_stack[LP_TGSI_MAX_NESTING]; + int cond_stack_size; + LLVMValueRef cond_mask; + + LLVMValueRef exec_mask; +}; struct lp_build_tgsi_soa_context { @@ -97,9 +113,9 @@ struct lp_build_tgsi_soa_context LLVMValueRef temps[LP_MAX_TEMPS][NUM_CHANNELS]; struct lp_build_mask_context *mask; + struct lp_exec_mask exec_mask; }; - static const unsigned char swizzle_left[4] = { QUAD_TOP_LEFT, QUAD_TOP_LEFT, @@ -124,6 +140,73 @@ swizzle_bottom[4] = { QUAD_BOTTOM_LEFT, QUAD_BOTTOM_RIGHT }; +static void lp_exec_mask_init(struct lp_exec_mask *mask, struct lp_build_context *bld) +{ + mask->bld = bld; + mask->has_mask = FALSE; + mask->cond_stack_size = 0; + + mask->int_vec_type = lp_build_int_vec_type(mask->bld->type); +} + +static void lp_exec_mask_update(struct lp_exec_mask *mask) +{ + mask->exec_mask = mask->cond_mask; + if (mask->cond_stack_size > 0) + mask->has_mask = TRUE; +} + +static void lp_exec_mask_cond_push(struct lp_exec_mask *mask, + LLVMValueRef val) +{ + mask->cond_stack[mask->cond_stack_size++] = mask->cond_mask; + mask->cond_mask = LLVMBuildBitCast(mask->bld->builder, val, + mask->int_vec_type, ""); + + lp_exec_mask_update(mask); +} + +static void lp_exec_mask_cond_invert(struct lp_exec_mask *mask) +{ + LLVMValueRef prev_mask = mask->cond_stack[mask->cond_stack_size - 1]; + LLVMValueRef inv_mask = LLVMBuildNot(mask->bld->builder, + mask->cond_mask, ""); + + /* means that we didn't have any mask before and that + * we were fully enabled */ + if (mask->cond_stack_size <= 1) { + prev_mask = LLVMConstAllOnes(mask->int_vec_type); + } + + mask->cond_mask = LLVMBuildAnd(mask->bld->builder, + inv_mask, + prev_mask, ""); + lp_exec_mask_update(mask); +} + +static void lp_exec_mask_cond_pop(struct lp_exec_mask *mask) +{ + mask->cond_mask = mask->cond_stack[--mask->cond_stack_size]; + lp_exec_mask_update(mask); +} + +static void lp_exec_mask_store(struct lp_exec_mask *mask, + LLVMValueRef val, + LLVMValueRef dst) +{ + if (mask->has_mask) { + LLVMValueRef real_val, dst_val; + + dst_val = LLVMBuildLoad(mask->bld->builder, dst, ""); + real_val = lp_build_select(mask->bld, + mask->exec_mask, + val, dst_val); + + LLVMBuildStore(mask->bld->builder, real_val, dst); + } else + LLVMBuildStore(mask->bld->builder, val, dst); +} + static LLVMValueRef emit_ddx(struct lp_build_tgsi_soa_context *bld, @@ -287,13 +370,13 @@ emit_store( switch( reg->Register.File ) { case TGSI_FILE_OUTPUT: - LLVMBuildStore(bld->base.builder, value, - bld->outputs[reg->Register.Index][chan_index]); + lp_exec_mask_store(&bld->exec_mask, value, + bld->outputs[reg->Register.Index][chan_index]); break; case TGSI_FILE_TEMPORARY: - LLVMBuildStore(bld->base.builder, value, - bld->temps[reg->Register.Index][chan_index]); + lp_exec_mask_store(&bld->exec_mask, value, + bld->temps[reg->Register.Index][chan_index]); break; case TGSI_FILE_ADDRESS: @@ -301,6 +384,11 @@ emit_store( assert(0); break; + case TGSI_FILE_PREDICATE: + /* FIXME */ + assert(0); + break; + default: assert( 0 ); } @@ -498,6 +586,17 @@ emit_instruction( if (indirect_temp_reference(inst)) return FALSE; + /* + * Stores and write masks are handled in a general fashion after the long + * instruction opcode switch statement. + * + * Although not stricitly necessary, we avoid generating instructions for + * channels which won't be stored, in cases where's that easy. For some + * complex instructions, like texture sampling, it is more convenient to + * assume a full writemask and then let LLVM optimization passes eliminate + * redundant code. + */ + assert(info->num_dst <= 1); if(info->num_dst) { FOR_EACH_DST0_ENABLED_CHANNEL( inst, chan_index ) { @@ -1272,8 +1371,8 @@ emit_instruction( break; case TGSI_OPCODE_IF: - /* FIXME */ - return 0; + tmp0 = emit_fetch(bld, inst, 0, CHAN_X); + lp_exec_mask_cond_push(&bld->exec_mask, tmp0); break; case TGSI_OPCODE_BGNFOR: @@ -1289,13 +1388,11 @@ emit_instruction( break; case TGSI_OPCODE_ELSE: - /* FIXME */ - return 0; + lp_exec_mask_cond_invert(&bld->exec_mask); break; case TGSI_OPCODE_ENDIF: - /* FIXME */ - return 0; + lp_exec_mask_cond_pop(&bld->exec_mask); break; case TGSI_OPCODE_ENDFOR: @@ -1458,6 +1555,8 @@ lp_build_tgsi_soa(LLVMBuilderRef builder, bld.consts_ptr = consts_ptr; bld.sampler = sampler; + lp_exec_mask_init(&bld.exec_mask, &bld.base); + tgsi_parse_init( &parse, tokens ); while( !tgsi_parse_end_of_tokens( &parse ) ) { diff --git a/src/gallium/auxiliary/gallivm/lp_bld_type.c b/src/gallium/auxiliary/gallivm/lp_bld_type.c index 8270cd057f..c327ba045a 100644 --- a/src/gallium/auxiliary/gallivm/lp_bld_type.c +++ b/src/gallium/auxiliary/gallivm/lp_bld_type.c @@ -178,6 +178,25 @@ lp_build_int32_vec4_type(void) } +/** + * Create unsigned integer type variation of given type. + */ +struct lp_type +lp_uint_type(struct lp_type type) +{ + struct lp_type res_type; + + memset(&res_type, 0, sizeof res_type); + res_type.width = type.width; + res_type.length = type.length; + + return res_type; +} + + +/** + * Create signed integer type variation of given type. + */ struct lp_type lp_int_type(struct lp_type type) { @@ -186,6 +205,7 @@ lp_int_type(struct lp_type type) memset(&res_type, 0, sizeof res_type); res_type.width = type.width; res_type.length = type.length; + res_type.sign = 1; return res_type; } diff --git a/src/gallium/auxiliary/gallivm/lp_bld_type.h b/src/gallium/auxiliary/gallivm/lp_bld_type.h index 62ee05be4d..16946cc28a 100644 --- a/src/gallium/auxiliary/gallivm/lp_bld_type.h +++ b/src/gallium/auxiliary/gallivm/lp_bld_type.h @@ -257,6 +257,10 @@ lp_build_int32_vec4_type(void); struct lp_type +lp_uint_type(struct lp_type type); + + +struct lp_type lp_int_type(struct lp_type type); |