+#include "glsl/ralloc.h"
+
+static inline void assign_vue_slot(struct brw_vue_map *vue_map,
+ int varying)
+{
+ /* Make sure this varying hasn't been assigned a slot already */
+ assert (vue_map->varying_to_slot[varying] == -1);
+
+ vue_map->varying_to_slot[varying] = vue_map->num_slots;
+ vue_map->slot_to_varying[vue_map->num_slots++] = varying;
+}
+
+/**
+ * Compute the VUE map for vertex shader program.
+ */
+void
+brw_compute_vue_map(struct brw_context *brw, struct brw_vue_map *vue_map,
+ GLbitfield64 slots_valid)
+{
+ vue_map->slots_valid = slots_valid;
+ int i;
+
+ /* gl_Layer doesn't get its own varying slot--it's stored in the virst VUE
+ * slot (VARYING_SLOT_PSIZ).
+ */
+ slots_valid &= ~VARYING_BIT_LAYER;
+
+ /* Make sure that the values we store in vue_map->varying_to_slot and
+ * vue_map->slot_to_varying won't overflow the signed chars that are used
+ * to store them. Note that since vue_map->slot_to_varying sometimes holds
+ * values equal to BRW_VARYING_SLOT_COUNT, we need to ensure that
+ * BRW_VARYING_SLOT_COUNT is <= 127, not 128.
+ */
+ STATIC_ASSERT(BRW_VARYING_SLOT_COUNT <= 127);
+
+ vue_map->num_slots = 0;
+ for (i = 0; i < BRW_VARYING_SLOT_COUNT; ++i) {
+ vue_map->varying_to_slot[i] = -1;
+ vue_map->slot_to_varying[i] = BRW_VARYING_SLOT_COUNT;
+ }
+
+ /* VUE header: format depends on chip generation and whether clipping is
+ * enabled.
+ */
+ switch (brw->gen) {
+ case 4:
+ case 5:
+ /* There are 8 dwords in VUE header pre-Ironlake:
+ * dword 0-3 is indices, point width, clip flags.
+ * dword 4-7 is ndc position
+ * dword 8-11 is the first vertex data.
+ *
+ * On Ironlake the VUE header is nominally 20 dwords, but the hardware
+ * will accept the same header layout as Gen4 [and should be a bit faster]
+ */
+ assign_vue_slot(vue_map, VARYING_SLOT_PSIZ);
+ assign_vue_slot(vue_map, BRW_VARYING_SLOT_NDC);
+ assign_vue_slot(vue_map, VARYING_SLOT_POS);
+ break;
+ case 6:
+ case 7:
+ /* There are 8 or 16 DWs (D0-D15) in VUE header on Sandybridge:
+ * dword 0-3 of the header is indices, point width, clip flags.
+ * dword 4-7 is the 4D space position
+ * dword 8-15 of the vertex header is the user clip distance if
+ * enabled.
+ * dword 8-11 or 16-19 is the first vertex element data we fill.
+ */
+ assign_vue_slot(vue_map, VARYING_SLOT_PSIZ);
+ assign_vue_slot(vue_map, VARYING_SLOT_POS);
+ if (slots_valid & BITFIELD64_BIT(VARYING_SLOT_CLIP_DIST0))
+ assign_vue_slot(vue_map, VARYING_SLOT_CLIP_DIST0);
+ if (slots_valid & BITFIELD64_BIT(VARYING_SLOT_CLIP_DIST1))
+ assign_vue_slot(vue_map, VARYING_SLOT_CLIP_DIST1);
+
+ /* front and back colors need to be consecutive so that we can use
+ * ATTRIBUTE_SWIZZLE_INPUTATTR_FACING to swizzle them when doing
+ * two-sided color.
+ */
+ if (slots_valid & BITFIELD64_BIT(VARYING_SLOT_COL0))
+ assign_vue_slot(vue_map, VARYING_SLOT_COL0);
+ if (slots_valid & BITFIELD64_BIT(VARYING_SLOT_BFC0))
+ assign_vue_slot(vue_map, VARYING_SLOT_BFC0);
+ if (slots_valid & BITFIELD64_BIT(VARYING_SLOT_COL1))
+ assign_vue_slot(vue_map, VARYING_SLOT_COL1);
+ if (slots_valid & BITFIELD64_BIT(VARYING_SLOT_BFC1))
+ assign_vue_slot(vue_map, VARYING_SLOT_BFC1);
+ break;
+ default:
+ assert (!"VUE map not known for this chip generation");
+ break;
+ }
+
+ /* The hardware doesn't care about the rest of the vertex outputs, so just
+ * assign them contiguously. Don't reassign outputs that already have a
+ * slot.
+ *
+ * We generally don't need to assign a slot for VARYING_SLOT_CLIP_VERTEX,
+ * since it's encoded as the clip distances by emit_clip_distances().
+ * However, it may be output by transform feedback, and we'd rather not
+ * recompute state when TF changes, so we just always include it.
+ */
+ for (int i = 0; i < VARYING_SLOT_MAX; ++i) {
+ if ((slots_valid & BITFIELD64_BIT(i)) &&
+ vue_map->varying_to_slot[i] == -1) {
+ assign_vue_slot(vue_map, i);
+ }
+ }
+}
+
+
+/**
+ * Decide which set of clip planes should be used when clipping via
+ * gl_Position or gl_ClipVertex.
+ */
+gl_clip_plane *brw_select_clip_planes(struct gl_context *ctx)
+{
+ if (ctx->Shader.CurrentVertexProgram) {
+ /* There is currently a GLSL vertex shader, so clip according to GLSL
+ * rules, which means compare gl_ClipVertex (or gl_Position, if
+ * gl_ClipVertex wasn't assigned) against the eye-coordinate clip planes
+ * that were stored in EyeUserPlane at the time the clip planes were
+ * specified.
+ */
+ return ctx->Transform.EyeUserPlane;
+ } else {
+ /* Either we are using fixed function or an ARB vertex program. In
+ * either case the clip planes are going to be compared against
+ * gl_Position (which is in clip coordinates) so we have to clip using
+ * _ClipUserPlane, which was transformed into clip coordinates by Mesa
+ * core.
+ */
+ return ctx->Transform._ClipUserPlane;
+ }
+}