+
+
+ /* First handle the 3D and NDC interpolation, in case we
+ * need noperspective interpolation. Doing it early has no
+ * performance impact in any case.
+ */
+
+ /* Take a copy of the v0 NDC coordinates, in case dest == v0. */
+ if (c->has_noperspective_shading) {
+ GLuint offset = brw_varying_to_offset(&c->vue_map,
+ BRW_VARYING_SLOT_NDC);
+ v0_ndc_copy = get_tmp(c);
+ brw_MOV(p, v0_ndc_copy, deref_4f(v0_ptr, offset));
+ }
+
+ /* Compute the new 3D position
+ *
+ * dest_hpos = v0_hpos * (1 - t0) + v1_hpos * t0
+ */
+ {
+ GLuint delta = brw_varying_to_offset(&c->vue_map, VARYING_SLOT_POS);
+ struct brw_reg tmp = get_tmp(c);
+ brw_MUL(p, vec4(brw_null_reg()), deref_4f(v1_ptr, delta), t0);
+ brw_MAC(p, tmp, negate(deref_4f(v0_ptr, delta)), t0);
+ brw_ADD(p, deref_4f(dest_ptr, delta), deref_4f(v0_ptr, delta), tmp);
+ release_tmp(c, tmp);
+ }
+
+ /* Recreate the projected (NDC) coordinate in the new vertex header */
+ brw_clip_project_vertex(c, dest_ptr);
+
+ /* If we have noperspective attributes,
+ * we need to compute the screen-space t
+ */
+ if (c->has_noperspective_shading) {
+ GLuint delta = brw_varying_to_offset(&c->vue_map,
+ BRW_VARYING_SLOT_NDC);
+ struct brw_reg tmp = get_tmp(c);
+ t_nopersp = get_tmp(c);
+
+ /* t_nopersp = vec4(v1.xy, dest.xy) */
+ brw_MOV(p, t_nopersp, deref_4f(v1_ptr, delta));
+ brw_MOV(p, tmp, deref_4f(dest_ptr, delta));
+ brw_set_default_access_mode(p, BRW_ALIGN_16);
+ brw_MOV(p,
+ brw_writemask(t_nopersp, WRITEMASK_ZW),
+ brw_swizzle(tmp, BRW_SWIZZLE_XYXY));
+
+ /* t_nopersp = vec4(v1.xy, dest.xy) - v0.xyxy */
+ brw_ADD(p, t_nopersp, t_nopersp,
+ negate(brw_swizzle(v0_ndc_copy, BRW_SWIZZLE_XYXY)));
+
+ /* Add the absolute values of the X and Y deltas so that if
+ * the points aren't in the same place on the screen we get
+ * nonzero values to divide.
+ *
+ * After that, we have vert1 - vert0 in t_nopersp.x and
+ * vertnew - vert0 in t_nopersp.y
+ *
+ * t_nopersp = vec2(|v1.x -v0.x| + |v1.y -v0.y|,
+ * |dest.x-v0.x| + |dest.y-v0.y|)
+ */
+ brw_ADD(p,
+ brw_writemask(t_nopersp, WRITEMASK_XY),
+ brw_abs(brw_swizzle(t_nopersp, BRW_SWIZZLE_XZXZ)),
+ brw_abs(brw_swizzle(t_nopersp, BRW_SWIZZLE_YWYW)));
+ brw_set_default_access_mode(p, BRW_ALIGN_1);
+
+ /* If the points are in the same place, just substitute a
+ * value to avoid divide-by-zero
+ */
+ brw_CMP(p, vec1(brw_null_reg()), BRW_CONDITIONAL_EQ,
+ vec1(t_nopersp),
+ brw_imm_f(0));
+ brw_IF(p, BRW_EXECUTE_1);
+ brw_MOV(p, t_nopersp, brw_imm_vf4(brw_float_to_vf(1.0),
+ brw_float_to_vf(0.0),
+ brw_float_to_vf(0.0),
+ brw_float_to_vf(0.0)));
+ brw_ENDIF(p);
+
+ /* Now compute t_nopersp = t_nopersp.y/t_nopersp.x and broadcast it. */
+ brw_math_invert(p, get_element(t_nopersp, 0), get_element(t_nopersp, 0));
+ brw_MUL(p, vec1(t_nopersp), vec1(t_nopersp),
+ vec1(suboffset(t_nopersp, 1)));
+ brw_set_default_access_mode(p, BRW_ALIGN_16);
+ brw_MOV(p, t_nopersp, brw_swizzle(t_nopersp, BRW_SWIZZLE_XXXX));
+ brw_set_default_access_mode(p, BRW_ALIGN_1);
+
+ release_tmp(c, tmp);
+ release_tmp(c, v0_ndc_copy);
+ }
+
+ /* Now we can iterate over each attribute
+ * (could be done in pairs?)