From acaed8f41d3cf57092f3fe3a607b8069c72b57f1 Mon Sep 17 00:00:00 2001 From: Ilia Mirkin Date: Sat, 5 Jul 2014 23:05:35 -0400 Subject: [PATCH] nvc0/ir: add support for interpolating with non-default settings Signed-off-by: Ilia Mirkin --- .../nouveau/codegen/nv50_ir_build_util.cpp | 1 + .../nouveau/codegen/nv50_ir_from_tgsi.cpp | 85 +++++++++++++++++++ .../nouveau/codegen/nv50_ir_lowering_nvc0.cpp | 9 +- 3 files changed, 94 insertions(+), 1 deletion(-) diff --git a/src/gallium/drivers/nouveau/codegen/nv50_ir_build_util.cpp b/src/gallium/drivers/nouveau/codegen/nv50_ir_build_util.cpp index 6d9c830ddc8..708c5b322ee 100644 --- a/src/gallium/drivers/nouveau/codegen/nv50_ir_build_util.cpp +++ b/src/gallium/drivers/nouveau/codegen/nv50_ir_build_util.cpp @@ -163,6 +163,7 @@ BuildUtil::mkInterp(unsigned mode, Value *dst, int32_t offset, Value *rel) Instruction *insn = mkOp1(op, ty, dst, sym); insn->setIndirect(0, 0, rel); + insn->setInterpolate(mode); return insn; } 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 93f96a1b731..14b6d68c4a1 100644 --- a/src/gallium/drivers/nouveau/codegen/nv50_ir_from_tgsi.cpp +++ b/src/gallium/drivers/nouveau/codegen/nv50_ir_from_tgsi.cpp @@ -1202,6 +1202,8 @@ private: void handleSTORE(); void handleATOM(Value *dst0[4], DataType, uint16_t subOp); + void handleINTERP(Value *dst0[4]); + Value *interpolate(tgsi::Instruction::SrcRegister, int c, Value *ptr); void insertConvergenceOps(BasicBlock *conv, BasicBlock *fork); @@ -2132,6 +2134,84 @@ Converter::handleATOM(Value *dst0[4], DataType ty, uint16_t subOp) dst0[c] = dst; // not equal to rDst so handleInstruction will do mkMov } +void +Converter::handleINTERP(Value *dst[4]) +{ + // Check whether the input is linear. All other attributes ignored. + Instruction *insn; + Value *offset = NULL, *ptr = NULL, *w; + bool linear; + operation op; + int c, mode; + + tgsi::Instruction::SrcRegister src = tgsi.getSrc(0); + assert(src.getFile() == TGSI_FILE_INPUT); + + if (src.isIndirect(0)) + ptr = fetchSrc(src.getIndirect(0), 0, NULL); + + // XXX: no way to know interp mode if we don't know the index + linear = info->in[ptr ? 0 : src.getIndex(0)].linear; + if (linear) { + op = OP_LINTERP; + mode = NV50_IR_INTERP_LINEAR; + } else { + op = OP_PINTERP; + mode = NV50_IR_INTERP_PERSPECTIVE; + } + + switch (tgsi.getOpcode()) { + case TGSI_OPCODE_INTERP_CENTROID: + mode |= NV50_IR_INTERP_CENTROID; + break; + case TGSI_OPCODE_INTERP_SAMPLE: + insn = mkOp1(OP_PIXLD, TYPE_U32, (offset = getScratch()), fetchSrc(1, 0)); + insn->subOp = NV50_IR_SUBOP_PIXLD_OFFSET; + mode |= NV50_IR_INTERP_OFFSET; + break; + case TGSI_OPCODE_INTERP_OFFSET: { + // The input in src1.xy is float, but we need a single 32-bit value + // where the upper and lower 16 bits are encoded in S0.12 format. We need + // to clamp the input coordinates to (-0.5, 0.4375), multiply by 4096, + // and then convert to s32. + Value *offs[2]; + for (c = 0; c < 2; c++) { + offs[c] = fetchSrc(1, c); + mkOp2(OP_MIN, TYPE_F32, offs[c], offs[c], loadImm(NULL, 0.4375f)); + mkOp2(OP_MAX, TYPE_F32, offs[c], offs[c], loadImm(NULL, -0.5f)); + mkOp2(OP_MUL, TYPE_F32, offs[c], offs[c], loadImm(NULL, 4096.0f)); + mkCvt(OP_CVT, TYPE_S32, offs[c], TYPE_F32, offs[c]); + } + offset = mkOp3v(OP_INSBF, TYPE_U32, getScratch(), + offs[1], mkImm(0x1010), offs[0]); + mode |= NV50_IR_INTERP_OFFSET; + break; + } + } + + if (op == OP_PINTERP) { + if (offset) { + w = mkOp2v(OP_RDSV, TYPE_F32, getSSA(), mkSysVal(SV_POSITION, 3), offset); + mkOp1(OP_RCP, TYPE_F32, w, w); + } else { + w = fragCoord[3]; + } + } + + + FOR_EACH_DST_ENABLED_CHANNEL(0, c, tgsi) { + insn = mkOp1(op, TYPE_F32, dst[c], srcToSym(src, c)); + if (op == OP_PINTERP) + insn->setSrc(1, w); + if (ptr) + insn->setIndirect(0, 0, ptr); + if (offset) + insn->setSrc(op == OP_PINTERP ? 2 : 1, offset); + + insn->setInterpolate(mode); + } +} + Converter::Subroutine * Converter::getSubroutine(unsigned ip) { @@ -2796,6 +2876,11 @@ Converter::handleInstruction(const struct tgsi_full_instruction *insn) mkOp2(OP_POPCNT, TYPE_U32, dst0[c], src0, src0); } break; + case TGSI_OPCODE_INTERP_CENTROID: + case TGSI_OPCODE_INTERP_SAMPLE: + case TGSI_OPCODE_INTERP_OFFSET: + handleINTERP(dst0); + break; default: ERROR("unhandled TGSI opcode: %u\n", tgsi.getOpcode()); assert(0); diff --git a/src/gallium/drivers/nouveau/codegen/nv50_ir_lowering_nvc0.cpp b/src/gallium/drivers/nouveau/codegen/nv50_ir_lowering_nvc0.cpp index bc95cd843ea..cc4808c0010 100644 --- a/src/gallium/drivers/nouveau/codegen/nv50_ir_lowering_nvc0.cpp +++ b/src/gallium/drivers/nouveau/codegen/nv50_ir_lowering_nvc0.cpp @@ -1354,7 +1354,14 @@ NVC0LoweringPass::handleRDSV(Instruction *i) switch (sv) { case SV_POSITION: assert(prog->getType() == Program::TYPE_FRAGMENT); - bld.mkInterp(NV50_IR_INTERP_LINEAR, i->getDef(0), addr, NULL); + if (i->srcExists(1)) { + // Pass offset through to the interpolation logic + ld = bld.mkInterp(NV50_IR_INTERP_LINEAR | NV50_IR_INTERP_OFFSET, + i->getDef(0), addr, NULL); + ld->setSrc(1, i->getSrc(1)); + } else { + bld.mkInterp(NV50_IR_INTERP_LINEAR, i->getDef(0), addr, NULL); + } break; case SV_FACE: { -- 2.30.2