+ for (attrib = 0; attrib < bld->num_attribs; ++attrib) {
+ const unsigned mask = bld->mask[attrib];
+ const unsigned interp = bld->interp[attrib];
+ LLVMValueRef index = lp_build_const_int32(gallivm,
+ attrib * TGSI_NUM_CHANNELS);
+ LLVMValueRef ptr;
+ LLVMValueRef dadxaos = setup_bld->zero;
+ LLVMValueRef dadyaos = setup_bld->zero;
+ LLVMValueRef a0aos = setup_bld->zero;
+
+ /* always fetch all 4 values for performance/simplicity */
+ switch (interp) {
+ case LP_INTERP_PERSPECTIVE:
+ /* fall-through */
+
+ case LP_INTERP_LINEAR:
+ ptr = LLVMBuildGEP(builder, dadx_ptr, &index, 1, "");
+ ptr = LLVMBuildBitCast(builder, ptr,
+ LLVMPointerType(setup_bld->vec_type, 0), "");
+ dadxaos = LLVMBuildLoad(builder, ptr, "");
+
+ ptr = LLVMBuildGEP(builder, dady_ptr, &index, 1, "");
+ ptr = LLVMBuildBitCast(builder, ptr,
+ LLVMPointerType(setup_bld->vec_type, 0), "");
+ dadyaos = LLVMBuildLoad(builder, ptr, "");
+
+ attrib_name(dadxaos, attrib, 0, ".dadxaos");
+ attrib_name(dadyaos, attrib, 0, ".dadyaos");
+ /* fall-through */
+
+ case LP_INTERP_CONSTANT:
+ case LP_INTERP_FACING:
+ ptr = LLVMBuildGEP(builder, a0_ptr, &index, 1, "");
+ ptr = LLVMBuildBitCast(builder, ptr,
+ LLVMPointerType(setup_bld->vec_type, 0), "");
+ a0aos = LLVMBuildLoad(builder, ptr, "");
+ attrib_name(a0aos, attrib, 0, ".a0aos");
+ break;
+
+ case LP_INTERP_POSITION:
+ /* Nothing to do as the position coeffs are already setup in slot 0 */
+ continue;
+
+ default:
+ assert(0);
+ break;
+ }
+
+ /*
+ * a = a0 + (x * dadx + y * dady)
+ * a0aos is the attrib value at top left corner of stamp
+ */
+ if (interp != LP_INTERP_CONSTANT &&
+ interp != LP_INTERP_FACING) {
+ LLVMValueRef x = lp_build_broadcast_scalar(setup_bld, bld->x);
+ LLVMValueRef y = lp_build_broadcast_scalar(setup_bld, bld->y);
+ a0aos = lp_build_fmuladd(builder, x, dadxaos, a0aos);
+ a0aos = lp_build_fmuladd(builder, y, dadyaos, a0aos);
+ }
+
+ /*
+ * dadq = {0, dadx, dady, dadx + dady}
+ * for two quads (side by side) this is:
+ * {0, dadx, dady, dadx+dady, 2*dadx, 2*dadx+dady, 3*dadx+dady}
+ */
+ for (chan = 0; chan < TGSI_NUM_CHANNELS; ++chan) {
+ /* this generates a CRAPLOAD of shuffles... */
+ if (mask & (1 << chan)) {
+ LLVMValueRef dadx, dady;
+ LLVMValueRef dadq, dadq2;
+ LLVMValueRef a;
+ LLVMValueRef chan_index = lp_build_const_int32(gallivm, chan);
+
+ if (attrib == 0 && chan == 0) {
+ a = bld->x;
+ if (bld->pos_offset) {
+ a = LLVMBuildFAdd(builder, a, lp_build_const_float(gallivm, bld->pos_offset), "");
+ }
+ a = lp_build_broadcast_scalar(coeff_bld, a);
+ dadx = coeff_bld->one;
+ dady = coeff_bld->zero;
+ }
+ else if (attrib == 0 && chan == 1) {
+ a = bld->y;
+ if (bld->pos_offset) {
+ a = LLVMBuildFAdd(builder, a, lp_build_const_float(gallivm, bld->pos_offset), "");
+ }
+ a = lp_build_broadcast_scalar(coeff_bld, a);
+ dady = coeff_bld->one;
+ dadx = coeff_bld->zero;
+ }
+ else {
+ dadx = lp_build_extract_broadcast(gallivm, setup_bld->type,
+ coeff_bld->type, dadxaos, chan_index);
+ dady = lp_build_extract_broadcast(gallivm, setup_bld->type,
+ coeff_bld->type, dadyaos, chan_index);
+
+ /*
+ * a = {a, a, a, a}
+ */
+ a = lp_build_extract_broadcast(gallivm, setup_bld->type,
+ coeff_bld->type, a0aos, chan_index);
+ }