Mesa (10.2): nv50/ir: allow gl_ViewportIndex to work on non-provoking vertices

Carl Worth cworth at kemper.freedesktop.org
Fri Jul 4 04:07:35 UTC 2014


Module: Mesa
Branch: 10.2
Commit: bcff69f18f9f7751aa998e08245d3f0ef8e45151
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=bcff69f18f9f7751aa998e08245d3f0ef8e45151

Author: Tobias Klausmann <tobias.johannes.klausmann at mni.thm.de>
Date:   Mon Jun 23 23:01:42 2014 +0200

nv50/ir: allow gl_ViewportIndex to work on non-provoking vertices

Previously, if we had something like:

  gl_ViewportIndex = idx;
  for(int i = 0; i < gl_in.length(); i++) {
     gl_Position = gl_in[i].gl_Position;
     EmitVertex();
  }
  EndPrimitive();

The right viewport index would not be set on the primitive because the
last vertex is the provoking one. However blob drivers appear to move
the gl_ViewportIndex write into the for loop, allowing the application
to be ignorant of this detail.

While the application is technically wrong here, because the blob does
it and other drivers appear to implicitly work this way as well, we add
a buffer register that viewport index writes go into, which is then
exported before every EmitVertex() call.

This fixes the remaining piglit tests in ARB_viewport_array for nv50/nvc0.

Signed-off-by: Tobias Klausmann <tobias.johannes.klausmann at mni.thm.de>
Cc: "10.2" <mesa-stable at lists.freedesktop.org>
Reviewed-by: Ilia Mirkin <imirkin at alum.mit.edu>
(cherry picked from commit 98a86f61a8d17eaafaf5907debc7735aa20610d5)

---

 .../drivers/nouveau/codegen/nv50_ir_driver.h       |    1 +
 .../drivers/nouveau/codegen/nv50_ir_from_tgsi.cpp  |   31 ++++++++++++++++++--
 2 files changed, 30 insertions(+), 2 deletions(-)

diff --git a/src/gallium/drivers/nouveau/codegen/nv50_ir_driver.h b/src/gallium/drivers/nouveau/codegen/nv50_ir_driver.h
index d7a9c2c..ee967e1 100644
--- a/src/gallium/drivers/nouveau/codegen/nv50_ir_driver.h
+++ b/src/gallium/drivers/nouveau/codegen/nv50_ir_driver.h
@@ -177,6 +177,7 @@ struct nv50_ir_prog_info
       uint8_t vertexId;          /* system value index of VertexID */
       uint8_t edgeFlagIn;
       uint8_t edgeFlagOut;
+      int8_t viewportId;         /* output index of ViewportIndex */
       uint8_t fragDepth;         /* output index of FragDepth */
       uint8_t sampleMask;        /* output index of SampleMask */
       boolean sampleInterp;      /* perform sample interp on all fp inputs */
diff --git a/src/gallium/drivers/nouveau/codegen/nv50_ir_from_tgsi.cpp b/src/gallium/drivers/nouveau/codegen/nv50_ir_from_tgsi.cpp
index a0f1fe1..2ba3c1c 100644
--- a/src/gallium/drivers/nouveau/codegen/nv50_ir_from_tgsi.cpp
+++ b/src/gallium/drivers/nouveau/codegen/nv50_ir_from_tgsi.cpp
@@ -790,6 +790,8 @@ bool Source::scanSource()
       info->prop.gp.instanceCount = 1; // default value
    }
 
+   info->io.viewportId = -1;
+
    info->immd.data = (uint32_t *)MALLOC(scan.immediate_count * 16);
    info->immd.type = (ubyte *)MALLOC(scan.immediate_count * sizeof(ubyte));
 
@@ -982,6 +984,9 @@ bool Source::scanDeclaration(const struct tgsi_full_declaration *decl)
          case TGSI_SEMANTIC_SAMPLEMASK:
             info->io.sampleMask = i;
             break;
+         case TGSI_SEMANTIC_VIEWPORT_INDEX:
+            info->io.viewportId = i;
+            break;
          default:
             break;
          }
@@ -1258,6 +1263,8 @@ private:
    Stack joinBBs;  // fork BB, for inserting join ops on ENDIF
    Stack loopBBs;  // loop headers
    Stack breakBBs; // end of / after loop
+
+   Value *viewport;
 };
 
 Symbol *
@@ -1555,8 +1562,16 @@ Converter::storeDst(const tgsi::Instruction::DstRegister dst, int c,
       mkOp2(OP_WRSV, TYPE_U32, NULL, dstToSym(dst, c), val);
    } else
    if (f == TGSI_FILE_OUTPUT && prog->getType() != Program::TYPE_FRAGMENT) {
-      if (ptr || (info->out[idx].mask & (1 << c)))
-         mkStore(OP_EXPORT, TYPE_U32, dstToSym(dst, c), ptr, val);
+
+      if (ptr || (info->out[idx].mask & (1 << c))) {
+         /* Save the viewport index into a scratch register so that it can be
+            exported at EMIT time */
+         if (info->out[idx].sn == TGSI_SEMANTIC_VIEWPORT_INDEX &&
+             viewport != NULL)
+            mkOp1(OP_MOV, TYPE_U32, viewport, val);
+         else
+            mkStore(OP_EXPORT, TYPE_U32, dstToSym(dst, c), ptr, val);
+      }
    } else
    if (f == TGSI_FILE_TEMPORARY ||
        f == TGSI_FILE_PREDICATE ||
@@ -2523,6 +2538,13 @@ Converter::handleInstruction(const struct tgsi_full_instruction *insn)
          mkCvt(OP_CVT, dstTy, dst0[c], srcTy, fetchSrc(0, c));
       break;
    case TGSI_OPCODE_EMIT:
+      /* export the saved viewport index */
+      if (viewport != NULL) {
+         Symbol *vpSym = mkSymbol(FILE_SHADER_OUTPUT, 0, TYPE_U32,
+                                  info->out[info->io.viewportId].slot[0] * 4);
+         mkStore(OP_EXPORT, TYPE_U32, vpSym, NULL, viewport);
+      }
+      /* fallthrough */
    case TGSI_OPCODE_ENDPRIM:
       // get vertex stream if specified (must be immediate)
       src0 = tgsi.srcCount() ?
@@ -2952,6 +2974,11 @@ Converter::run()
       mkOp1(OP_RCP, TYPE_F32, fragCoord[3], fragCoord[3]);
    }
 
+   if (info->io.viewportId >= 0)
+      viewport = getScratch();
+   else
+      viewport = NULL;
+
    for (ip = 0; ip < code->scan.num_instructions; ++ip) {
       if (!handleInstruction(&code->insns[ip]))
          return false;




More information about the mesa-commit mailing list