summaryrefslogtreecommitdiffstats
path: root/src/gallium/drivers/freedreno/freedreno_lowering.c
diff options
context:
space:
mode:
authorRob Clark <[email protected]>2014-02-23 14:40:41 -0500
committerRob Clark <[email protected]>2014-03-02 11:26:35 -0500
commit26530716ab9398703f91285381033073f47e8bd4 (patch)
treeb7d4c19fd40f508083ca0a9a86a9c07bac8ff122 /src/gallium/drivers/freedreno/freedreno_lowering.c
parent8dd70125fc5ea45b206df50bac00f15d6e5da38c (diff)
freedreno/lowering: two-sided-color
Add option to generate fragment shader to emulate two sided color. Additional inputs are added to shader for BCOLOR's (on corresponding to each COLOR input). CMP instructions are used to select whether to use COLOR or BCOLOR. Signed-off-by: Rob Clark <[email protected]>
Diffstat (limited to 'src/gallium/drivers/freedreno/freedreno_lowering.c')
-rw-r--r--src/gallium/drivers/freedreno/freedreno_lowering.c245
1 files changed, 204 insertions, 41 deletions
diff --git a/src/gallium/drivers/freedreno/freedreno_lowering.c b/src/gallium/drivers/freedreno/freedreno_lowering.c
index 607a5acbadb..ffc7eaea53f 100644
--- a/src/gallium/drivers/freedreno/freedreno_lowering.c
+++ b/src/gallium/drivers/freedreno/freedreno_lowering.c
@@ -39,6 +39,10 @@ struct fd_lowering_context {
struct tgsi_transform_context base;
const struct fd_lowering_config *config;
struct tgsi_shader_info *info;
+ unsigned two_side_colors;
+ unsigned two_side_idx[PIPE_MAX_SHADER_INPUTS];
+ unsigned color_base; /* base register for chosen COLOR/BCOLOR's */
+ int face_idx;
unsigned numtmp;
struct {
struct tgsi_full_src_register src;
@@ -977,56 +981,188 @@ transform_dotp(struct tgsi_transform_context *tctx,
}
}
+
+/* Two-sided color emulation:
+ * For each COLOR input, create a corresponding BCOLOR input, plus
+ * CMP instruction to select front or back color based on FACE
+ */
+#define TWOSIDE_GROW(n) ( \
+ 2 + /* FACE */ \
+ ((n) * 2) + /* IN[] BCOLOR[n] */ \
+ ((n) * 1) + /* TEMP[] */ \
+ ((n) * 5) /* CMP instr */ \
+ )
+
static void
-transform_instr(struct tgsi_transform_context *tctx,
- struct tgsi_full_instruction *inst)
+emit_twoside(struct tgsi_transform_context *tctx)
{
struct fd_lowering_context *ctx = fd_lowering_context(tctx);
+ struct tgsi_shader_info *info = ctx->info;
+ struct tgsi_full_declaration decl;
+ struct tgsi_full_instruction new_inst;
+ unsigned inbase, tmpbase;
+ int i;
+
+ inbase = info->file_max[TGSI_FILE_INPUT] + 1;
+ tmpbase = info->file_max[TGSI_FILE_TEMPORARY] + 1;
+
+ /* additional inputs for BCOLOR's */
+ for (i = 0; i < ctx->two_side_colors; i++) {
+ decl = tgsi_default_full_declaration();
+ decl.Declaration.File = TGSI_FILE_INPUT;
+ decl.Declaration.Semantic = true;
+ decl.Range.First = decl.Range.Last = inbase + i;
+ decl.Semantic.Name = TGSI_SEMANTIC_BCOLOR;
+ decl.Semantic.Index =
+ info->input_semantic_index[ctx->two_side_idx[i]];
+ tctx->emit_declaration(tctx, &decl);
+ }
- if (!ctx->emitted_decls) {
- struct tgsi_full_declaration decl;
- struct tgsi_full_immediate immed;
- unsigned tmpbase = ctx->info->file_max[TGSI_FILE_TEMPORARY] + 1;
- int i;
+ /* additional input for FACE */
+ if (ctx->two_side_colors && (ctx->face_idx == -1)) {
+ decl = tgsi_default_full_declaration();
+ decl.Declaration.File = TGSI_FILE_INPUT;
+ decl.Declaration.Semantic = true;
+ decl.Range.First = decl.Range.Last = inbase + ctx->two_side_colors;
+ decl.Semantic.Name = TGSI_SEMANTIC_FACE;
+ decl.Semantic.Index = 0;
+ tctx->emit_declaration(tctx, &decl);
+
+ ctx->face_idx = decl.Range.First;
+ }
- /* declare immediate: */
- immed = tgsi_default_full_immediate();
- immed.Immediate.NrTokens = 1 + 4; /* one for the token itself */
- immed.u[0].Float = 0.0;
- immed.u[1].Float = 1.0;
- immed.u[2].Float = 128.0;
- immed.u[3].Float = 0.0;
- tctx->emit_immediate(tctx, &immed);
-
- ctx->imm.Register.File = TGSI_FILE_IMMEDIATE;
- ctx->imm.Register.Index = ctx->info->immediate_count;
- ctx->imm.Register.SwizzleX = TGSI_SWIZZLE_X;
- ctx->imm.Register.SwizzleY = TGSI_SWIZZLE_Y;
- ctx->imm.Register.SwizzleZ = TGSI_SWIZZLE_Z;
- ctx->imm.Register.SwizzleW = TGSI_SWIZZLE_W;
-
- /* declare temp regs: */
- for (i = 0; i < ctx->numtmp; i++) {
- decl = tgsi_default_full_declaration();
- decl.Declaration.File = TGSI_FILE_TEMPORARY;
- decl.Range.First = decl.Range.Last = tmpbase + i;
- tctx->emit_declaration(tctx, &decl);
-
- ctx->tmp[i].src.Register.File = TGSI_FILE_TEMPORARY;
- ctx->tmp[i].src.Register.Index = tmpbase + i;
- ctx->tmp[i].src.Register.SwizzleX = TGSI_SWIZZLE_X;
- ctx->tmp[i].src.Register.SwizzleY = TGSI_SWIZZLE_Y;
- ctx->tmp[i].src.Register.SwizzleZ = TGSI_SWIZZLE_Z;
- ctx->tmp[i].src.Register.SwizzleW = TGSI_SWIZZLE_W;
-
- ctx->tmp[i].dst.Register.File = TGSI_FILE_TEMPORARY;
- ctx->tmp[i].dst.Register.Index = tmpbase + i;
- ctx->tmp[i].dst.Register.WriteMask = TGSI_WRITEMASK_XYZW;
+ /* additional temps for COLOR/BCOLOR selection: */
+ for (i = 0; i < ctx->two_side_colors; i++) {
+ decl = tgsi_default_full_declaration();
+ decl.Declaration.File = TGSI_FILE_TEMPORARY;
+ decl.Range.First = decl.Range.Last = tmpbase + ctx->numtmp + i;
+ tctx->emit_declaration(tctx, &decl);
+ }
+
+ /* and finally additional instructions to select COLOR/BCOLOR: */
+ for (i = 0; i < ctx->two_side_colors; i++) {
+ new_inst = tgsi_default_full_instruction();
+ new_inst.Instruction.Opcode = TGSI_OPCODE_CMP;
+
+ new_inst.Instruction.NumDstRegs = 1;
+ new_inst.Dst[0].Register.File = TGSI_FILE_TEMPORARY;
+ new_inst.Dst[0].Register.Index = tmpbase + ctx->numtmp + i;
+ new_inst.Dst[0].Register.WriteMask = TGSI_WRITEMASK_XYZW;
+
+ new_inst.Instruction.NumSrcRegs = 3;
+ new_inst.Src[0].Register.File = TGSI_FILE_INPUT;
+ new_inst.Src[0].Register.Index = ctx->face_idx;
+ new_inst.Src[0].Register.SwizzleX = TGSI_SWIZZLE_X;
+ new_inst.Src[0].Register.SwizzleY = TGSI_SWIZZLE_X;
+ new_inst.Src[0].Register.SwizzleZ = TGSI_SWIZZLE_X;
+ new_inst.Src[0].Register.SwizzleW = TGSI_SWIZZLE_X;
+ new_inst.Src[1].Register.File = TGSI_FILE_INPUT;
+ new_inst.Src[1].Register.Index = inbase + i;
+ new_inst.Src[1].Register.SwizzleX = TGSI_SWIZZLE_X;
+ new_inst.Src[1].Register.SwizzleY = TGSI_SWIZZLE_Y;
+ new_inst.Src[1].Register.SwizzleZ = TGSI_SWIZZLE_Z;
+ new_inst.Src[1].Register.SwizzleW = TGSI_SWIZZLE_W;
+ new_inst.Src[2].Register.File = TGSI_FILE_INPUT;
+ new_inst.Src[2].Register.Index = ctx->two_side_idx[i];
+ new_inst.Src[2].Register.SwizzleX = TGSI_SWIZZLE_X;
+ new_inst.Src[2].Register.SwizzleY = TGSI_SWIZZLE_Y;
+ new_inst.Src[2].Register.SwizzleZ = TGSI_SWIZZLE_Z;
+ new_inst.Src[2].Register.SwizzleW = TGSI_SWIZZLE_W;
+
+ tctx->emit_instruction(tctx, &new_inst);
+ }
+}
+
+static void
+emit_decls(struct tgsi_transform_context *tctx)
+{
+ struct fd_lowering_context *ctx = fd_lowering_context(tctx);
+ struct tgsi_shader_info *info = ctx->info;
+ struct tgsi_full_declaration decl;
+ struct tgsi_full_immediate immed;
+ unsigned tmpbase;
+ int i;
+
+ tmpbase = info->file_max[TGSI_FILE_TEMPORARY] + 1;
+
+ ctx->color_base = tmpbase + ctx->numtmp;
+
+ /* declare immediate: */
+ immed = tgsi_default_full_immediate();
+ immed.Immediate.NrTokens = 1 + 4; /* one for the token itself */
+ immed.u[0].Float = 0.0;
+ immed.u[1].Float = 1.0;
+ immed.u[2].Float = 128.0;
+ immed.u[3].Float = 0.0;
+ tctx->emit_immediate(tctx, &immed);
+
+ ctx->imm.Register.File = TGSI_FILE_IMMEDIATE;
+ ctx->imm.Register.Index = info->immediate_count;
+ ctx->imm.Register.SwizzleX = TGSI_SWIZZLE_X;
+ ctx->imm.Register.SwizzleY = TGSI_SWIZZLE_Y;
+ ctx->imm.Register.SwizzleZ = TGSI_SWIZZLE_Z;
+ ctx->imm.Register.SwizzleW = TGSI_SWIZZLE_W;
+
+ /* declare temp regs: */
+ for (i = 0; i < ctx->numtmp; i++) {
+ decl = tgsi_default_full_declaration();
+ decl.Declaration.File = TGSI_FILE_TEMPORARY;
+ decl.Range.First = decl.Range.Last = tmpbase + i;
+ tctx->emit_declaration(tctx, &decl);
+
+ ctx->tmp[i].src.Register.File = TGSI_FILE_TEMPORARY;
+ ctx->tmp[i].src.Register.Index = tmpbase + i;
+ ctx->tmp[i].src.Register.SwizzleX = TGSI_SWIZZLE_X;
+ ctx->tmp[i].src.Register.SwizzleY = TGSI_SWIZZLE_Y;
+ ctx->tmp[i].src.Register.SwizzleZ = TGSI_SWIZZLE_Z;
+ ctx->tmp[i].src.Register.SwizzleW = TGSI_SWIZZLE_W;
+
+ ctx->tmp[i].dst.Register.File = TGSI_FILE_TEMPORARY;
+ ctx->tmp[i].dst.Register.Index = tmpbase + i;
+ ctx->tmp[i].dst.Register.WriteMask = TGSI_WRITEMASK_XYZW;
+ }
+
+ if (ctx->two_side_colors)
+ emit_twoside(tctx);
+}
+
+static void
+rename_color_inputs(struct fd_lowering_context *ctx,
+ struct tgsi_full_instruction *inst)
+{
+ unsigned i, j;
+ for (i = 0; i < inst->Instruction.NumSrcRegs; i++) {
+ struct tgsi_src_register *src = &inst->Src[i].Register;
+ if (src->File == TGSI_FILE_INPUT) {
+ for (j = 0; j < ctx->two_side_colors; j++) {
+ if (src->Index == ctx->two_side_idx[j]) {
+ src->File = TGSI_FILE_TEMPORARY;
+ src->Index = ctx->color_base + j;
+ break;
+ }
+ }
}
+ }
+
+}
+
+static void
+transform_instr(struct tgsi_transform_context *tctx,
+ struct tgsi_full_instruction *inst)
+{
+ struct fd_lowering_context *ctx = fd_lowering_context(tctx);
+ if (!ctx->emitted_decls) {
+ emit_decls(tctx);
ctx->emitted_decls = 1;
}
+ /* if emulating two-sided-color, we need to re-write some
+ * src registers:
+ */
+ if (ctx->two_side_colors)
+ rename_color_inputs(ctx, inst);
+
switch (inst->Instruction.Opcode) {
case TGSI_OPCODE_DST:
if (!ctx->config->lower_DST)
@@ -1125,6 +1261,22 @@ fd_transform_lowering(const struct fd_lowering_config *config,
tgsi_scan_shader(tokens, info);
+ /* if we are adding fragment shader support to emulate two-sided
+ * color, then figure out the number of additional inputs we need
+ * to create for BCOLOR's..
+ */
+ if ((info->processor == TGSI_PROCESSOR_FRAGMENT) &&
+ config->color_two_side) {
+ int i;
+ ctx.face_idx = -1;
+ for (i = 0; i <= info->file_max[TGSI_FILE_INPUT]; i++) {
+ if (info->input_semantic_name[i] == TGSI_SEMANTIC_COLOR)
+ ctx.two_side_idx[ctx.two_side_colors++] = i;
+ if (info->input_semantic_name[i] == TGSI_SEMANTIC_FACE)
+ ctx.face_idx = i;
+ }
+ }
+
#define OPCS(x) ((config->lower_ ## x) ? info->opcode_count[TGSI_OPCODE_ ## x] : 0)
/* if there are no instructions to lower, then we are done: */
if (!(OPCS(DST) ||
@@ -1140,7 +1292,8 @@ fd_transform_lowering(const struct fd_lowering_config *config,
OPCS(DP3) ||
OPCS(DPH) ||
OPCS(DP2) ||
- OPCS(DP2A)))
+ OPCS(DP2A) ||
+ ctx.two_side_colors))
return NULL;
#if 0 /* debug */
@@ -1207,8 +1360,18 @@ fd_transform_lowering(const struct fd_lowering_config *config,
numtmp = MAX2(numtmp, DOTP_TMP);
}
+ /* specifically don't include two_side_colors temps in the count: */
ctx.numtmp = numtmp;
+ if (ctx.two_side_colors) {
+ newlen += TWOSIDE_GROW(ctx.two_side_colors);
+ /* note: we permanently consume temp regs, re-writing references
+ * to IN.COLOR[n] to TEMP[m] (holding the output of of the CMP
+ * instruction that selects which varying to use):
+ */
+ numtmp += ctx.two_side_colors;
+ }
+
newlen += 2 * numtmp;
newlen += 5; /* immediate */