diff options
Diffstat (limited to 'src/gallium/auxiliary')
-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_logic.c | 5 | ||||
-rw-r--r-- | src/gallium/auxiliary/gallivm/lp_bld_sample.c | 9 | ||||
-rw-r--r-- | src/gallium/auxiliary/gallivm/lp_bld_sample.h | 1 | ||||
-rw-r--r-- | src/gallium/auxiliary/gallivm/lp_bld_sample_soa.c | 634 | ||||
-rw-r--r-- | src/gallium/auxiliary/gallivm/lp_bld_tgsi_soa.c | 1 | ||||
-rw-r--r-- | src/gallium/auxiliary/gallivm/lp_bld_type.c | 20 | ||||
-rw-r--r-- | src/gallium/auxiliary/gallivm/lp_bld_type.h | 4 |
9 files changed, 672 insertions, 70 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_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_sample.c b/src/gallium/auxiliary/gallivm/lp_bld_sample.c index a133b56ac5..55ac2e9436 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, @@ -70,6 +75,10 @@ lp_sampler_static_state(struct lp_sampler_static_state *state, state->min_mip_filter = sampler->min_mip_filter; state->mag_img_filter = sampler->mag_img_filter; state->compare_mode = sampler->compare_mode; + 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]; if(sampler->compare_mode != PIPE_TEX_COMPARE_NONE) { state->compare_func = sampler->compare_func; } diff --git a/src/gallium/auxiliary/gallivm/lp_bld_sample.h b/src/gallium/auxiliary/gallivm/lp_bld_sample.h index 39edcf13d1..a791d88612 100644 --- a/src/gallium/auxiliary/gallivm/lp_bld_sample.h +++ b/src/gallium/auxiliary/gallivm/lp_bld_sample.h @@ -70,6 +70,7 @@ struct lp_sampler_static_state unsigned compare_mode:1; unsigned compare_func:3; unsigned normalized_coords:1; + float border_color[4]; }; diff --git a/src/gallium/auxiliary/gallivm/lp_bld_sample_soa.c b/src/gallium/auxiliary/gallivm/lp_bld_sample_soa.c index e268862282..fe41d5ee49 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,344 @@ 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; + LLVMValueRef length_f_minus_one; + LLVMValueRef coord0, coord1, weight; + + /* XXX check for normalized vs. unnormalized coords */ + + length_minus_one = lp_build_sub(uint_coord_bld, length, uint_coord_bld->one); + length_f_minus_one = lp_build_sub(coord_bld, length_f, coord_bld->one); + + 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: + 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: + /* 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); + /* 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; + /* 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 = 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); + /* 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) */ + min = lp_build_rcp(coord_bld, lp_build_mul(coord_bld, two, length_f)); + min = lp_build_negate(coord_bld, min); + /* 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; + + /* XXX check for normalized vs. unnormalized coords */ + + 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 */ + 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; + /* 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); + /* 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; + /* 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); + /* 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_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 +687,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 +716,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 +723,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 +807,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 +841,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 +1008,11 @@ lp_build_sample_compare(struct lp_build_sample_context *bld, } +/** + * 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, @@ -545,9 +1040,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); @@ -561,30 +1058,27 @@ lp_build_sample_soa(LLVMBuilderRef builder, t = coords[1]; p = 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); diff --git a/src/gallium/auxiliary/gallivm/lp_bld_tgsi_soa.c b/src/gallium/auxiliary/gallivm/lp_bld_tgsi_soa.c index ae866243a9..5f2c2a54ee 100644 --- a/src/gallium/auxiliary/gallivm/lp_bld_tgsi_soa.c +++ b/src/gallium/auxiliary/gallivm/lp_bld_tgsi_soa.c @@ -1126,6 +1126,7 @@ emit_instruction( break; case TGSI_OPCODE_TEX: + /* XXX what about dst0 writemask? */ emit_tex( bld, inst, FALSE, FALSE, dst0 ); break; 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); |