+ have_corner = lp_build_and(ivec_bld, fall_off_x, fall_off_y);
+ have_corner = lp_build_any_true_range(ivec_bld, ivec_bld->type.length, have_corner);
+ LLVMBuildStore(builder, have_corner, have_corners);
+
+ /*
+ * Need to feed clamped values here for cheap corner handling,
+ * but only for y coord (as when falling off both edges we only
+ * fall off the x one) - this should be sufficient.
+ */
+ y0_clamped = lp_build_max(ivec_bld, y0, ivec_bld->zero);
+ y1_clamped = lp_build_min(ivec_bld, y1, length_minus_one);
+
+ /*
+ * Get all possible new coords.
+ */
+ lp_build_cube_new_coords(ivec_bld, face,
+ x0, x1, y0_clamped, y1_clamped,
+ length_minus_one,
+ new_faces, new_xcoords, new_ycoords);
+
+ /* handle fall off x-, x+ direction */
+ /* determine new coords, face (not both fall_off vars can be true at same time) */
+ x00 = lp_build_select(ivec_bld, fall_off[0], new_xcoords[0][0], x0);
+ y00 = lp_build_select(ivec_bld, fall_off[0], new_ycoords[0][0], y0_clamped);
+ x10 = lp_build_select(ivec_bld, fall_off[0], new_xcoords[0][1], x0);
+ y10 = lp_build_select(ivec_bld, fall_off[0], new_ycoords[0][1], y1_clamped);
+ x01 = lp_build_select(ivec_bld, fall_off[1], new_xcoords[1][0], x1);
+ y01 = lp_build_select(ivec_bld, fall_off[1], new_ycoords[1][0], y0_clamped);
+ x11 = lp_build_select(ivec_bld, fall_off[1], new_xcoords[1][1], x1);
+ y11 = lp_build_select(ivec_bld, fall_off[1], new_ycoords[1][1], y1_clamped);
+
+ z00 = z10 = lp_build_select(ivec_bld, fall_off[0], new_faces[0], face);
+ z01 = z11 = lp_build_select(ivec_bld, fall_off[1], new_faces[1], face);
+
+ /* handle fall off y-, y+ direction */
+ /*
+ * Cheap corner logic: just hack up things so a texel doesn't fall
+ * off both sides (which means filter weights will be wrong but we'll only
+ * use valid texels in the filter).
+ * This means however (y) coords must additionally be clamped (see above).
+ * This corner handling should be fully OpenGL (but not d3d10) compliant.
+ */
+ fall_off_ym_notxm = lp_build_andnot(ivec_bld, fall_off[2], fall_off[0]);
+ fall_off_ym_notxp = lp_build_andnot(ivec_bld, fall_off[2], fall_off[1]);
+ fall_off_yp_notxm = lp_build_andnot(ivec_bld, fall_off[3], fall_off[0]);
+ fall_off_yp_notxp = lp_build_andnot(ivec_bld, fall_off[3], fall_off[1]);
+
+ x00 = lp_build_select(ivec_bld, fall_off_ym_notxm, new_xcoords[2][0], x00);
+ y00 = lp_build_select(ivec_bld, fall_off_ym_notxm, new_ycoords[2][0], y00);
+ x01 = lp_build_select(ivec_bld, fall_off_ym_notxp, new_xcoords[2][1], x01);
+ y01 = lp_build_select(ivec_bld, fall_off_ym_notxp, new_ycoords[2][1], y01);
+ x10 = lp_build_select(ivec_bld, fall_off_yp_notxm, new_xcoords[3][0], x10);
+ y10 = lp_build_select(ivec_bld, fall_off_yp_notxm, new_ycoords[3][0], y10);
+ x11 = lp_build_select(ivec_bld, fall_off_yp_notxp, new_xcoords[3][1], x11);
+ y11 = lp_build_select(ivec_bld, fall_off_yp_notxp, new_ycoords[3][1], y11);
+
+ z00 = lp_build_select(ivec_bld, fall_off_ym_notxm, new_faces[2], z00);
+ z01 = lp_build_select(ivec_bld, fall_off_ym_notxp, new_faces[2], z01);
+ z10 = lp_build_select(ivec_bld, fall_off_yp_notxm, new_faces[3], z10);
+ z11 = lp_build_select(ivec_bld, fall_off_yp_notxp, new_faces[3], z11);
+
+ LLVMBuildStore(builder, x00, xs[0]);
+ LLVMBuildStore(builder, x01, xs[1]);
+ LLVMBuildStore(builder, x10, xs[2]);
+ LLVMBuildStore(builder, x11, xs[3]);
+ LLVMBuildStore(builder, y00, ys[0]);
+ LLVMBuildStore(builder, y01, ys[1]);
+ LLVMBuildStore(builder, y10, ys[2]);
+ LLVMBuildStore(builder, y11, ys[3]);
+ LLVMBuildStore(builder, z00, zs[0]);
+ LLVMBuildStore(builder, z01, zs[1]);
+ LLVMBuildStore(builder, z10, zs[2]);
+ LLVMBuildStore(builder, z11, zs[3]);
+
+ lp_build_else(&edge_if);
+
+ LLVMBuildStore(builder, x0, xs[0]);
+ LLVMBuildStore(builder, x1, xs[1]);
+ LLVMBuildStore(builder, x0, xs[2]);
+ LLVMBuildStore(builder, x1, xs[3]);
+ LLVMBuildStore(builder, y0, ys[0]);
+ LLVMBuildStore(builder, y0, ys[1]);
+ LLVMBuildStore(builder, y1, ys[2]);
+ LLVMBuildStore(builder, y1, ys[3]);
+ LLVMBuildStore(builder, face, zs[0]);
+ LLVMBuildStore(builder, face, zs[1]);
+ LLVMBuildStore(builder, face, zs[2]);
+ LLVMBuildStore(builder, face, zs[3]);
+
+ lp_build_endif(&edge_if);
+
+ x00 = LLVMBuildLoad(builder, xs[0], "");
+ x01 = LLVMBuildLoad(builder, xs[1], "");
+ x10 = LLVMBuildLoad(builder, xs[2], "");
+ x11 = LLVMBuildLoad(builder, xs[3], "");
+ y00 = LLVMBuildLoad(builder, ys[0], "");
+ y01 = LLVMBuildLoad(builder, ys[1], "");
+ y10 = LLVMBuildLoad(builder, ys[2], "");
+ y11 = LLVMBuildLoad(builder, ys[3], "");
+ z00 = LLVMBuildLoad(builder, zs[0], "");
+ z01 = LLVMBuildLoad(builder, zs[1], "");
+ z10 = LLVMBuildLoad(builder, zs[2], "");
+ z11 = LLVMBuildLoad(builder, zs[3], "");
+ }
+
+ if (linear_mask) {
+ /*
+ * Whack filter weights into place. Whatever texel had more weight is
+ * the one which should have been selected by nearest filtering hence
+ * just use 100% weight for it.
+ */
+ struct lp_build_context *c_bld = &bld->coord_bld;
+ LLVMValueRef w1_mask, w1_weight;
+ LLVMValueRef half = lp_build_const_vec(bld->gallivm, c_bld->type, 0.5f);
+
+ w1_mask = lp_build_cmp(c_bld, PIPE_FUNC_GREATER, s_fpart, half);
+ /* this select is really just a "and" */
+ w1_weight = lp_build_select(c_bld, w1_mask, c_bld->one, c_bld->zero);
+ s_fpart = lp_build_select(c_bld, linear_mask, s_fpart, w1_weight);
+ if (dims >= 2) {
+ w1_mask = lp_build_cmp(c_bld, PIPE_FUNC_GREATER, t_fpart, half);
+ w1_weight = lp_build_select(c_bld, w1_mask, c_bld->one, c_bld->zero);
+ t_fpart = lp_build_select(c_bld, linear_mask, t_fpart, w1_weight);
+ if (dims == 3) {
+ w1_mask = lp_build_cmp(c_bld, PIPE_FUNC_GREATER, r_fpart, half);
+ w1_weight = lp_build_select(c_bld, w1_mask, c_bld->one, c_bld->zero);
+ r_fpart = lp_build_select(c_bld, linear_mask, r_fpart, w1_weight);
+ }
+ }
+ }