summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRoland Scheidegger <[email protected]>2018-02-13 18:56:34 +0100
committerRoland Scheidegger <[email protected]>2018-02-14 02:06:54 +0100
commitf6718baabc7d6fed0d41f72fb22e57c0d67fbf1d (patch)
tree28f6c6ecd16e78096b74f6e30fbb9f136a5202f3
parent7461bd5b8f77652195bdb771232cb762b9b8758f (diff)
tgsi: Recognize RET in main for tgsi_transform
Shaders coming from dx10 state trackers have a RET before the END. And the epilog needs to be placed before the RET (otherwise it will get ignored). Hence figure out if a RET is in main, in this case we'll place the epilog there rather than before the END. (At a closer look, there actually seem to be problems with control flow in general with output redirection, that would need another look. It's enough however to fix draw's aa line emulation in some internal bug - lines tend to be drawn with trivial shaders, moving either a constant color or a vertex color directly to the output). v2: add assert so buggy handling of RET in main is detected Reviewed-by: Brian Paul <[email protected]> Reviewed-by: Jose Fonseca <[email protected]>
-rw-r--r--src/gallium/auxiliary/tgsi/tgsi_transform.c62
1 files changed, 55 insertions, 7 deletions
diff --git a/src/gallium/auxiliary/tgsi/tgsi_transform.c b/src/gallium/auxiliary/tgsi/tgsi_transform.c
index ffdad1338c5..a13cf90a274 100644
--- a/src/gallium/auxiliary/tgsi/tgsi_transform.c
+++ b/src/gallium/auxiliary/tgsi/tgsi_transform.c
@@ -110,6 +110,9 @@ tgsi_transform_shader(const struct tgsi_token *tokens_in,
{
uint procType;
boolean first_instruction = TRUE;
+ boolean epilog_emitted = FALSE;
+ int cond_stack = 0;
+ int call_stack = 0;
/* input shader */
struct tgsi_parse_context parse;
@@ -166,22 +169,66 @@ tgsi_transform_shader(const struct tgsi_token *tokens_in,
{
struct tgsi_full_instruction *fullinst
= &parse.FullToken.FullInstruction;
+ unsigned opcode = fullinst->Instruction.Opcode;
if (first_instruction && ctx->prolog) {
ctx->prolog(ctx);
}
- /* XXX Note: we may also want to look for a main/top-level
- * TGSI_OPCODE_RET instruction in the future.
+ /*
+ * XXX Note: we handle the case of ret in main.
+ * However, the output redirections done by transform
+ * have their limits with control flow and will generally
+ * not work correctly. e.g.
+ * if (cond) {
+ * oColor = x;
+ * ret;
+ * }
+ * oColor = y;
+ * end;
+ * If the color output is redirected to a temp and modified
+ * by a transform, this will not work (the oColor assignment
+ * in the conditional will never make it to the actual output).
*/
- if (fullinst->Instruction.Opcode == TGSI_OPCODE_END
- && ctx->epilog) {
- /* Emit caller's epilog */
- ctx->epilog(ctx);
- /* Emit END */
+ if ((opcode == TGSI_OPCODE_END || opcode == TGSI_OPCODE_RET) &&
+ call_stack == 0 && ctx->epilog && !epilog_emitted) {
+ if (opcode == TGSI_OPCODE_RET && cond_stack != 0) {
+ assert(!"transform ignoring RET in main");
+ } else {
+ assert(cond_stack == 0);
+ /* Emit caller's epilog */
+ ctx->epilog(ctx);
+ epilog_emitted = TRUE;
+ }
+ /* Emit END (or RET) */
ctx->emit_instruction(ctx, fullinst);
}
else {
+ switch (opcode) {
+ case TGSI_OPCODE_IF:
+ case TGSI_OPCODE_UIF:
+ case TGSI_OPCODE_SWITCH:
+ case TGSI_OPCODE_BGNLOOP:
+ cond_stack++;
+ break;
+ case TGSI_OPCODE_CAL:
+ call_stack++;
+ break;
+ case TGSI_OPCODE_ENDIF:
+ case TGSI_OPCODE_ENDSWITCH:
+ case TGSI_OPCODE_ENDLOOP:
+ assert(cond_stack > 0);
+ cond_stack--;
+ break;
+ case TGSI_OPCODE_ENDSUB:
+ assert(call_stack > 0);
+ call_stack--;
+ break;
+ case TGSI_OPCODE_BGNSUB:
+ case TGSI_OPCODE_RET:
+ default:
+ break;
+ }
if (ctx->transform_instruction)
ctx->transform_instruction(ctx, fullinst);
else
@@ -231,6 +278,7 @@ tgsi_transform_shader(const struct tgsi_token *tokens_in,
assert( 0 );
}
}
+ assert(call_stack == 0);
tgsi_parse_free (&parse);