nvc0: fix gl_SampleMaskIn computation
authorIlia Mirkin <imirkin@alum.mit.edu>
Sat, 9 Apr 2016 16:00:54 +0000 (12:00 -0400)
committerIlia Mirkin <imirkin@alum.mit.edu>
Thu, 12 May 2016 00:39:27 +0000 (20:39 -0400)
The SAMPLEMASK semantic should only return the bits set covered by the
current invocation. However we were always retrieving the covmask, which
returns the covered samples of the whole pixel.

When not doing per-sample invocation, this is precisely what we want.
However when doing per-sample invocation, we have to select the
sampleid'th bit and only return that. Furthermore, this means that we
have to have a 1:1 correlation for invocations and samples.

This fixes most

dEQP-GLES31.functional.shaders.sample_variables.sample_mask_in.*

tests. A few failures remain due to disagreements about nr_samples==1
logic as well as what happens with MSAA x2 RTs when the shading fraction
is 0.5.

Signed-off-by: Ilia Mirkin <imirkin@alum.mit.edu>
src/gallium/drivers/nouveau/codegen/nv50_ir_driver.h
src/gallium/drivers/nouveau/codegen/nv50_ir_emit_gk110.cpp
src/gallium/drivers/nouveau/codegen/nv50_ir_emit_gm107.cpp
src/gallium/drivers/nouveau/codegen/nv50_ir_emit_nvc0.cpp
src/gallium/drivers/nouveau/codegen/nv50_ir_from_tgsi.cpp
src/gallium/drivers/nouveau/codegen/nv50_ir_lowering_nvc0.cpp
src/gallium/drivers/nouveau/codegen/nv50_ir_lowering_nvc0.h
src/gallium/drivers/nouveau/nvc0/nvc0_program.c
src/gallium/drivers/nouveau/nvc0/nvc0_program.h
src/gallium/drivers/nouveau/nvc0/nvc0_state_validate.c

index 16dc1d1228209d20dcfad9fca15a40073e900b9e..1f7de51e3f6284126596fa48d9f8dde3ed97c878 100644 (file)
@@ -146,6 +146,8 @@ struct nv50_ir_prog_info
          bool earlyFragTests;
          bool separateFragData;
          bool usesDiscard;
+         bool persampleInvocation;
+         bool usesSampleMaskIn;
       } fp;
       struct {
          uint32_t inputOffset; /* base address for user args */
index 83009c5222e6edf970d76bfac5139080de9b307e..6a5981daadf93731f552883db1a032caec2ab06c 100644 (file)
@@ -1113,12 +1113,26 @@ CodeEmitterGK110::emitSLCT(const CmpInstruction *i)
    }
 }
 
+static void
+selpFlip(const FixupEntry *entry, uint32_t *code, const FixupData& data)
+{
+   int loc = entry->loc;
+   if (data.force_persample_interp)
+      code[loc + 1] |= 1 << 13;
+   else
+      code[loc + 1] &= ~(1 << 13);
+}
+
 void CodeEmitterGK110::emitSELP(const Instruction *i)
 {
    emitForm_21(i, 0x250, 0x050);
 
    if (i->src(2).mod & Modifier(NV50_IR_MOD_NOT))
       code[1] |= 1 << 13;
+
+   if (i->subOp == 1) {
+      addInterp(0, 0, selpFlip);
+   }
 }
 
 void CodeEmitterGK110::emitTEXBAR(const Instruction *i)
index 9dc2e309e044bfa8718d51c121404a8838e1bda8..a43d7b1296ae63d7cedba1729310f8ed18e86afb 100644 (file)
@@ -894,6 +894,16 @@ CodeEmitterGM107::emitI2I()
    emitGPR  (0x00, insn->def(0));
 }
 
+static void
+selpFlip(const FixupEntry *entry, uint32_t *code, const FixupData& data)
+{
+   int loc = entry->loc;
+   if (data.force_persample_interp)
+      code[loc + 1] |= 1 << 10;
+   else
+      code[loc + 1] &= ~(1 << 10);
+}
+
 void
 CodeEmitterGM107::emitSEL()
 {
@@ -915,9 +925,14 @@ CodeEmitterGM107::emitSEL()
       break;
    }
 
+   emitINV (0x2a, insn->src(2));
    emitPRED(0x27, insn->src(2));
    emitGPR (0x08, insn->src(0));
    emitGPR (0x00, insn->def(0));
+
+   if (insn->subOp == 1) {
+      addInterp(0, 0, selpFlip);
+   }
 }
 
 void
index 8819e3b3f5ee2626376227383148664f202f8243..14f4be4eed9f24c90eaa2b8cbc9f8ac18167c2d7 100644 (file)
@@ -1177,12 +1177,26 @@ CodeEmitterNVC0::emitSLCT(const CmpInstruction *i)
       code[0] |= 1 << 5;
 }
 
+static void
+selpFlip(const FixupEntry *entry, uint32_t *code, const FixupData& data)
+{
+   int loc = entry->loc;
+   if (data.force_persample_interp)
+      code[loc + 1] |= 1 << 20;
+   else
+      code[loc + 1] &= ~(1 << 20);
+}
+
 void CodeEmitterNVC0::emitSELP(const Instruction *i)
 {
    emitForm_A(i, HEX64(20000000, 00000004));
 
    if (i->src(2).mod & Modifier(NV50_IR_MOD_NOT))
       code[1] |= 1 << 20;
+
+   if (i->subOp == 1) {
+      addInterp(0, 0, selpFlip);
+   }
 }
 
 void CodeEmitterNVC0::emitTEXBAR(const Instruction *i)
index d59950eb6f4577f2dc5d6ebdef1fa5d6b7b39ecb..69e1a341bc3622729cb1a6027ca18ad75ba590ec 100644 (file)
@@ -1273,6 +1273,13 @@ bool Source::scanDeclaration(const struct tgsi_full_declaration *decl)
       case TGSI_SEMANTIC_DRAWID:
          info->prop.vp.usesDrawParameters = true;
          break;
+      case TGSI_SEMANTIC_SAMPLEID:
+      case TGSI_SEMANTIC_SAMPLEPOS:
+         info->prop.fp.persampleInvocation = true;
+         break;
+      case TGSI_SEMANTIC_SAMPLEMASK:
+         info->prop.fp.usesSampleMaskIn = true;
+         break;
       default:
          break;
       }
index 3bce9624ab6d98d7e6875f460fcfcc32d5a96b6e..1068c210f89442b301d27d1129e4b2273e9c8b98 100644 (file)
@@ -153,6 +153,7 @@ NVC0LegalizeSSA::visit(BasicBlock *bb)
 NVC0LegalizePostRA::NVC0LegalizePostRA(const Program *prog)
    : rZero(NULL),
      carry(NULL),
+     pOne(NULL),
      needTexBar(prog->getTarget()->getChipset() >= 0xe0)
 {
 }
@@ -451,10 +452,12 @@ NVC0LegalizePostRA::visit(Function *fn)
       insertTextureBarriers(fn);
 
    rZero = new_LValue(fn, FILE_GPR);
+   pOne = new_LValue(fn, FILE_PREDICATE);
    carry = new_LValue(fn, FILE_FLAGS);
 
    rZero->reg.data.id = prog->getTarget()->getFileSize(FILE_GPR);
    carry->reg.data.id = 0;
+   pOne->reg.data.id = 7;
 
    return true;
 }
@@ -466,8 +469,15 @@ NVC0LegalizePostRA::replaceZero(Instruction *i)
       if (s == 2 && i->op == OP_SUCLAMP)
          continue;
       ImmediateValue *imm = i->getSrc(s)->asImm();
-      if (imm && imm->reg.data.u64 == 0)
-         i->setSrc(s, rZero);
+      if (imm) {
+         if (i->op == OP_SELP && s == 2) {
+            i->setSrc(s, pOne);
+            if (imm->reg.data.u64 == 0)
+               i->src(s).mod = i->src(s).mod ^ Modifier(NV50_IR_MOD_NOT);
+         } else if (imm->reg.data.u64 == 0) {
+            i->setSrc(s, rZero);
+         }
+      }
    }
 }
 
@@ -2204,10 +2214,25 @@ NVC0LoweringPass::handleRDSV(Instruction *i)
                  off);
       break;
    }
-   case SV_SAMPLE_MASK:
+   case SV_SAMPLE_MASK: {
       ld = bld.mkOp1(OP_PIXLD, TYPE_U32, i->getDef(0), bld.mkImm(0));
       ld->subOp = NV50_IR_SUBOP_PIXLD_COVMASK;
+      Instruction *sampleid =
+         bld.mkOp1(OP_PIXLD, TYPE_U32, bld.getSSA(), bld.mkImm(0));
+      sampleid->subOp = NV50_IR_SUBOP_PIXLD_SAMPLEID;
+      Value *masked =
+         bld.mkOp2v(OP_AND, TYPE_U32, bld.getSSA(), ld->getDef(0),
+                    bld.mkOp2v(OP_SHL, TYPE_U32, bld.getSSA(),
+                               bld.loadImm(NULL, 1), sampleid->getDef(0)));
+      if (prog->driver->prop.fp.persampleInvocation) {
+         bld.mkMov(i->getDef(0), masked);
+      } else {
+         bld.mkOp3(OP_SELP, TYPE_U32, i->getDef(0), ld->getDef(0), masked,
+                   bld.mkImm(0))
+            ->subOp = 1;
+      }
       break;
+   }
    case SV_BASEVERTEX:
    case SV_BASEINSTANCE:
    case SV_DRAWID:
index 17883a9b8f63ae9976a99a536472cb2b48923cbe..c007e09439ecb97b98c6b52cbd7cd5f6cc53b783 100644 (file)
@@ -79,6 +79,7 @@ private:
 private:
    LValue *rZero;
    LValue *carry;
+   LValue *pOne;
    const bool needTexBar;
 };
 
index 944efa042bf05e15523e3bd87840a902cb1cd193..9db45c0759a69b61ca9deb769aff15092daa6836 100644 (file)
@@ -464,6 +464,7 @@ nvc0_fp_gen_header(struct nvc0_program *fp, struct nv50_ir_prog_info *info)
       fp->hdr[18] |= 0xf;
 
    fp->fp.early_z = info->prop.fp.earlyFragTests;
+   fp->fp.sample_mask_in = info->prop.fp.usesSampleMaskIn;
 
    return 0;
 }
index bd852e27c36064651fced87e8d95f2f7e9857f4c..08af3c823b828a7bcbc8f960adf452dae103bb2a 100644 (file)
@@ -48,6 +48,7 @@ struct nvc0_program {
       uint8_t early_z;
       uint8_t colors;
       uint8_t color_interp[2];
+      bool sample_mask_in;
       bool force_persample_interp;
       bool flatshade;
    } fp;
index e8d41729392940a4bccfb9e98f495b2d943b7282..4280db44bb63216904ffed1668385beb484081fb 100644 (file)
@@ -1,5 +1,6 @@
 
 #include "util/u_format.h"
+#include "util/u_framebuffer.h"
 #include "util/u_math.h"
 
 #include "nvc0/nvc0_context.h"
@@ -551,8 +552,14 @@ nvc0_validate_min_samples(struct nvc0_context *nvc0)
    int samples;
 
    samples = util_next_power_of_two(nvc0->min_samples);
-   if (samples > 1)
+   if (samples > 1) {
+      // If we're using the incoming sample mask and doing sample shading, we
+      // have to do sample shading "to the max", otherwise there's no way to
+      // tell which sets of samples are covered by the current invocation.
+      if (nvc0->fragprog->fp.sample_mask_in)
+         samples = util_framebuffer_get_num_samples(&nvc0->framebuffer);
       samples |= NVC0_3D_SAMPLE_SHADING_ENABLE;
+   }
 
    IMMED_NVC0(push, NVC0_3D(SAMPLE_SHADING), samples);
 }
@@ -708,6 +715,9 @@ validate_list_3d[] = {
     { nvc0_tevlprog_validate,      NVC0_NEW_3D_TEVLPROG },
     { nvc0_validate_tess_state,    NVC0_NEW_3D_TESSFACTOR },
     { nvc0_gmtyprog_validate,      NVC0_NEW_3D_GMTYPROG },
+    { nvc0_validate_min_samples,   NVC0_NEW_3D_MIN_SAMPLES |
+                                   NVC0_NEW_3D_FRAGPROG |
+                                   NVC0_NEW_3D_FRAMEBUFFER },
     { nvc0_fragprog_validate,      NVC0_NEW_3D_FRAGPROG | NVC0_NEW_3D_RASTERIZER },
     { nvc0_validate_derived_1,     NVC0_NEW_3D_FRAGPROG | NVC0_NEW_3D_ZSA |
                                    NVC0_NEW_3D_RASTERIZER },
@@ -726,7 +736,6 @@ validate_list_3d[] = {
     { nvc0_validate_buffers,       NVC0_NEW_3D_BUFFERS },
     { nvc0_idxbuf_validate,        NVC0_NEW_3D_IDXBUF },
     { nvc0_tfb_validate,           NVC0_NEW_3D_TFB_TARGETS | NVC0_NEW_3D_GMTYPROG },
-    { nvc0_validate_min_samples,   NVC0_NEW_3D_MIN_SAMPLES },
     { nvc0_validate_driverconst,   NVC0_NEW_3D_DRIVERCONST },
 };