+/**
+ * Build LLVM code for texture coord wrapping, for linear filtering,
+ * for float texcoords.
+ * \param block_length is the length of the pixel block along the
+ * coordinate axis
+ * \param coord the incoming texcoord (s,t,r or q)
+ * \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
+ * \param coord0 the first texcoord after wrapping, as int
+ * \param coord1 the second texcoord after wrapping, as int
+ * \param weight the filter weight as int (0-255)
+ * \param force_nearest if this coord actually uses nearest filtering
+ */
+static void
+lp_build_sample_wrap_linear_float(struct lp_build_sample_context *bld,
+ unsigned block_length,
+ LLVMValueRef coord,
+ LLVMValueRef length,
+ boolean is_pot,
+ unsigned wrap_mode,
+ LLVMValueRef *coord0,
+ LLVMValueRef *coord1,
+ LLVMValueRef *weight,
+ unsigned force_nearest)
+{
+ struct lp_build_context *int_coord_bld = &bld->int_coord_bld;
+ struct lp_build_context *coord_bld = &bld->coord_bld;
+ LLVMBuilderRef builder = bld->gallivm->builder;
+ LLVMValueRef half = lp_build_const_vec(bld->gallivm, coord_bld->type, 0.5);
+ LLVMValueRef length_minus_one = lp_build_sub(coord_bld, length, coord_bld->one);
+
+ switch(wrap_mode) {
+ case PIPE_TEX_WRAP_REPEAT:
+ if (is_pot) {
+ /* mul by size and subtract 0.5 */
+ coord = lp_build_mul(coord_bld, coord, length);
+ if (!force_nearest)
+ coord = lp_build_sub(coord_bld, coord, half);
+ *coord1 = lp_build_add(coord_bld, coord, coord_bld->one);
+ /* convert to int, compute lerp weight */
+ lp_build_ifloor_fract(coord_bld, coord, coord0, weight);
+ *coord1 = lp_build_ifloor(coord_bld, *coord1);
+ /* repeat wrap */
+ length_minus_one = lp_build_itrunc(coord_bld, length_minus_one);
+ *coord0 = LLVMBuildAnd(builder, *coord0, length_minus_one, "");
+ *coord1 = LLVMBuildAnd(builder, *coord1, length_minus_one, "");
+ }
+ else {
+ LLVMValueRef mask;
+ /* wrap with normalized floats is just fract */
+ coord = lp_build_fract(coord_bld, coord);
+ /* unnormalize */
+ coord = lp_build_mul(coord_bld, coord, length);
+ /*
+ * we avoided the 0.5/length division, have to fix up wrong
+ * edge cases with selects
+ */
+ *coord1 = lp_build_add(coord_bld, coord, half);
+ coord = lp_build_sub(coord_bld, coord, half);
+ *weight = lp_build_fract(coord_bld, coord);
+ mask = lp_build_compare(coord_bld->gallivm, coord_bld->type,
+ PIPE_FUNC_LESS, coord, coord_bld->zero);
+ *coord0 = lp_build_select(coord_bld, mask, length_minus_one, coord);
+ *coord0 = lp_build_itrunc(coord_bld, *coord0);
+ mask = lp_build_compare(coord_bld->gallivm, coord_bld->type,
+ PIPE_FUNC_LESS, *coord1, length);
+ *coord1 = lp_build_select(coord_bld, mask, *coord1, coord_bld->zero);
+ *coord1 = lp_build_itrunc(coord_bld, *coord1);
+ }
+ break;
+ case PIPE_TEX_WRAP_CLAMP_TO_EDGE:
+ if (bld->static_sampler_state->normalized_coords) {
+ /* mul by tex size */
+ coord = lp_build_mul(coord_bld, coord, length);
+ }
+ /* subtract 0.5 */
+ if (!force_nearest) {
+ coord = lp_build_sub(coord_bld, coord, half);
+ }
+ /* clamp to [0, length - 1] */
+ coord = lp_build_min(coord_bld, coord, length_minus_one);
+ coord = lp_build_max(coord_bld, coord, coord_bld->zero);
+ *coord1 = lp_build_add(coord_bld, coord, coord_bld->one);
+ /* convert to int, compute lerp weight */
+ lp_build_ifloor_fract(coord_bld, coord, coord0, weight);
+ /* coord1 = min(coord1, length-1) */
+ *coord1 = lp_build_min(coord_bld, *coord1, length_minus_one);
+ *coord1 = lp_build_itrunc(coord_bld, *coord1);
+ break;
+ default:
+ assert(0);
+ *coord0 = int_coord_bld->zero;
+ *coord1 = int_coord_bld->zero;
+ *weight = coord_bld->zero;
+ break;
+ }
+ *weight = lp_build_mul_imm(coord_bld, *weight, 256);
+ *weight = lp_build_itrunc(coord_bld, *weight);
+ return;
+}
+
+
+/**
+ * Fetch texels for image with nearest sampling.
+ * Return filtered color as two vectors of 16-bit fixed point values.
+ */
+static void
+lp_build_sample_fetch_image_nearest(struct lp_build_sample_context *bld,
+ LLVMValueRef data_ptr,
+ LLVMValueRef offset,
+ LLVMValueRef x_subcoord,
+ LLVMValueRef y_subcoord,
+ LLVMValueRef *colors_lo,
+ LLVMValueRef *colors_hi)
+{
+ /*
+ * Fetch the pixels as 4 x 32bit (rgba order might differ):
+ *
+ * rgba0 rgba1 rgba2 rgba3
+ *
+ * bit cast them into 16 x u8
+ *
+ * r0 g0 b0 a0 r1 g1 b1 a1 r2 g2 b2 a2 r3 g3 b3 a3
+ *
+ * unpack them into two 8 x i16:
+ *
+ * r0 g0 b0 a0 r1 g1 b1 a1
+ * r2 g2 b2 a2 r3 g3 b3 a3
+ *
+ * The higher 8 bits of the resulting elements will be zero.
+ */
+ LLVMBuilderRef builder = bld->gallivm->builder;
+ LLVMValueRef rgba8;
+ struct lp_build_context h16, u8n;
+ LLVMTypeRef u8n_vec_type;
+
+ lp_build_context_init(&h16, bld->gallivm, lp_type_ufixed(16, bld->vector_width));
+ lp_build_context_init(&u8n, bld->gallivm, lp_type_unorm(8, bld->vector_width));
+ u8n_vec_type = lp_build_vec_type(bld->gallivm, u8n.type);
+
+ if (util_format_is_rgba8_variant(bld->format_desc)) {
+ /*
+ * Given the format is a rgba8, just read the pixels as is,
+ * without any swizzling. Swizzling will be done later.
+ */
+ rgba8 = lp_build_gather(bld->gallivm,
+ bld->texel_type.length,
+ bld->format_desc->block.bits,
+ bld->texel_type.width,
+ data_ptr, offset);
+
+ rgba8 = LLVMBuildBitCast(builder, rgba8, u8n_vec_type, "");
+ }
+ else {
+ rgba8 = lp_build_fetch_rgba_aos(bld->gallivm,
+ bld->format_desc,
+ u8n.type,
+ data_ptr, offset,
+ x_subcoord,
+ y_subcoord);
+ }
+
+ /* Expand one 4*rgba8 to two 2*rgba16 */
+ lp_build_unpack2(bld->gallivm, u8n.type, h16.type,
+ rgba8,
+ colors_lo, colors_hi);
+}
+
+