On Fri, Dec 19, 2014 at 3:50 PM, Ilia Mirkin <imir...@alum.mit.edu> wrote: > On Fri, Dec 19, 2014 at 2:11 PM, Rob Clark <robdcl...@gmail.com> wrote: >> From: Rob Clark <robcl...@freedesktop.org> >> >> This emulates alpha-test with a compare + KILL_IF. The alpha-ref value >> is passed to the shader via constant tagged with new ALPHAREF semantic. >> For example: >> >> FRAG >> PROPERTY FS_COLOR0_WRITES_ALL_CBUFS 1 >> DCL IN[0], COLOR, COLOR >> DCL OUT[0], COLOR >> 0: MOV OUT[0], IN[0] >> 1: END >> >> with alpha-func PIPE_FUNC_LESS, becomes: >> >> FRAG >> PROPERTY FS_COLOR0_WRITES_ALL_CBUFS 1 >> DCL IN[0], COLOR, COLOR >> DCL OUT[0], COLOR >> IMM[0] FLT32 { 0.0000, 1.0000, 128.0000, 0.0000} >> DCL TEMP[0] >> DCL TEMP[1] >> DCL CONST[0], ALPHAREF > > IMO this is pretty confusing. A SV makes more sense, no? Otherwise > you'd have a situation where > > DCL CONST[0] > DCL CONST[1] > DCL CONST[2], ALPHAREF > > MOV TEMP[0], CONST[ADDR[0].x] > > Could potentially be expected to move the alpharef into the temp, > which is... odd. Also I don't think there's any precendent for tagging > const's with semantics.
it is a bit odd, but isn't an out of bounds access undefined anyways? And yes, I don't think there is any precedent for tagging const's w/ semantic, it was a rather logical choice.. ie. if you are lowering alpha-test, that means you don't have some special register/etc to store alpharef, therefore driver is going to treat it as a normal const. It just needs some way to know where to stuff the const val. Treating it as something other than a const didn't seem to make much sense from the perspective of the consumer of the resulting tgsi. > The other thing to consider is whether each of these things should be > semantics, or whether there should be a > > TGSI_SEMANTIC_DRIVER > > Which is then indexed in a custom way (in this case, however > tgsi_lowering decides). Many drivers end up with driver-internal > constbufs full of convenient values, this would be a way to represent > that. I thought about it.. but not like we are running out of room in semantic namespace, and it was a very straightforward way to hook this all up (including tgsi_dump() and tgsi_text_translate()) BR, -R > >> 0: MOV TEMP[1], IN[0] >> 1: SLT TEMP[0].x, TEMP[1].wwww, CONST[0].xxxx >> 2: KILL_IF TEMP[0].xxxx >> 3: MOV OUT[0], TEMP[1] >> 4: END >> >> Signed-off-by: Rob Clark <robcl...@freedesktop.org> >> --- >> src/gallium/auxiliary/tgsi/tgsi_lowering.c | 170 >> ++++++++++++++++++++++++++++- >> src/gallium/auxiliary/tgsi/tgsi_lowering.h | 7 ++ >> src/gallium/auxiliary/tgsi/tgsi_strings.c | 1 + >> src/gallium/include/pipe/p_shader_tokens.h | 3 +- >> 4 files changed, 177 insertions(+), 4 deletions(-) >> >> diff --git a/src/gallium/auxiliary/tgsi/tgsi_lowering.c >> b/src/gallium/auxiliary/tgsi/tgsi_lowering.c >> index dee6c41..4f1da29 100644 >> --- a/src/gallium/auxiliary/tgsi/tgsi_lowering.c >> +++ b/src/gallium/auxiliary/tgsi/tgsi_lowering.c >> @@ -37,15 +37,22 @@ struct tgsi_lowering_context { >> struct tgsi_transform_context base; >> const struct tgsi_lowering_config *config; >> struct tgsi_shader_info *info; >> + >> + bool alpha_test; >> + unsigned colorout; >> + unsigned colortmp; /* tmp register to hold original color out */ >> + unsigned alpharef; /* const slot used to hold alpharef value */ >> + >> 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; >> struct tgsi_full_dst_register dst; >> - } tmp[2]; >> + } tmp[3]; >> #define A 0 >> #define B 1 >> struct tgsi_full_src_register imm; >> @@ -1146,6 +1153,128 @@ transform_samp(struct tgsi_transform_context *tctx, >> return 0; >> } >> >> +/* Alpha-test emulation: >> + * Redirects writes to COLOR output to a temporary and appends >> + * extra instructions to do conditional kill based on output >> + * alpha value >> + */ >> +#define ALPHATEST_GROW ( \ >> + 3 + /* CONST[], ALPHAREF */ \ >> + NINST(2) + /* SEQ/SNE/SLE/SGT/SLT */ \ >> + NINST(1) + /* KILL_IF */ \ >> + NINST(1) /* MOV */ \ >> + ) >> +#define ALPHATEST_TMP 1 >> + >> +static void >> +emit_alphatest_decls(struct tgsi_transform_context *tctx) >> +{ >> + struct tgsi_lowering_context *ctx = tgsi_lowering_context(tctx); >> + struct tgsi_full_declaration decl; >> + >> + /* NOTE: the temporaries we need are handled in emit_decls() */ >> + >> + decl = tgsi_default_full_declaration(); >> + decl.Declaration.File = TGSI_FILE_CONSTANT; >> + decl.Declaration.Semantic = true; >> + decl.Range.First = decl.Range.Last = ctx->alpharef; >> + decl.Semantic.Name = TGSI_SEMANTIC_ALPHAREF; >> + decl.Semantic.Index = 0; >> + tctx->emit_declaration(tctx, &decl); >> +} >> + >> +static void >> +emit_alphatest_instrs(struct tgsi_transform_context *tctx) >> +{ >> + struct tgsi_lowering_context *ctx = tgsi_lowering_context(tctx); >> + struct tgsi_full_instruction new_inst; >> + int c = ctx->colortmp; >> + >> + if (ctx->config->alpha_func == PIPE_FUNC_NEVER) { >> + /* KILL */ >> + new_inst = tgsi_default_full_instruction(); >> + new_inst.Instruction.Opcode = TGSI_OPCODE_KILL; >> + new_inst.Instruction.NumDstRegs = 0; >> + new_inst.Instruction.NumSrcRegs = 0; >> + tctx->emit_instruction(tctx, &new_inst); >> + } else { >> + unsigned opcode; >> + >> + switch (ctx->config->alpha_func) { >> + case PIPE_FUNC_LESS: >> + opcode = TGSI_OPCODE_SLT; >> + break; >> + case PIPE_FUNC_EQUAL: >> + opcode = TGSI_OPCODE_SEQ; >> + break; >> + case PIPE_FUNC_LEQUAL: >> + opcode = TGSI_OPCODE_SLE; >> + break; >> + case PIPE_FUNC_GREATER: >> + opcode = TGSI_OPCODE_SGT; >> + break; >> + case PIPE_FUNC_NOTEQUAL: >> + opcode = TGSI_OPCODE_SNE; >> + break; >> + case PIPE_FUNC_GEQUAL: >> + opcode = TGSI_OPCODE_SGE; >> + break; >> + default: >> + assert(0); >> + return; >> + } >> + >> + /* SEQ/SNE/SGE/SLE/SGT/SLT tmpA.x, tmpColor.w, alpharef.x */ >> + new_inst = tgsi_default_full_instruction(); >> + new_inst.Instruction.Opcode = opcode; >> + new_inst.Instruction.NumDstRegs = 1; >> + reg_dst(&new_inst.Dst[0], &ctx->tmp[A].dst, TGSI_WRITEMASK_X); >> + new_inst.Instruction.NumSrcRegs = 2; >> + reg_src(&new_inst.Src[0], &ctx->tmp[c].src, SWIZ(W, W, W, W)); >> + new_inst.Src[1].Register.File = TGSI_FILE_CONSTANT; >> + new_inst.Src[1].Register.Index = ctx->alpharef; >> + new_inst.Src[1].Register.SwizzleX = TGSI_SWIZZLE_X; >> + new_inst.Src[1].Register.SwizzleY = TGSI_SWIZZLE_X; >> + new_inst.Src[1].Register.SwizzleZ = TGSI_SWIZZLE_X; >> + new_inst.Src[1].Register.SwizzleW = TGSI_SWIZZLE_X; >> + tctx->emit_instruction(tctx, &new_inst); >> + >> + /* KILL_IF tmpA.x */ >> + new_inst = tgsi_default_full_instruction(); >> + new_inst.Instruction.Opcode = TGSI_OPCODE_KILL_IF; >> + new_inst.Instruction.NumDstRegs = 0; >> + new_inst.Instruction.NumSrcRegs = 1; >> + reg_src(&new_inst.Src[0], &ctx->tmp[A].src, SWIZ(X, _, _, _)); >> + tctx->emit_instruction(tctx, &new_inst); >> + } >> + >> + /* MOV OUT[color], tmpColor */ >> + /* (would be nice if we could create_mov() here..) */ >> + new_inst = tgsi_default_full_instruction(); >> + new_inst.Instruction.Opcode = TGSI_OPCODE_MOV; >> + new_inst.Instruction.NumDstRegs = 1; >> + new_inst.Dst[0].Register.File = TGSI_FILE_OUTPUT; >> + new_inst.Dst[0].Register.Index = ctx->colorout; >> + new_inst.Dst[0].Register.WriteMask = TGSI_WRITEMASK_XYZW; >> + new_inst.Instruction.NumSrcRegs = 1; >> + reg_src(&new_inst.Src[0], &ctx->tmp[c].src, SWIZ(X, Y, Z, W)); >> + tctx->emit_instruction(tctx, &new_inst); >> +} >> + >> +static void >> +rename_color_outputs(struct tgsi_lowering_context *ctx, >> + struct tgsi_full_instruction *inst) >> +{ >> + unsigned i; >> + for (i = 0; i < inst->Instruction.NumDstRegs; i++) { >> + struct tgsi_dst_register *dst = &inst->Dst[i].Register; >> + if ((dst->File == TGSI_FILE_OUTPUT) && >> + (dst->Index == ctx->colorout)) { >> + *dst = ctx->tmp[ctx->colortmp].dst.Register; >> + } >> + } >> +} >> + >> /* 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 >> @@ -1288,6 +1417,9 @@ emit_decls(struct tgsi_transform_context *tctx) >> >> if (ctx->two_side_colors) >> emit_twoside(tctx); >> + >> + if (ctx->alpha_test) >> + emit_alphatest_decls(tctx); >> } >> >> static void >> @@ -1307,7 +1439,6 @@ rename_color_inputs(struct tgsi_lowering_context *ctx, >> } >> } >> } >> - >> } >> >> static void >> @@ -1327,6 +1458,12 @@ transform_instr(struct tgsi_transform_context *tctx, >> if (ctx->two_side_colors) >> rename_color_inputs(ctx, inst); >> >> + /* if emulating alpha-test, we need to re-write some dst >> + * registers: >> + */ >> + if (ctx->alpha_test) >> + rename_color_outputs(ctx, inst); >> + >> switch (inst->Instruction.Opcode) { >> case TGSI_OPCODE_DST: >> if (!ctx->config->lower_DST) >> @@ -1406,6 +1543,10 @@ transform_instr(struct tgsi_transform_context *tctx, >> if (transform_samp(tctx, inst)) >> goto skip; >> break; >> + case TGSI_OPCODE_END: >> + if (ctx->alpha_test) >> + emit_alphatest_instrs(tctx); >> + goto skip; /* emit the actual END instruction itself */ >> default: >> skip: >> tctx->emit_instruction(tctx, inst); >> @@ -1452,6 +1593,20 @@ tgsi_transform_lowering(const struct >> tgsi_lowering_config *config, >> } >> } >> >> + if ((info->processor == TGSI_PROCESSOR_FRAGMENT) && >> + config->lower_alpha_test && >> + (config->alpha_func != PIPE_FUNC_ALWAYS)) { >> + int i; >> + ctx.alpha_test = true; >> + for (i = 0; i < info->file_max[TGSI_FILE_OUTPUT]; i++) { >> + /* TODO not sure what to do in case of MRT */ >> + if (info->output_semantic_name[i] == TGSI_SEMANTIC_COLOR) { >> + ctx.colorout = i; >> + break; >> + } >> + } >> + } >> + >> ctx.saturate = config->saturate_r | config->saturate_s | >> config->saturate_t; >> >> #define OPCS(x) ((config->lower_ ## x) ? info->opcode_count[TGSI_OPCODE_ ## >> x] : 0) >> @@ -1472,7 +1627,8 @@ tgsi_transform_lowering(const struct >> tgsi_lowering_config *config, >> OPCS(DP2A) || >> OPCS(TXP) || >> ctx.two_side_colors || >> - ctx.saturate)) >> + ctx.saturate || >> + ctx.alpha_test)) >> return NULL; >> >> #if 0 /* debug */ >> @@ -1555,6 +1711,14 @@ tgsi_transform_lowering(const struct >> tgsi_lowering_config *config, >> numtmp = MAX2(numtmp, SAMP_TMP); >> } >> >> + if (ctx.alpha_test) { >> + newlen += ALPHATEST_GROW; >> + numtmp = MAX2(numtmp, ALPHATEST_TMP); >> + /* and one more tmp to hold temporary color output: */ >> + ctx.colortmp = numtmp++; >> + ctx.alpharef = info->file_max[TGSI_FILE_CONSTANT] + 1; >> + } >> + >> /* specifically don't include two_side_colors temps in the count: */ >> ctx.numtmp = numtmp; >> >> diff --git a/src/gallium/auxiliary/tgsi/tgsi_lowering.h >> b/src/gallium/auxiliary/tgsi/tgsi_lowering.h >> index 52c204f..3a95c82 100644 >> --- a/src/gallium/auxiliary/tgsi/tgsi_lowering.h >> +++ b/src/gallium/auxiliary/tgsi/tgsi_lowering.h >> @@ -69,6 +69,13 @@ struct tgsi_lowering_config >> unsigned lower_DP2:1; >> unsigned lower_DP2A:1; >> >> + /* If lowering alpha-test, a constant w/ the semantic >> + * ALPHAREF is inserted. The driver should pass in the >> + * actual alpha-ref value via this constant (.x coord) >> + */ >> + unsigned lower_alpha_test:1; >> + unsigned alpha_func:3; /* PIPE_FUNC_x */ >> + >> /* bitmask of (1 << TGSI_TEXTURE_type): */ >> unsigned lower_TXP; >> >> diff --git a/src/gallium/auxiliary/tgsi/tgsi_strings.c >> b/src/gallium/auxiliary/tgsi/tgsi_strings.c >> index bd97544..b696838 100644 >> --- a/src/gallium/auxiliary/tgsi/tgsi_strings.c >> +++ b/src/gallium/auxiliary/tgsi/tgsi_strings.c >> @@ -88,6 +88,7 @@ const char *tgsi_semantic_names[TGSI_SEMANTIC_COUNT] = >> "INVOCATIONID", >> "VERTEXID_NOBASE", >> "BASEVERTEX", >> + "ALPHAREF", >> }; >> >> const char *tgsi_texture_names[TGSI_TEXTURE_COUNT] = >> diff --git a/src/gallium/include/pipe/p_shader_tokens.h >> b/src/gallium/include/pipe/p_shader_tokens.h >> index 442b67b..bf54c3e 100644 >> --- a/src/gallium/include/pipe/p_shader_tokens.h >> +++ b/src/gallium/include/pipe/p_shader_tokens.h >> @@ -178,7 +178,8 @@ struct tgsi_declaration_interp >> #define TGSI_SEMANTIC_INVOCATIONID 27 >> #define TGSI_SEMANTIC_VERTEXID_NOBASE 28 >> #define TGSI_SEMANTIC_BASEVERTEX 29 >> -#define TGSI_SEMANTIC_COUNT 30 /**< number of semantic values */ >> +#define TGSI_SEMANTIC_ALPHAREF 30 >> +#define TGSI_SEMANTIC_COUNT 31 /**< number of semantic values */ >> >> struct tgsi_declaration_semantic >> { >> -- >> 2.1.0 >> >> _______________________________________________ >> mesa-dev mailing list >> mesa-dev@lists.freedesktop.org >> http://lists.freedesktop.org/mailman/listinfo/mesa-dev _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/mesa-dev