i965: Fix last slot calculations
authorKenneth Graunke <kenneth@whitecape.org>
Wed, 14 Dec 2016 11:29:29 +0000 (03:29 -0800)
committerKenneth Graunke <kenneth@whitecape.org>
Thu, 5 Jan 2017 09:54:52 +0000 (01:54 -0800)
If the VUE map has slots at the end which the shader does not write,
then we'd "flush" (constructing an URB write) on the last output it
actually wrote.  Then, we'd construct another SEND with EOT, but with
no actual payload data.  That's not legal.

For example, SSO programs have clip distance slots allocated no matter
what, but the shader may not write them.  If it doesn't write any user
defined varyings, then the clip distance slots will be the last ones.

Found while debugging
dEQP-VK.tessellation.shader_input_output.gl_position_vs_to_tcs_to_tes

Cc: mesa-stable@lists.freedesktop.org
Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
Reviewed-by: Timothy Arceri <timothy.arceri@collabora.com>
src/mesa/drivers/dri/i965/brw_fs_visitor.cpp

index 14415bd5c7a17333e34a7ab5d1a84fe479bc138d..3775e6c4a094638c5a56c7d4ef0ddce29abc69ce 100644 (file)
@@ -672,6 +672,17 @@ fs_visitor::emit_urb_writes(const fs_reg &gs_vertex_count)
    length = 0;
    urb_offset = starting_urb_offset;
    flush = false;
+
+   /* SSO shaders can have VUE slots allocated which are never actually
+    * written to, so ignore them when looking for the last (written) slot.
+    */
+   int last_slot = vue_map->num_slots - 1;
+   while (last_slot > 0 &&
+          (vue_map->slot_to_varying[last_slot] == BRW_VARYING_SLOT_PAD ||
+           outputs[vue_map->slot_to_varying[last_slot]].file == BAD_FILE)) {
+      last_slot--;
+   }
+
    for (slot = 0; slot < vue_map->num_slots; slot++) {
       int varying = vue_map->slot_to_varying[slot];
       switch (varying) {
@@ -757,8 +768,7 @@ fs_visitor::emit_urb_writes(const fs_reg &gs_vertex_count)
        * the last slot or if we need to flush (see BAD_FILE varying case
        * above), emit a URB write send now to flush out the data.
        */
-      int last = slot == vue_map->num_slots - 1;
-      if (length == 8 || last)
+      if (length == 8 || slot == last_slot)
          flush = true;
       if (flush) {
          fs_reg *payload_sources =
@@ -777,7 +787,7 @@ fs_visitor::emit_urb_writes(const fs_reg &gs_vertex_count)
                            header_size);
 
          fs_inst *inst = abld.emit(opcode, reg_undef, payload);
-         inst->eot = last && stage != MESA_SHADER_GEOMETRY;
+         inst->eot = slot == last_slot && stage != MESA_SHADER_GEOMETRY;
          inst->mlen = length + header_size;
          inst->offset = urb_offset;
          urb_offset = starting_urb_offset + slot + 1;