diff options
-rw-r--r-- | src/gallium/drivers/nouveau/codegen/nv50_ir_from_tgsi.cpp | 60 |
1 files changed, 48 insertions, 12 deletions
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 69e1a341bc3..c085e3818ad 100644 --- a/src/gallium/drivers/nouveau/codegen/nv50_ir_from_tgsi.cpp +++ b/src/gallium/drivers/nouveau/codegen/nv50_ir_from_tgsi.cpp @@ -2733,24 +2733,60 @@ Converter::handleINTERP(Value *dst[4]) // Check whether the input is linear. All other attributes ignored. Instruction *insn; Value *offset = NULL, *ptr = NULL, *w = NULL; + Symbol *sym[4] = { NULL }; 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; + // In some odd cases, in large part due to varying packing, the source + // might not actually be an input. This is illegal TGSI, but it's easier to + // account for it here than it is to fix it where the TGSI is being + // generated. In that case, it's going to be a straight up mov (or sequence + // of mov's) from the input in question. We follow the mov chain to see + // which input we need to use. + if (src.getFile() != TGSI_FILE_INPUT) { + if (src.isIndirect(0)) { + ERROR("Ignoring indirect input interpolation\n"); + return; + } + FOR_EACH_DST_ENABLED_CHANNEL(0, c, tgsi) { + Value *val = fetchSrc(0, c); + assert(val->defs.size() == 1); + insn = val->getInsn(); + while (insn->op == OP_MOV) { + assert(insn->getSrc(0)->defs.size() == 1); + insn = insn->getSrc(0)->getInsn(); + if (!insn) { + ERROR("Miscompiling shader due to unhandled INTERP\n"); + return; + } + } + if (insn->op != OP_LINTERP && insn->op != OP_PINTERP) { + ERROR("Trying to interpolate non-input, this is not allowed.\n"); + return; + } + sym[c] = insn->getSrc(0)->asSym(); + assert(sym[c]); + op = insn->op; + mode = insn->ipa; + } } else { - op = OP_PINTERP; - mode = NV50_IR_INTERP_PERSPECTIVE; + if (src.isIndirect(0)) + ptr = fetchSrc(src.getIndirect(0), 0, NULL); + + // We can assume that the fixed index will point to an input of the same + // interpolation type in case of an indirect. + // TODO: Make use of ArrayID. + linear = info->in[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()) { @@ -2793,7 +2829,7 @@ Converter::handleINTERP(Value *dst[4]) FOR_EACH_DST_ENABLED_CHANNEL(0, c, tgsi) { - insn = mkOp1(op, TYPE_F32, dst[c], srcToSym(src, c)); + insn = mkOp1(op, TYPE_F32, dst[c], sym[c] ? sym[c] : srcToSym(src, c)); if (op == OP_PINTERP) insn->setSrc(1, w); if (ptr) |