case TGSI_SEMANTIC_TESSOUTER: return nv50_ir::SV_TESS_OUTER;
case TGSI_SEMANTIC_TESSINNER: return nv50_ir::SV_TESS_INNER;
case TGSI_SEMANTIC_VERTICESIN: return nv50_ir::SV_VERTEX_COUNT;
+ case TGSI_SEMANTIC_HELPER_INVOCATION: return nv50_ir::SV_THREAD_KILL;
default:
assert(0);
return nv50_ir::SV_CLOCK;
NV50_IR_OPCODE_CASE(SAD, SAD);
NV50_IR_OPCODE_CASE(TXF, TXF);
NV50_IR_OPCODE_CASE(TXQ, TXQ);
+ NV50_IR_OPCODE_CASE(TXQS, TXQ);
NV50_IR_OPCODE_CASE(TG4, TXG);
NV50_IR_OPCODE_CASE(LODQ, TXLQ);
info->bin.tlsSpace += (scan.file_max[TGSI_FILE_TEMPORARY] + 1) * 16;
if (info->io.genUserClip > 0) {
- info->io.clipDistanceMask = (1 << info->io.genUserClip) - 1;
+ info->io.clipDistances = info->io.genUserClip;
const unsigned int nOut = (info->io.genUserClip + 3) / 4;
info->out[i].id = i;
info->out[i].sn = TGSI_SEMANTIC_CLIPDIST;
info->out[i].si = n;
- info->out[i].mask = info->io.clipDistanceMask >> (n * 4);
+ info->out[i].mask = ((1 << info->io.clipDistances) - 1) >> (n * 4);
}
}
else
info->prop.tp.outputPrim = PIPE_PRIM_TRIANGLES; /* anything but points */
break;
+ case TGSI_PROPERTY_NUM_CLIPDIST_ENABLED:
+ info->io.clipDistances = prop->u[0].Data;
+ break;
+ case TGSI_PROPERTY_NUM_CULLDIST_ENABLED:
+ info->io.cullDistances = prop->u[0].Data;
+ break;
default:
INFO("unhandled TGSI property %d\n", prop->Property.PropertyName);
break;
default:
break;
}
- if (decl->Interp.Location || info->io.sampleInterp)
+ if (decl->Interp.Location)
info->in[i].centroid = 1;
}
clipVertexOutput = i;
break;
case TGSI_SEMANTIC_CLIPDIST:
- info->io.clipDistanceMask |=
- decl->Declaration.UsageMask << (si * 4);
info->io.genUserClip = -1;
break;
case TGSI_SEMANTIC_SAMPLEMASK:
case TGSI_SEMANTIC_VERTEXID:
info->io.vertexId = first;
break;
+ case TGSI_SEMANTIC_SAMPLEID:
+ case TGSI_SEMANTIC_SAMPLEPOS:
+ info->prop.fp.sampleInterp = 1;
+ break;
default:
break;
}
void setTexRS(TexInstruction *, unsigned int& s, int R, int S);
void handleTEX(Value *dst0[4], int R, int S, int L, int C, int Dx, int Dy);
void handleTXF(Value *dst0[4], int R, int L_M);
- void handleTXQ(Value *dst0[4], enum TexQuery);
+ void handleTXQ(Value *dst0[4], enum TexQuery, int R);
void handleLIT(Value *dst0[4]);
void handleUserClipPlanes();
void handleINTERP(Value *dst0[4]);
+ uint8_t translateInterpMode(const struct nv50_ir_varying *var,
+ operation& op);
Value *interpolate(tgsi::Instruction::SrcRegister, int c, Value *ptr);
void insertConvergenceOps(BasicBlock *conv, BasicBlock *fork);
Value *vtxBase[5]; // base address of vertex in primitive (for TP/GP)
uint8_t vtxBaseValid;
+ Value *outBase; // base address of vertex out patch (for TCP)
+
Stack condBBs; // fork BB, then else clause BB
Stack joinBBs; // fork BB, for inserting join ops on ENDIF
Stack loopBBs; // loop headers
return sym;
}
-static inline uint8_t
-translateInterpMode(const struct nv50_ir_varying *var, operation& op)
+uint8_t
+Converter::translateInterpMode(const struct nv50_ir_varying *var, operation& op)
{
uint8_t mode = NV50_IR_INTERP_PERSPECTIVE;
op = (mode == NV50_IR_INTERP_PERSPECTIVE || mode == NV50_IR_INTERP_SC)
? OP_PINTERP : OP_LINTERP;
- if (var->centroid)
+ if (var->centroid || info->prop.fp.sampleInterp)
mode |= NV50_IR_INTERP_CENTROID;
return mode;
fetchSrc(tgsi.getSrc(s).getIndirect(1), 0, NULL),
offset);
vtxBaseValid |= 1 << s;
- vtxBase[s] = mkOp2v(
- OP_ADD, TYPE_U32, getSSA(),
- mkOp2v(
- OP_SUB, TYPE_U32, getSSA(),
- mkOp1v(OP_RDSV, TYPE_U32, getSSA(), mkSysVal(SV_LANEID, 0)),
- mkOp1v(OP_RDSV, TYPE_U32, getSSA(), mkSysVal(SV_INVOCATION_ID, 0))),
- offset);
+ vtxBase[s] = mkOp2v(OP_ADD, TYPE_U32, getSSA(), outBase, offset);
}
return vtxBase[s];
}
// don't load masked inputs, won't be assigned a slot
if (!ptr && !(info->in[idx].mask & (1 << swz)))
return loadImm(NULL, swz == TGSI_SWIZZLE_W ? 1.0f : 0.0f);
- if (!ptr && info->in[idx].sn == TGSI_SEMANTIC_FACE)
+ if (!ptr && info->in[idx].sn == TGSI_SEMANTIC_FACE)
return mkOp1v(OP_RDSV, TYPE_F32, getSSA(), mkSysVal(SV_FACE, 0));
return interpolate(src, c, shiftAddress(ptr));
} else
}
void
-Converter::handleTXQ(Value *dst0[4], enum TexQuery query)
+Converter::handleTXQ(Value *dst0[4], enum TexQuery query, int R)
{
TexInstruction *tex = new_TexInstruction(func, OP_TXQ);
tex->tex.query = query;
tex->tex.mask |= 1 << c;
tex->setDef(d++, dst0[c]);
}
- tex->setSrc((c = 0), fetchSrc(0, 0)); // mip level
+ if (query == TXQ_DIMS)
+ tex->setSrc((c = 0), fetchSrc(0, 0)); // mip level
+ else
+ tex->setSrc((c = 0), zero);
- setTexRS(tex, ++c, 1, -1);
+ setTexRS(tex, ++c, R, -1);
bb->insertTail(tex);
}
break;
case TGSI_OPCODE_TXQ:
case TGSI_OPCODE_SVIEWINFO:
- handleTXQ(dst0, TXQ_DIMS);
+ handleTXQ(dst0, TXQ_DIMS, 1);
+ break;
+ case TGSI_OPCODE_TXQS:
+ // The TXQ_TYPE query returns samples in its 3rd arg, but we need it to
+ // be in .x
+ dst0[1] = dst0[2] = dst0[3] = NULL;
+ std::swap(dst0[0], dst0[2]);
+ handleTXQ(dst0, TXQ_TYPE, 0);
+ std::swap(dst0[0], dst0[2]);
break;
case TGSI_OPCODE_F2I:
case TGSI_OPCODE_F2U:
bb->cfg.attach(&loopBB->cfg, Graph::Edge::BACK);
}
setPosition(reinterpret_cast<BasicBlock *>(breakBBs.pop().u.p), true);
+
+ // If the loop never breaks (e.g. only has RET's inside), then there
+ // will be no way to get to the break bb. However BGNLOOP will have
+ // already made a PREBREAK to it, so it must be in the CFG.
+ if (getBB()->cfg.incidentCount() == 0)
+ loopBB->cfg.attach(&getBB()->cfg, Graph::Edge::TREE);
}
break;
case TGSI_OPCODE_BRK:
case TGSI_OPCODE_UBFE:
FOR_EACH_DST_ENABLED_CHANNEL(0, c, tgsi) {
src0 = fetchSrc(0, c);
- src1 = fetchSrc(1, c);
- src2 = fetchSrc(2, c);
- mkOp3(OP_INSBF, TYPE_U32, src1, src2, mkImm(0x808), src1);
+ if (tgsi.getSrc(1).getFile() == TGSI_FILE_IMMEDIATE &&
+ tgsi.getSrc(2).getFile() == TGSI_FILE_IMMEDIATE) {
+ src1 = loadImm(NULL, tgsi.getSrc(2).getValueU32(c, info) << 8 |
+ tgsi.getSrc(1).getValueU32(c, info));
+ } else {
+ src1 = fetchSrc(1, c);
+ src2 = fetchSrc(2, c);
+ mkOp3(OP_INSBF, TYPE_U32, src1, src2, mkImm(0x808), src1);
+ }
mkOp2(OP_EXTBF, dstTy, dst0[c], src0, src1);
}
break;
clipVtx[c] = getScratch();
}
- if (prog->getType() == Program::TYPE_FRAGMENT) {
+ switch (prog->getType()) {
+ case Program::TYPE_TESSELLATION_CONTROL:
+ outBase = mkOp2v(
+ OP_SUB, TYPE_U32, getSSA(),
+ mkOp1v(OP_RDSV, TYPE_U32, getSSA(), mkSysVal(SV_LANEID, 0)),
+ mkOp1v(OP_RDSV, TYPE_U32, getSSA(), mkSysVal(SV_INVOCATION_ID, 0)));
+ break;
+ case Program::TYPE_FRAGMENT: {
Symbol *sv = mkSysVal(SV_POSITION, 3);
fragCoord[3] = mkOp1v(OP_RDSV, TYPE_F32, getSSA(), sv);
mkOp1(OP_RCP, TYPE_F32, fragCoord[3], fragCoord[3]);
+ break;
+ }
+ default:
+ break;
}
if (info->io.viewportId >= 0)