+static void
+lp_twoside(struct gallivm_state *gallivm,
+ struct lp_setup_args *args,
+ const struct lp_setup_variant_key *key,
+ int bcolor_slot,
+ LLVMValueRef attribv[3])
+{
+ LLVMBuilderRef b = gallivm->builder;
+ LLVMValueRef a0_back, a1_back, a2_back;
+ LLVMValueRef idx2 = lp_build_const_int32(gallivm, bcolor_slot);
+
+ LLVMValueRef facing = args->facing;
+ LLVMValueRef front_facing = LLVMBuildICmp(b, LLVMIntEQ, facing,
+ lp_build_const_int32(gallivm, 0), ""); /** need i1 for if condition */
+
+ a0_back = LLVMBuildLoad(b, LLVMBuildGEP(b, args->v0, &idx2, 1, ""), "v0a_back");
+ a1_back = LLVMBuildLoad(b, LLVMBuildGEP(b, args->v1, &idx2, 1, ""), "v1a_back");
+ a2_back = LLVMBuildLoad(b, LLVMBuildGEP(b, args->v2, &idx2, 1, ""), "v2a_back");
+
+ /* Possibly swap the front and back attrib values,
+ *
+ * Prefer select to if so we don't have to worry about phis or
+ * allocas.
+ */
+ attribv[0] = LLVMBuildSelect(b, front_facing, a0_back, attribv[0], "");
+ attribv[1] = LLVMBuildSelect(b, front_facing, a1_back, attribv[1], "");
+ attribv[2] = LLVMBuildSelect(b, front_facing, a2_back, attribv[2], "");
+
+}
+
+static void
+lp_do_offset_tri(struct gallivm_state *gallivm,
+ struct lp_setup_args *args,
+ const struct lp_setup_variant_key *key,
+ LLVMValueRef inv_det,
+ LLVMValueRef dxyz01,
+ LLVMValueRef dxyz20,
+ LLVMValueRef attribv[3])
+{
+ LLVMBuilderRef b = gallivm->builder;
+ struct lp_build_context flt_scalar_bld;
+ struct lp_build_context int_scalar_bld;
+ struct lp_build_context *bld = &args->bld;
+ LLVMValueRef zoffset, mult;
+ LLVMValueRef z0_new, z1_new, z2_new;
+ LLVMValueRef dzdxdzdy, dzdx, dzdy, dzxyz20, dyzzx01, dyzzx01_dzxyz20, dzx01_dyz20;
+ LLVMValueRef z0z1, z0z1z2;
+ LLVMValueRef max, max_value, res12;
+ LLVMValueRef shuffles[4];
+ LLVMTypeRef shuf_type = LLVMInt32TypeInContext(gallivm->context);
+ LLVMValueRef onei = lp_build_const_int32(gallivm, 1);
+ LLVMValueRef zeroi = lp_build_const_int32(gallivm, 0);
+ LLVMValueRef twoi = lp_build_const_int32(gallivm, 2);
+ LLVMValueRef threei = lp_build_const_int32(gallivm, 3);
+
+ /* (res12) = cross(e,f).xy */
+ shuffles[0] = twoi;
+ shuffles[1] = zeroi;
+ shuffles[2] = onei;
+ shuffles[3] = twoi;
+ dzxyz20 = LLVMBuildShuffleVector(b, dxyz20, dxyz20, LLVMConstVector(shuffles, 4), "");
+
+ shuffles[0] = onei;
+ shuffles[1] = twoi;
+ shuffles[2] = twoi;
+ shuffles[3] = zeroi;
+ dyzzx01 = LLVMBuildShuffleVector(b, dxyz01, dxyz01, LLVMConstVector(shuffles, 4), "");
+
+ dyzzx01_dzxyz20 = LLVMBuildFMul(b, dzxyz20, dyzzx01, "dyzzx01_dzxyz20");
+
+ shuffles[0] = twoi;
+ shuffles[1] = threei;
+ shuffles[2] = LLVMGetUndef(shuf_type);
+ shuffles[3] = LLVMGetUndef(shuf_type);
+ dzx01_dyz20 = LLVMBuildShuffleVector(b, dyzzx01_dzxyz20, dyzzx01_dzxyz20,
+ LLVMConstVector(shuffles, 4), "");
+
+ res12 = LLVMBuildFSub(b, dyzzx01_dzxyz20, dzx01_dyz20, "res12");
+
+ /* dzdx = fabsf(res1 * inv_det), dydx = fabsf(res2 * inv_det)*/
+ dzdxdzdy = LLVMBuildFMul(b, res12, inv_det, "dzdxdzdy");
+ dzdxdzdy = lp_build_abs(bld, dzdxdzdy);
+
+ dzdx = LLVMBuildExtractElement(b, dzdxdzdy, zeroi, "");
+ dzdy = LLVMBuildExtractElement(b, dzdxdzdy, onei, "");
+
+ /* mult = MAX2(dzdx, dzdy) * pgon_offset_scale */
+ max = LLVMBuildFCmp(b, LLVMRealUGT, dzdx, dzdy, "");
+ max_value = LLVMBuildSelect(b, max, dzdx, dzdy, "max");
+
+ mult = LLVMBuildFMul(b, max_value,
+ lp_build_const_float(gallivm, key->pgon_offset_scale), "");
+
+ lp_build_context_init(&flt_scalar_bld, gallivm, lp_type_float_vec(32, 32));
+
+ if (key->floating_point_depth) {
+ /*
+ * bias = pgon_offset_units * 2^(exponent(max(z0, z1, z2)) - mantissa_bits) +
+ * MAX2(dzdx, dzdy) * pgon_offset_scale
+ *
+ * NOTE: Assumes IEEE float32.
+ */
+ LLVMValueRef c23_shifted, exp_mask, bias, exp;
+ LLVMValueRef maxz_value, maxz0z1_value;
+
+ lp_build_context_init(&int_scalar_bld, gallivm, lp_type_int_vec(32, 32));
+
+ c23_shifted = lp_build_const_int32(gallivm, 23 << 23);
+ exp_mask = lp_build_const_int32(gallivm, 0xff << 23);
+
+ maxz0z1_value = lp_build_max(&flt_scalar_bld,
+ LLVMBuildExtractElement(b, attribv[0], twoi, ""),
+ LLVMBuildExtractElement(b, attribv[1], twoi, ""));
+
+ maxz_value = lp_build_max(&flt_scalar_bld,
+ LLVMBuildExtractElement(b, attribv[2], twoi, ""),
+ maxz0z1_value);
+
+ exp = LLVMBuildBitCast(b, maxz_value, int_scalar_bld.vec_type, "");
+ exp = lp_build_and(&int_scalar_bld, exp, exp_mask);
+ exp = lp_build_sub(&int_scalar_bld, exp, c23_shifted);
+ /* Clamping to zero means mrd will be zero for very small numbers,
+ * but specs do not indicate this should be prevented by clamping
+ * mrd to smallest normal number instead. */
+ exp = lp_build_max(&int_scalar_bld, exp, int_scalar_bld.zero);
+ exp = LLVMBuildBitCast(b, exp, flt_scalar_bld.vec_type, "");
+
+ bias = LLVMBuildFMul(b, exp,
+ lp_build_const_float(gallivm, key->pgon_offset_units),
+ "bias");
+
+ zoffset = LLVMBuildFAdd(b, bias, mult, "zoffset");
+ } else {
+ /*
+ * bias = pgon_offset_units + MAX2(dzdx, dzdy) * pgon_offset_scale
+ */
+ zoffset = LLVMBuildFAdd(b,
+ lp_build_const_float(gallivm, key->pgon_offset_units),
+ mult, "zoffset");
+ }