- else {
- struct lp_build_if_state if_ctx;
- LLVMValueRef face_s_var;
- LLVMValueRef face_t_var;
- LLVMValueRef face_var;
- LLVMValueRef arx_ge_ary_arz, ary_ge_arx_arz;
- LLVMValueRef shuffles[4];
- LLVMValueRef arxy_ge_aryx, arxy_ge_arzz, arxy_ge_arxy_arzz;
- LLVMValueRef arxyxy, aryxzz, arxyxy_ge_aryxzz;
- LLVMValueRef tmp[4], rxyz, arxyz;
- struct lp_build_context *float_bld = &bld->float_bld;
- LLVMValueRef s, t, r, face, face_s, face_t;
-
- assert(bld->coord_bld.type.length == 4);
-
- tmp[0] = s = coords[0];
- tmp[1] = t = coords[1];
- tmp[2] = r = coords[2];
- rxyz = lp_build_hadd_partial4(&bld->coord_bld, tmp, 3);
- arxyz = lp_build_abs(&bld->coord_bld, rxyz);
-
- shuffles[0] = lp_build_const_int32(gallivm, 0);
- shuffles[1] = lp_build_const_int32(gallivm, 1);
- shuffles[2] = lp_build_const_int32(gallivm, 0);
- shuffles[3] = lp_build_const_int32(gallivm, 1);
- arxyxy = LLVMBuildShuffleVector(builder, arxyz, arxyz, LLVMConstVector(shuffles, 4), "");
- shuffles[0] = lp_build_const_int32(gallivm, 1);
- shuffles[1] = lp_build_const_int32(gallivm, 0);
- shuffles[2] = lp_build_const_int32(gallivm, 2);
- shuffles[3] = lp_build_const_int32(gallivm, 2);
- aryxzz = LLVMBuildShuffleVector(builder, arxyz, arxyz, LLVMConstVector(shuffles, 4), "");
- arxyxy_ge_aryxzz = lp_build_cmp(&bld->coord_bld, PIPE_FUNC_GEQUAL, arxyxy, aryxzz);
-
- shuffles[0] = lp_build_const_int32(gallivm, 0);
- shuffles[1] = lp_build_const_int32(gallivm, 1);
- arxy_ge_aryx = LLVMBuildShuffleVector(builder, arxyxy_ge_aryxzz, arxyxy_ge_aryxzz,
- LLVMConstVector(shuffles, 2), "");
- shuffles[0] = lp_build_const_int32(gallivm, 2);
- shuffles[1] = lp_build_const_int32(gallivm, 3);
- arxy_ge_arzz = LLVMBuildShuffleVector(builder, arxyxy_ge_aryxzz, arxyxy_ge_aryxzz,
- LLVMConstVector(shuffles, 2), "");
- arxy_ge_arxy_arzz = LLVMBuildAnd(builder, arxy_ge_aryx, arxy_ge_arzz, "");
-
- arx_ge_ary_arz = LLVMBuildExtractElement(builder, arxy_ge_arxy_arzz,
- lp_build_const_int32(gallivm, 0), "");
- arx_ge_ary_arz = LLVMBuildICmp(builder, LLVMIntNE, arx_ge_ary_arz,
- lp_build_const_int32(gallivm, 0), "");
- ary_ge_arx_arz = LLVMBuildExtractElement(builder, arxy_ge_arxy_arzz,
- lp_build_const_int32(gallivm, 1), "");
- ary_ge_arx_arz = LLVMBuildICmp(builder, LLVMIntNE, ary_ge_arx_arz,
- lp_build_const_int32(gallivm, 0), "");
- face_s_var = lp_build_alloca(gallivm, bld->coord_bld.vec_type, "face_s_var");
- face_t_var = lp_build_alloca(gallivm, bld->coord_bld.vec_type, "face_t_var");
- face_var = lp_build_alloca(gallivm, bld->int_bld.vec_type, "face_var");
-
- lp_build_if(&if_ctx, gallivm, arx_ge_ary_arz);
- {
- /* +/- X face */
- LLVMValueRef sign, ima;
- si = LLVMBuildExtractElement(builder, rxyz,
- lp_build_const_int32(gallivm, 0), "");
- /* +/- X face */
- sign = lp_build_sgn(float_bld, si);
- ima = lp_build_cube_imaneg(coord_bld, s);
- face_s = lp_build_cube_coord(coord_bld, sign, +1, r, ima);
- face_t = lp_build_cube_coord(coord_bld, NULL, +1, t, ima);
- face = lp_build_cube_face(bld, si,
- PIPE_TEX_FACE_POS_X,
- PIPE_TEX_FACE_NEG_X);
- LLVMBuildStore(builder, face_s, face_s_var);
- LLVMBuildStore(builder, face_t, face_t_var);
- LLVMBuildStore(builder, face, face_var);
- }
- lp_build_else(&if_ctx);
- {
- struct lp_build_if_state if_ctx2;
-
- lp_build_if(&if_ctx2, gallivm, ary_ge_arx_arz);
- {
- LLVMValueRef sign, ima;
- /* +/- Y face */
- ti = LLVMBuildExtractElement(builder, rxyz,
- lp_build_const_int32(gallivm, 1), "");
- sign = lp_build_sgn(float_bld, ti);
- ima = lp_build_cube_imaneg(coord_bld, t);
- face_s = lp_build_cube_coord(coord_bld, NULL, -1, s, ima);
- face_t = lp_build_cube_coord(coord_bld, sign, -1, r, ima);
- face = lp_build_cube_face(bld, ti,
- PIPE_TEX_FACE_POS_Y,
- PIPE_TEX_FACE_NEG_Y);
- LLVMBuildStore(builder, face_s, face_s_var);
- LLVMBuildStore(builder, face_t, face_t_var);
- LLVMBuildStore(builder, face, face_var);
- }
- lp_build_else(&if_ctx2);
- {
- /* +/- Z face */
- LLVMValueRef sign, ima;
- ri = LLVMBuildExtractElement(builder, rxyz,
- lp_build_const_int32(gallivm, 2), "");
- sign = lp_build_sgn(float_bld, ri);
- ima = lp_build_cube_imaneg(coord_bld, r);
- face_s = lp_build_cube_coord(coord_bld, sign, -1, s, ima);
- face_t = lp_build_cube_coord(coord_bld, NULL, +1, t, ima);
- face = lp_build_cube_face(bld, ri,
- PIPE_TEX_FACE_POS_Z,
- PIPE_TEX_FACE_NEG_Z);
- LLVMBuildStore(builder, face_s, face_s_var);
- LLVMBuildStore(builder, face_t, face_t_var);
- LLVMBuildStore(builder, face, face_var);
- }
- lp_build_endif(&if_ctx2);
- }
+ else if (need_derivs) {
+ LLVMValueRef ddx_ddy[2], tmp[3], rho_vec;
+ static const unsigned char swizzle0[] = { /* no-op swizzle */
+ 0, LP_BLD_SWIZZLE_DONTCARE,
+ LP_BLD_SWIZZLE_DONTCARE, LP_BLD_SWIZZLE_DONTCARE
+ };
+ static const unsigned char swizzle1[] = {
+ 1, LP_BLD_SWIZZLE_DONTCARE,
+ LP_BLD_SWIZZLE_DONTCARE, LP_BLD_SWIZZLE_DONTCARE
+ };
+ static const unsigned char swizzle01[] = { /* no-op swizzle */
+ 0, 1,
+ LP_BLD_SWIZZLE_DONTCARE, LP_BLD_SWIZZLE_DONTCARE
+ };
+ static const unsigned char swizzle23[] = {
+ 2, 3,
+ LP_BLD_SWIZZLE_DONTCARE, LP_BLD_SWIZZLE_DONTCARE
+ };
+ static const unsigned char swizzle02[] = {
+ 0, 2,
+ LP_BLD_SWIZZLE_DONTCARE, LP_BLD_SWIZZLE_DONTCARE
+ };
+
+ /*
+ * scale the s/t/r coords pre-select/mirror so we can calculate
+ * "reasonable" derivs.
+ */
+ ma = lp_build_select3(coord_bld, as_ge_at, ar_ge_as_at, s, t, r);
+ imahalfpos = lp_build_cube_imapos(coord_bld, ma);
+ s = lp_build_mul(coord_bld, s, imahalfpos);
+ t = lp_build_mul(coord_bld, t, imahalfpos);
+ r = lp_build_mul(coord_bld, r, imahalfpos);
+
+ /*
+ * This isn't quite the same as the "ordinary" (3d deriv) path since we
+ * know the texture is square which simplifies things (we can omit the
+ * size mul which happens very early completely here and do it at the
+ * very end).
+ * Also always do calculations according to GALLIVM_DEBUG_NO_RHO_APPROX
+ * since the error can get quite big otherwise at edges.
+ * (With no_rho_approx max error is sqrt(2) at edges, same as it is
+ * without no_rho_approx for 2d textures, otherwise it would be factor 2.)
+ */
+ ddx_ddy[0] = lp_build_packed_ddx_ddy_twocoord(coord_bld, s, t);
+ ddx_ddy[1] = lp_build_packed_ddx_ddy_onecoord(coord_bld, r);