summaryrefslogtreecommitdiff
path: root/src/gallium/drivers/nouveau/codegen
diff options
context:
space:
mode:
authorIlia Mirkin <imirkin@alum.mit.edu>2015-10-20 18:03:40 -0400
committerIlia Mirkin <imirkin@alum.mit.edu>2015-10-29 00:44:22 -0400
commitb75fff70d82474a571c59c2a3a01e4f9f02286a7 (patch)
tree3ef1249221ecab3eeddb9460ea1c256fc4c06d2c /src/gallium/drivers/nouveau/codegen
parent77f58c04cc287b72e2b859d71591da158db6830a (diff)
nvc0: do upload-time fixups for interpolation parameters
Unfortunately flatshading is an all-or-nothing proposition on nvc0, while GL 3.0 calls for the ability to selectively specify explicit interpolation parameters on gl_Color/gl_SecondaryColor which would override the flatshading setting. This allows us to fix up the interpolation settings after shader generation based on rasterizer settings. While we're at it, we can add support for dynamically forcing all (non-flat) shader inputs to be interpolated per-sample, which allows st/mesa to not generate variants for these. Fixes the remaining failing glsl-1.30/execution/interpolation piglits. Signed-off-by: Ilia Mirkin <imirkin@alum.mit.edu>
Diffstat (limited to 'src/gallium/drivers/nouveau/codegen')
-rw-r--r--src/gallium/drivers/nouveau/codegen/nv50_ir_driver.h5
-rw-r--r--src/gallium/drivers/nouveau/codegen/nv50_ir_emit_gk110.cpp31
-rw-r--r--src/gallium/drivers/nouveau/codegen/nv50_ir_emit_gm107.cpp26
-rw-r--r--src/gallium/drivers/nouveau/codegen/nv50_ir_emit_nvc0.cpp30
-rw-r--r--src/gallium/drivers/nouveau/codegen/nv50_ir_from_tgsi.cpp14
-rw-r--r--src/gallium/drivers/nouveau/codegen/nv50_ir_target.cpp39
-rw-r--r--src/gallium/drivers/nouveau/codegen/nv50_ir_target.h21
7 files changed, 157 insertions, 9 deletions
diff --git a/src/gallium/drivers/nouveau/codegen/nv50_ir_driver.h b/src/gallium/drivers/nouveau/codegen/nv50_ir_driver.h
index 2b9edcf9172..3cc467fdb13 100644
--- a/src/gallium/drivers/nouveau/codegen/nv50_ir_driver.h
+++ b/src/gallium/drivers/nouveau/codegen/nv50_ir_driver.h
@@ -99,6 +99,7 @@ struct nv50_ir_prog_info
uint8_t sourceRep; /* NV50_PROGRAM_IR */
const void *source;
void *relocData;
+ void *interpData;
struct nv50_ir_prog_symbol *syms;
uint16_t numSyms;
} bin;
@@ -198,6 +199,10 @@ extern void nv50_ir_relocate_code(void *relocData, uint32_t *code,
uint32_t libPos,
uint32_t dataPos);
+extern void
+nv50_ir_change_interp(void *interpData, uint32_t *code,
+ bool force_per_sample, bool flatshade);
+
/* obtain code that will be shared among programs */
extern void nv50_ir_get_target_library(uint32_t chipset,
const uint32_t **code, uint32_t *size);
diff --git a/src/gallium/drivers/nouveau/codegen/nv50_ir_emit_gk110.cpp b/src/gallium/drivers/nouveau/codegen/nv50_ir_emit_gk110.cpp
index 8f1542959c9..d712c9c300a 100644
--- a/src/gallium/drivers/nouveau/codegen/nv50_ir_emit_gk110.cpp
+++ b/src/gallium/drivers/nouveau/codegen/nv50_ir_emit_gk110.cpp
@@ -1437,6 +1437,30 @@ CodeEmitterGK110::emitInterpMode(const Instruction *i)
code[1] |= (i->ipa & 0xc) << (19 - 2);
}
+static void
+interpApply(const InterpEntry *entry, uint32_t *code,
+ bool force_persample_interp, bool flatshade)
+{
+ int ipa = entry->ipa;
+ int reg = entry->reg;
+ int loc = entry->loc;
+
+ if (flatshade &&
+ (ipa & NV50_IR_INTERP_MODE_MASK) == NV50_IR_INTERP_SC) {
+ ipa = NV50_IR_INTERP_FLAT;
+ reg = 0xff;
+ } else if (force_persample_interp &&
+ (ipa & NV50_IR_INTERP_SAMPLE_MASK) == NV50_IR_INTERP_DEFAULT &&
+ (ipa & NV50_IR_INTERP_MODE_MASK) != NV50_IR_INTERP_FLAT) {
+ ipa |= NV50_IR_INTERP_CENTROID;
+ }
+ code[loc + 1] &= ~(0xf << 19);
+ code[loc + 1] |= (ipa & 0x3) << 21;
+ code[loc + 1] |= (ipa & 0xc) << (19 - 2);
+ code[loc + 0] &= ~(0xff << 23);
+ code[loc + 0] |= reg << 23;
+}
+
void
CodeEmitterGK110::emitINTERP(const Instruction *i)
{
@@ -1448,10 +1472,13 @@ CodeEmitterGK110::emitINTERP(const Instruction *i)
if (i->saturate)
code[1] |= 1 << 18;
- if (i->op == OP_PINTERP)
+ if (i->op == OP_PINTERP) {
srcId(i->src(1), 23);
- else
+ addInterp(i->ipa, SDATA(i->src(1)).id, interpApply);
+ } else {
code[0] |= 0xff << 23;
+ addInterp(i->ipa, 0xff, interpApply);
+ }
srcId(i->src(0).getIndirect(0), 10);
emitInterpMode(i);
diff --git a/src/gallium/drivers/nouveau/codegen/nv50_ir_emit_gm107.cpp b/src/gallium/drivers/nouveau/codegen/nv50_ir_emit_gm107.cpp
index 6e22788341f..a327d572470 100644
--- a/src/gallium/drivers/nouveau/codegen/nv50_ir_emit_gm107.cpp
+++ b/src/gallium/drivers/nouveau/codegen/nv50_ir_emit_gm107.cpp
@@ -2217,6 +2217,30 @@ CodeEmitterGM107::emitAL2P()
emitGPR (0x00, insn->def(0));
}
+static void
+interpApply(const InterpEntry *entry, uint32_t *code,
+ bool force_persample_interp, bool flatshade)
+{
+ int ipa = entry->ipa;
+ int reg = entry->reg;
+ int loc = entry->loc;
+
+ if (flatshade &&
+ (ipa & NV50_IR_INTERP_MODE_MASK) == NV50_IR_INTERP_SC) {
+ ipa = NV50_IR_INTERP_FLAT;
+ reg = 0xff;
+ } else if (force_persample_interp &&
+ (ipa & NV50_IR_INTERP_SAMPLE_MASK) == NV50_IR_INTERP_DEFAULT &&
+ (ipa & NV50_IR_INTERP_MODE_MASK) != NV50_IR_INTERP_FLAT) {
+ ipa |= NV50_IR_INTERP_CENTROID;
+ }
+ code[loc + 1] &= ~(0xf << 0x14);
+ code[loc + 1] |= (ipa & 0x3) << 0x16;
+ code[loc + 1] |= (ipa & 0xc) << (0x14 - 2);
+ code[loc + 0] &= ~(0xff << 0x14);
+ code[loc + 0] |= reg << 0x14;
+}
+
void
CodeEmitterGM107::emitIPA()
{
@@ -2255,10 +2279,12 @@ CodeEmitterGM107::emitIPA()
emitGPR(0x14, insn->src(1));
if (insn->getSampleMode() == NV50_IR_INTERP_OFFSET)
emitGPR(0x27, insn->src(2));
+ addInterp(insn->ipa, insn->getSrc(1)->reg.data.id, interpApply);
} else {
if (insn->getSampleMode() == NV50_IR_INTERP_OFFSET)
emitGPR(0x27, insn->src(1));
emitGPR(0x14);
+ addInterp(insn->ipa, 0xff, interpApply);
}
if (insn->getSampleMode() != NV50_IR_INTERP_OFFSET)
diff --git a/src/gallium/drivers/nouveau/codegen/nv50_ir_emit_nvc0.cpp b/src/gallium/drivers/nouveau/codegen/nv50_ir_emit_nvc0.cpp
index 6bf5219d346..fd103146c72 100644
--- a/src/gallium/drivers/nouveau/codegen/nv50_ir_emit_nvc0.cpp
+++ b/src/gallium/drivers/nouveau/codegen/nv50_ir_emit_nvc0.cpp
@@ -1618,6 +1618,29 @@ CodeEmitterNVC0::emitInterpMode(const Instruction *i)
}
}
+static void
+interpApply(const InterpEntry *entry, uint32_t *code,
+ bool force_persample_interp, bool flatshade)
+{
+ int ipa = entry->ipa;
+ int reg = entry->reg;
+ int loc = entry->loc;
+
+ if (flatshade &&
+ (ipa & NV50_IR_INTERP_MODE_MASK) == NV50_IR_INTERP_SC) {
+ ipa = NV50_IR_INTERP_FLAT;
+ reg = 0x3f;
+ } else if (force_persample_interp &&
+ (ipa & NV50_IR_INTERP_SAMPLE_MASK) == NV50_IR_INTERP_DEFAULT &&
+ (ipa & NV50_IR_INTERP_MODE_MASK) != NV50_IR_INTERP_FLAT) {
+ ipa |= NV50_IR_INTERP_CENTROID;
+ }
+ code[loc + 0] &= ~(0xf << 6);
+ code[loc + 0] |= ipa << 6;
+ code[loc + 0] &= ~(0x3f << 26);
+ code[loc + 0] |= reg << 26;
+}
+
void
CodeEmitterNVC0::emitINTERP(const Instruction *i)
{
@@ -1630,10 +1653,13 @@ CodeEmitterNVC0::emitINTERP(const Instruction *i)
if (i->saturate)
code[0] |= 1 << 5;
- if (i->op == OP_PINTERP)
+ if (i->op == OP_PINTERP) {
srcId(i->src(1), 26);
- else
+ addInterp(i->ipa, SDATA(i->src(1)).id, interpApply);
+ } else {
code[0] |= 0x3f << 26;
+ addInterp(i->ipa, 0x3f, interpApply);
+ }
srcId(i->src(0).getIndirect(0), 20);
} else {
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 c8efaf5947a..f27a78e715d 100644
--- a/src/gallium/drivers/nouveau/codegen/nv50_ir_from_tgsi.cpp
+++ b/src/gallium/drivers/nouveau/codegen/nv50_ir_from_tgsi.cpp
@@ -1054,7 +1054,7 @@ bool Source::scanDeclaration(const struct tgsi_full_declaration *decl)
default:
break;
}
- if (decl->Interp.Location || info->io.sampleInterp)
+ if (decl->Interp.Location)
info->in[i].centroid = 1;
}
@@ -1119,6 +1119,10 @@ bool Source::scanDeclaration(const struct tgsi_full_declaration *decl)
case TGSI_SEMANTIC_VERTEXID:
info->io.vertexId = first;
break;
+ case TGSI_SEMANTIC_SAMPLEID:
+ case TGSI_SEMANTIC_SAMPLEPOS:
+ info->io.sampleInterp = 1;
+ break;
default:
break;
}
@@ -1338,6 +1342,8 @@ private:
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);
@@ -1451,8 +1457,8 @@ Converter::makeSym(uint tgsiFile, int fileIdx, int idx, int c, uint32_t address)
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;
@@ -1468,7 +1474,7 @@ translateInterpMode(const struct nv50_ir_varying *var, operation& op)
op = (mode == NV50_IR_INTERP_PERSPECTIVE || mode == NV50_IR_INTERP_SC)
? OP_PINTERP : OP_LINTERP;
- if (var->centroid)
+ if (var->centroid || info->io.sampleInterp)
mode |= NV50_IR_INTERP_CENTROID;
return mode;
diff --git a/src/gallium/drivers/nouveau/codegen/nv50_ir_target.cpp b/src/gallium/drivers/nouveau/codegen/nv50_ir_target.cpp
index fe530c76b62..afc8ff1374f 100644
--- a/src/gallium/drivers/nouveau/codegen/nv50_ir_target.cpp
+++ b/src/gallium/drivers/nouveau/codegen/nv50_ir_target.cpp
@@ -166,7 +166,7 @@ void Target::destroy(Target *targ)
delete targ;
}
-CodeEmitter::CodeEmitter(const Target *target) : targ(target)
+CodeEmitter::CodeEmitter(const Target *target) : targ(target), interpInfo(NULL)
{
}
@@ -388,6 +388,7 @@ Program::emitBinary(struct nv50_ir_prog_info *info)
}
}
info->bin.relocData = emit->getRelocInfo();
+ info->bin.interpData = emit->getInterpInfo();
emitSymbolTable(info);
@@ -428,6 +429,29 @@ CodeEmitter::addReloc(RelocEntry::Type ty, int w, uint32_t data, uint32_t m,
return true;
}
+bool
+CodeEmitter::addInterp(int ipa, int reg, InterpApply apply)
+{
+ unsigned int n = interpInfo ? interpInfo->count : 0;
+
+ if (!(n % RELOC_ALLOC_INCREMENT)) {
+ size_t size = sizeof(InterpInfo) + n * sizeof(InterpEntry);
+ interpInfo = reinterpret_cast<InterpInfo *>(
+ REALLOC(interpInfo, n ? size : 0,
+ size + RELOC_ALLOC_INCREMENT * sizeof(InterpEntry)));
+ if (!interpInfo)
+ return false;
+ if (n == 0)
+ memset(interpInfo, 0, sizeof(InterpInfo));
+ }
+ ++interpInfo->count;
+
+ interpInfo->entry[n] = InterpEntry(ipa, reg, codeSize >> 2);
+ interpInfo->apply = apply;
+
+ return true;
+}
+
void
RelocEntry::apply(uint32_t *binary, const RelocInfo *info) const
{
@@ -472,6 +496,19 @@ nv50_ir_relocate_code(void *relocData, uint32_t *code,
}
void
+nv50_ir_change_interp(void *interpData, uint32_t *code,
+ bool force_persample_interp, bool flatshade)
+{
+ nv50_ir::InterpInfo *info = reinterpret_cast<nv50_ir::InterpInfo *>(
+ interpData);
+
+ // force_persample_interp: all non-flat -> per-sample
+ // flatshade: all color -> flat
+ for (unsigned i = 0; i < info->count; ++i)
+ info->apply(&info->entry[i], code, force_persample_interp, flatshade);
+}
+
+void
nv50_ir_get_target_library(uint32_t chipset,
const uint32_t **code, uint32_t *size)
{
diff --git a/src/gallium/drivers/nouveau/codegen/nv50_ir_target.h b/src/gallium/drivers/nouveau/codegen/nv50_ir_target.h
index 591916eb412..4e33997e1c1 100644
--- a/src/gallium/drivers/nouveau/codegen/nv50_ir_target.h
+++ b/src/gallium/drivers/nouveau/codegen/nv50_ir_target.h
@@ -58,6 +58,23 @@ struct RelocInfo
RelocEntry entry[0];
};
+struct InterpEntry
+{
+ InterpEntry(int ipa, int reg, int loc) : ipa(ipa), reg(reg), loc(loc) {}
+ uint32_t ipa:4; // SC mode used to identify colors
+ uint32_t reg:8; // The reg used for perspective division
+ uint32_t loc:20; // Let's hope we don't have more than 1M-sized shaders
+};
+
+typedef void (*InterpApply)(const InterpEntry*, uint32_t*, bool, bool);
+
+struct InterpInfo
+{
+ uint32_t count;
+ InterpApply apply;
+ InterpEntry entry[0];
+};
+
class CodeEmitter
{
public:
@@ -78,6 +95,9 @@ public:
inline void *getRelocInfo() const { return relocInfo; }
+ bool addInterp(int ipa, int reg, InterpApply apply);
+ inline void *getInterpInfo() const { return interpInfo; }
+
virtual void prepareEmission(Program *);
virtual void prepareEmission(Function *);
virtual void prepareEmission(BasicBlock *);
@@ -92,6 +112,7 @@ protected:
uint32_t codeSizeLimit;
RelocInfo *relocInfo;
+ InterpInfo *interpInfo;
};