--- /dev/null
+From 5a3ea68895f7815ccb5b3adeab07c992683c2d59 Mon Sep 17 00:00:00 2001
+From: Christian Gmeiner <christian.gmeiner@gmail.com>
+Date: Tue, 3 Jan 2017 15:06:24 +0100
+Subject: [PATCH] etnaviv: wire up core pipe_debug_callback
+
+Signed-off-by: Christian Gmeiner <christian.gmeiner@gmail.com>
+Reviewed-by: Lucas Stach <l.stach@pengutronix.de>
+---
+ src/gallium/drivers/etnaviv/etnaviv_context.c | 13 +++++++++++++
+ src/gallium/drivers/etnaviv/etnaviv_context.h | 2 ++
+ 2 files changed, 15 insertions(+)
+
+diff --git a/src/gallium/drivers/etnaviv/etnaviv_context.c b/src/gallium/drivers/etnaviv/etnaviv_context.c
+index d767cd1..ce2d871 100644
+--- a/src/gallium/drivers/etnaviv/etnaviv_context.c
++++ b/src/gallium/drivers/etnaviv/etnaviv_context.c
+@@ -246,6 +246,18 @@ etna_cmd_stream_reset_notify(struct etna_cmd_stream *stream, void *priv)
+ assert(LIST_IS_EMPTY(&ctx->used_resources));
+ }
+
++static void
++etna_set_debug_callback(struct pipe_context *pctx,
++ const struct pipe_debug_callback *cb)
++{
++ struct etna_context *ctx = etna_context(pctx);
++
++ if (cb)
++ ctx->debug = *cb;
++ else
++ memset(&ctx->debug, 0, sizeof(ctx->debug));
++}
++
+ struct pipe_context *
+ etna_context_create(struct pipe_screen *pscreen, void *priv, unsigned flags)
+ {
+@@ -279,6 +291,7 @@ etna_context_create(struct pipe_screen *pscreen, void *priv, unsigned flags)
+ pctx->destroy = etna_context_destroy;
+ pctx->draw_vbo = etna_draw_vbo;
+ pctx->flush = etna_flush;
++ pctx->set_debug_callback = etna_set_debug_callback;
+
+ /* creation of compile states */
+ pctx->create_blend_state = etna_blend_state_create;
+diff --git a/src/gallium/drivers/etnaviv/etnaviv_context.h b/src/gallium/drivers/etnaviv/etnaviv_context.h
+index 74e93e1..a921403 100644
+--- a/src/gallium/drivers/etnaviv/etnaviv_context.h
++++ b/src/gallium/drivers/etnaviv/etnaviv_context.h
+@@ -174,6 +174,8 @@ struct etna_context {
+ uint64_t prims_emitted;
+ uint64_t draw_calls;
+ } stats;
++
++ struct pipe_debug_callback debug;
+ };
+
+ static inline struct etna_context *
+--
+2.7.4
+
--- /dev/null
+From 137ad879d5be404e86095267808baa91890e1390 Mon Sep 17 00:00:00 2001
+From: Christian Gmeiner <christian.gmeiner@gmail.com>
+Date: Wed, 4 Jan 2017 22:59:38 +0100
+Subject: [PATCH] etnaviv: shader-db traces
+
+Signed-off-by: Christian Gmeiner <christian.gmeiner@gmail.com>
+Reviewed-By: Wladimir J. van der Laan <laanwj@gmail.com>
+---
+ src/gallium/drivers/etnaviv/etnaviv_compiler.h | 2 ++
+ src/gallium/drivers/etnaviv/etnaviv_debug.h | 1 +
+ src/gallium/drivers/etnaviv/etnaviv_screen.c | 1 +
+ src/gallium/drivers/etnaviv/etnaviv_shader.c | 44 +++++++++++++++++++++++++-
+ 4 files changed, 47 insertions(+), 1 deletion(-)
+
+diff --git a/src/gallium/drivers/etnaviv/etnaviv_compiler.h b/src/gallium/drivers/etnaviv/etnaviv_compiler.h
+index 211ae1a..de3e20d 100644
+--- a/src/gallium/drivers/etnaviv/etnaviv_compiler.h
++++ b/src/gallium/drivers/etnaviv/etnaviv_compiler.h
+@@ -56,6 +56,8 @@ struct etna_shader_io_file {
+
+ /* shader object, for linking */
+ struct etna_shader {
++ uint32_t id; /* for debug */
++
+ uint processor; /* TGSI_PROCESSOR_... */
+ uint32_t code_size; /* code size in uint32 words */
+ uint32_t *code;
+diff --git a/src/gallium/drivers/etnaviv/etnaviv_debug.h b/src/gallium/drivers/etnaviv/etnaviv_debug.h
+index cfda52b..f47dffe 100644
+--- a/src/gallium/drivers/etnaviv/etnaviv_debug.h
++++ b/src/gallium/drivers/etnaviv/etnaviv_debug.h
+@@ -51,6 +51,7 @@
+ #define ETNA_DBG_FLUSH_ALL 0x100000 /* Flush after every rendered primitive */
+ #define ETNA_DBG_ZERO 0x200000 /* Zero all resources after allocation */
+ #define ETNA_DBG_DRAW_STALL 0x400000 /* Stall FE/PE after every draw op */
++#define ETNA_DBG_SHADERDB 0x800000 /* dump program compile information */
+
+ extern int etna_mesa_debug; /* set in etna_screen.c from ETNA_DEBUG */
+
+diff --git a/src/gallium/drivers/etnaviv/etnaviv_screen.c b/src/gallium/drivers/etnaviv/etnaviv_screen.c
+index e3090dc..9324a95 100644
+--- a/src/gallium/drivers/etnaviv/etnaviv_screen.c
++++ b/src/gallium/drivers/etnaviv/etnaviv_screen.c
+@@ -62,6 +62,7 @@ static const struct debug_named_value debug_options[] = {
+ {"flush_all", ETNA_DBG_FLUSH_ALL, "Flush after every rendered primitive"},
+ {"zero", ETNA_DBG_ZERO, "Zero all resources after allocation"},
+ {"draw_stall", ETNA_DBG_DRAW_STALL, "Stall FE/PE after each rendered primitive"},
++ {"shaderdb", ETNA_DBG_SHADERDB, "Enable shaderdb output"},
+ DEBUG_NAMED_VALUE_END
+ };
+
+diff --git a/src/gallium/drivers/etnaviv/etnaviv_shader.c b/src/gallium/drivers/etnaviv/etnaviv_shader.c
+index 8895311..87edf5b 100644
+--- a/src/gallium/drivers/etnaviv/etnaviv_shader.c
++++ b/src/gallium/drivers/etnaviv/etnaviv_shader.c
+@@ -223,6 +223,42 @@ etna_shader_update_vs_inputs(struct etna_context *ctx,
+ return true;
+ }
+
++static inline const char *
++etna_shader_stage(struct etna_shader *shader)
++{
++ switch (shader->processor) {
++ case PIPE_SHADER_VERTEX: return "VERT";
++ case PIPE_SHADER_FRAGMENT: return "FRAG";
++ case PIPE_SHADER_COMPUTE: return "CL";
++ default:
++ unreachable("invalid type");
++ return NULL;
++ }
++}
++
++static void
++dump_shader_info(struct etna_shader *shader, struct pipe_debug_callback *debug)
++{
++ if (!unlikely(etna_mesa_debug & ETNA_DBG_SHADERDB))
++ return;
++
++ pipe_debug_message(debug, SHADER_INFO, "\n"
++ "SHADER-DB: %s prog %d: %u instructions %u temps\n"
++ "SHADER-DB: %s prog %d: %u immediates %u consts\n"
++ "SHADER-DB: %s prog %d: %u loops\n",
++ etna_shader_stage(shader),
++ shader->id,
++ shader->code_size,
++ shader->num_temps,
++ etna_shader_stage(shader),
++ shader->id,
++ shader->uniforms.imm_count,
++ shader->uniforms.const_count,
++ etna_shader_stage(shader),
++ shader->id,
++ shader->num_loops);
++}
++
+ bool
+ etna_shader_update_vertex(struct etna_context *ctx)
+ {
+@@ -235,8 +271,14 @@ etna_create_shader_state(struct pipe_context *pctx,
+ const struct pipe_shader_state *pss)
+ {
+ struct etna_context *ctx = etna_context(pctx);
++ struct etna_shader *shader = etna_compile_shader(&ctx->specs, pss->tokens);
++
++ static uint32_t id;
++ shader->id = id++;
++
++ dump_shader_info(shader, &ctx->debug);
+
+- return etna_compile_shader(&ctx->specs, pss->tokens);
++ return shader;
+ }
+
+ static void
+--
+2.7.4
+
--- /dev/null
+From 7256ed3c7967a1fc2a4f9ad23377ef4fe458095f Mon Sep 17 00:00:00 2001
+From: Christian Gmeiner <christian.gmeiner@gmail.com>
+Date: Tue, 31 Jan 2017 20:15:53 +0100
+Subject: [PATCH] etnaviv: keep track of emitted loops
+
+Signed-off-by: Christian Gmeiner <christian.gmeiner@gmail.com>
+Reviewed-by: Lucas Stach <l.stach@pengutronix.de>
+Reviewed-by: Wladimir J. van der Laan <laanwj@gmail.com>
+---
+ src/gallium/drivers/etnaviv/etnaviv_compiler.c | 6 ++++++
+ src/gallium/drivers/etnaviv/etnaviv_compiler.h | 1 +
+ 2 files changed, 7 insertions(+)
+
+diff --git a/src/gallium/drivers/etnaviv/etnaviv_compiler.c b/src/gallium/drivers/etnaviv/etnaviv_compiler.c
+index 7446a19..af7b64d 100644
+--- a/src/gallium/drivers/etnaviv/etnaviv_compiler.c
++++ b/src/gallium/drivers/etnaviv/etnaviv_compiler.c
+@@ -183,6 +183,8 @@ struct etna_compile {
+ unsigned labels_count, labels_sz;
+ struct etna_compile_label *labels;
+
++ unsigned num_loops;
++
+ /* Code generation */
+ int inst_ptr; /* current instruction pointer */
+ uint32_t code[ETNA_MAX_INSTRUCTIONS * ETNA_INST_SIZE];
+@@ -1166,6 +1168,8 @@ trans_loop_bgn(const struct instr_translater *t, struct etna_compile *c,
+ f->lbl_loop_end = alloc_new_label(c);
+
+ label_place(c, f->lbl_loop_bgn);
++
++ c->num_loops++;
+ }
+
+ static void
+@@ -2418,6 +2422,7 @@ etna_compile_shader(const struct etna_specs *specs,
+ shader->processor = c->info.processor;
+ shader->code_size = c->inst_ptr * 4;
+ shader->code = mem_dup(c->code, c->inst_ptr * 16);
++ shader->num_loops = c->num_loops;
+ shader->num_temps = c->next_free_native;
+ shader->vs_pos_out_reg = -1;
+ shader->vs_pointsize_out_reg = -1;
+@@ -2455,6 +2460,7 @@ etna_dump_shader(const struct etna_shader *shader)
+
+ etna_disasm(shader->code, shader->code_size, PRINT_RAW);
+
++ printf("num loops: %i\n", shader->num_loops);
+ printf("num temps: %i\n", shader->num_temps);
+ printf("num const: %i\n", shader->uniforms.const_count);
+ printf("immediates:\n");
+diff --git a/src/gallium/drivers/etnaviv/etnaviv_compiler.h b/src/gallium/drivers/etnaviv/etnaviv_compiler.h
+index d310109..211ae1a 100644
+--- a/src/gallium/drivers/etnaviv/etnaviv_compiler.h
++++ b/src/gallium/drivers/etnaviv/etnaviv_compiler.h
+@@ -59,6 +59,7 @@ struct etna_shader {
+ uint processor; /* TGSI_PROCESSOR_... */
+ uint32_t code_size; /* code size in uint32 words */
+ uint32_t *code;
++ unsigned num_loops;
+ unsigned num_temps;
+
+ struct etna_shader_uniform_info uniforms;
+--
+2.7.4
+
--- /dev/null
+From 1b5af6e493b17d138e564c20bc2e28e32b2add94 Mon Sep 17 00:00:00 2001
+From: Christian Gmeiner <christian.gmeiner@gmail.com>
+Date: Sun, 12 Feb 2017 16:39:57 +0100
+Subject: [PATCH 04/14] etnaviv: remove not needed forward declarations
+
+Signed-off-by: Christian Gmeiner <christian.gmeiner@gmail.com>
+---
+ src/gallium/drivers/etnaviv/etnaviv_shader.h | 2 --
+ 1 file changed, 2 deletions(-)
+
+diff --git a/src/gallium/drivers/etnaviv/etnaviv_shader.h b/src/gallium/drivers/etnaviv/etnaviv_shader.h
+index b309370..1dbd200 100644
+--- a/src/gallium/drivers/etnaviv/etnaviv_shader.h
++++ b/src/gallium/drivers/etnaviv/etnaviv_shader.h
+@@ -30,8 +30,6 @@
+ #include "pipe/p_state.h"
+
+ struct etna_context;
+-struct etna_shader;
+-struct compiled_shader_state;
+
+ bool
+ etna_shader_link(struct etna_context *ctx);
+--
+2.7.4
+
--- /dev/null
+From 60363430ed3a4eca2de4eaad8ef5b0e4c293781b Mon Sep 17 00:00:00 2001
+From: Christian Gmeiner <christian.gmeiner@gmail.com>
+Date: Sun, 12 Feb 2017 17:11:44 +0100
+Subject: [PATCH 05/14] etnaviv: s/etna_shader/etna_shader_variant
+
+Prep work to add shader variant support.
+
+Signed-off-by: Christian Gmeiner <christian.gmeiner@gmail.com>
+---
+ src/gallium/drivers/etnaviv/etnaviv_compiler.c | 26 +++++++++++-----------
+ src/gallium/drivers/etnaviv/etnaviv_compiler.h | 10 ++++-----
+ .../drivers/etnaviv/etnaviv_compiler_cmdline.c | 2 +-
+ src/gallium/drivers/etnaviv/etnaviv_context.h | 6 ++---
+ src/gallium/drivers/etnaviv/etnaviv_shader.c | 14 ++++++------
+ src/gallium/drivers/etnaviv/etnaviv_uniforms.c | 4 ++--
+ src/gallium/drivers/etnaviv/etnaviv_uniforms.h | 6 ++---
+ 7 files changed, 34 insertions(+), 34 deletions(-)
+
+diff --git a/src/gallium/drivers/etnaviv/etnaviv_compiler.c b/src/gallium/drivers/etnaviv/etnaviv_compiler.c
+index af7b64d..be3838d 100644
+--- a/src/gallium/drivers/etnaviv/etnaviv_compiler.c
++++ b/src/gallium/drivers/etnaviv/etnaviv_compiler.c
+@@ -2044,7 +2044,7 @@ permute_ps_inputs(struct etna_compile *c)
+
+ /* fill in ps inputs into shader object */
+ static void
+-fill_in_ps_inputs(struct etna_shader *sobj, struct etna_compile *c)
++fill_in_ps_inputs(struct etna_shader_variant *sobj, struct etna_compile *c)
+ {
+ struct etna_shader_io_file *sf = &sobj->infile;
+
+@@ -2074,7 +2074,7 @@ fill_in_ps_inputs(struct etna_shader *sobj, struct etna_compile *c)
+
+ /* fill in output mapping for ps into shader object */
+ static void
+-fill_in_ps_outputs(struct etna_shader *sobj, struct etna_compile *c)
++fill_in_ps_outputs(struct etna_shader_variant *sobj, struct etna_compile *c)
+ {
+ sobj->outfile.num_reg = 0;
+
+@@ -2096,7 +2096,7 @@ fill_in_ps_outputs(struct etna_shader *sobj, struct etna_compile *c)
+
+ /* fill in inputs for vs into shader object */
+ static void
+-fill_in_vs_inputs(struct etna_shader *sobj, struct etna_compile *c)
++fill_in_vs_inputs(struct etna_shader_variant *sobj, struct etna_compile *c)
+ {
+ struct etna_shader_io_file *sf = &sobj->infile;
+
+@@ -2116,7 +2116,7 @@ fill_in_vs_inputs(struct etna_shader *sobj, struct etna_compile *c)
+
+ /* build two-level output index [Semantic][Index] for fast linking */
+ static void
+-build_output_index(struct etna_shader *sobj)
++build_output_index(struct etna_shader_variant *sobj)
+ {
+ int total = 0;
+ int offset = 0;
+@@ -2140,7 +2140,7 @@ build_output_index(struct etna_shader *sobj)
+
+ /* fill in outputs for vs into shader object */
+ static void
+-fill_in_vs_outputs(struct etna_shader *sobj, struct etna_compile *c)
++fill_in_vs_outputs(struct etna_shader_variant *sobj, struct etna_compile *c)
+ {
+ struct etna_shader_io_file *sf = &sobj->outfile;
+
+@@ -2240,7 +2240,7 @@ etna_compile_check_limits(struct etna_compile *c)
+ }
+
+ static void
+-copy_uniform_state_to_shader(struct etna_compile *c, struct etna_shader *sobj)
++copy_uniform_state_to_shader(struct etna_compile *c, struct etna_shader_variant *sobj)
+ {
+ uint32_t count = c->imm_size;
+ struct etna_shader_uniform_info *uinfo = &sobj->uniforms;
+@@ -2253,7 +2253,7 @@ copy_uniform_state_to_shader(struct etna_compile *c, struct etna_shader *sobj)
+ etna_set_shader_uniforms_dirty_flags(sobj);
+ }
+
+-struct etna_shader *
++struct etna_shader_variant *
+ etna_compile_shader(const struct etna_specs *specs,
+ const struct tgsi_token *tokens)
+ {
+@@ -2261,7 +2261,7 @@ etna_compile_shader(const struct etna_specs *specs,
+ */
+ bool ret;
+ struct etna_compile *c;
+- struct etna_shader *shader;
++ struct etna_shader_variant *shader;
+
+ struct tgsi_lowering_config lconfig = {
+ .lower_SCS = specs->has_sin_cos_sqrt,
+@@ -2280,7 +2280,7 @@ etna_compile_shader(const struct etna_specs *specs,
+ if (!c)
+ return NULL;
+
+- shader = CALLOC_STRUCT(etna_shader);
++ shader = CALLOC_STRUCT(etna_shader_variant);
+ if (!shader)
+ goto out;
+
+@@ -2450,7 +2450,7 @@ out:
+
+ extern const char *tgsi_swizzle_names[];
+ void
+-etna_dump_shader(const struct etna_shader *shader)
++etna_dump_shader(const struct etna_shader_variant *shader)
+ {
+ if (shader->processor == PIPE_SHADER_VERTEX)
+ printf("VERT\n");
+@@ -2498,7 +2498,7 @@ etna_dump_shader(const struct etna_shader *shader)
+ }
+
+ void
+-etna_destroy_shader(struct etna_shader *shader)
++etna_destroy_shader(struct etna_shader_variant *shader)
+ {
+ assert(shader);
+
+@@ -2510,7 +2510,7 @@ etna_destroy_shader(struct etna_shader *shader)
+ }
+
+ static const struct etna_shader_inout *
+-etna_shader_vs_lookup(const struct etna_shader *sobj,
++etna_shader_vs_lookup(const struct etna_shader_variant *sobj,
+ const struct etna_shader_inout *in)
+ {
+ if (in->semantic.Index < sobj->output_count_per_semantic[in->semantic.Name])
+@@ -2521,7 +2521,7 @@ etna_shader_vs_lookup(const struct etna_shader *sobj,
+
+ bool
+ etna_link_shader(struct etna_shader_link_info *info,
+- const struct etna_shader *vs, const struct etna_shader *fs)
++ const struct etna_shader_variant *vs, const struct etna_shader_variant *fs)
+ {
+ /* For each fragment input we need to find the associated vertex shader
+ * output, which can be found by matching on semantic name and index. A
+diff --git a/src/gallium/drivers/etnaviv/etnaviv_compiler.h b/src/gallium/drivers/etnaviv/etnaviv_compiler.h
+index de3e20d..2a3b4f4 100644
+--- a/src/gallium/drivers/etnaviv/etnaviv_compiler.h
++++ b/src/gallium/drivers/etnaviv/etnaviv_compiler.h
+@@ -55,7 +55,7 @@ struct etna_shader_io_file {
+ };
+
+ /* shader object, for linking */
+-struct etna_shader {
++struct etna_shader_variant {
+ uint32_t id; /* for debug */
+
+ uint processor; /* TGSI_PROCESSOR_... */
+@@ -107,17 +107,17 @@ struct etna_shader_link_info {
+ struct etna_varying varyings[ETNA_NUM_INPUTS];
+ };
+
+-struct etna_shader *
++struct etna_shader_variant *
+ etna_compile_shader(const struct etna_specs *specs, const struct tgsi_token *tokens);
+
+ void
+-etna_dump_shader(const struct etna_shader *shader);
++etna_dump_shader(const struct etna_shader_variant *shader);
+
+ bool
+ etna_link_shader(struct etna_shader_link_info *info,
+- const struct etna_shader *vs, const struct etna_shader *fs);
++ const struct etna_shader_variant *vs, const struct etna_shader_variant *fs);
+
+ void
+-etna_destroy_shader(struct etna_shader *shader);
++etna_destroy_shader(struct etna_shader_variant *shader);
+
+ #endif
+diff --git a/src/gallium/drivers/etnaviv/etnaviv_compiler_cmdline.c b/src/gallium/drivers/etnaviv/etnaviv_compiler_cmdline.c
+index 6f241d1..48f74b8 100644
+--- a/src/gallium/drivers/etnaviv/etnaviv_compiler_cmdline.c
++++ b/src/gallium/drivers/etnaviv/etnaviv_compiler_cmdline.c
+@@ -98,7 +98,7 @@ main(int argc, char **argv)
+ const char *filename;
+ struct tgsi_token toks[65536];
+ struct tgsi_parse_context parse;
+- struct etna_shader *shader_obj;
++ struct etna_shader_variant *shader_obj;
+ void *ptr;
+ size_t size;
+
+diff --git a/src/gallium/drivers/etnaviv/etnaviv_context.h b/src/gallium/drivers/etnaviv/etnaviv_context.h
+index a921403..81acc92 100644
+--- a/src/gallium/drivers/etnaviv/etnaviv_context.h
++++ b/src/gallium/drivers/etnaviv/etnaviv_context.h
+@@ -41,7 +41,7 @@
+ #include "util/slab.h"
+
+ struct pipe_screen;
+-struct etna_shader;
++struct etna_shader_variant;
+
+ struct etna_index_buffer {
+ struct pipe_index_buffer ib;
+@@ -157,8 +157,8 @@ struct etna_context {
+ struct etna_index_buffer index_buffer;
+
+ /* pointers to the bound state. these are mainly kept around for the blitter */
+- struct etna_shader *vs;
+- struct etna_shader *fs;
++ struct etna_shader_variant *vs;
++ struct etna_shader_variant *fs;
+
+ /* saved parameter-like state. these are mainly kept around for the blitter */
+ struct pipe_framebuffer_state framebuffer_s;
+diff --git a/src/gallium/drivers/etnaviv/etnaviv_shader.c b/src/gallium/drivers/etnaviv/etnaviv_shader.c
+index 87edf5b..35084e5 100644
+--- a/src/gallium/drivers/etnaviv/etnaviv_shader.c
++++ b/src/gallium/drivers/etnaviv/etnaviv_shader.c
+@@ -44,7 +44,7 @@
+ */
+ static bool
+ etna_link_shaders(struct etna_context *ctx, struct compiled_shader_state *cs,
+- const struct etna_shader *vs, const struct etna_shader *fs)
++ const struct etna_shader_variant *vs, const struct etna_shader_variant *fs)
+ {
+ struct etna_shader_link_info link = { };
+
+@@ -182,7 +182,7 @@ etna_shader_link(struct etna_context *ctx)
+ static bool
+ etna_shader_update_vs_inputs(struct etna_context *ctx,
+ struct compiled_shader_state *cs,
+- const struct etna_shader *vs,
++ const struct etna_shader_variant *vs,
+ const struct compiled_vertex_elements_state *ves)
+ {
+ unsigned num_temps, cur_temp, num_vs_inputs;
+@@ -224,7 +224,7 @@ etna_shader_update_vs_inputs(struct etna_context *ctx,
+ }
+
+ static inline const char *
+-etna_shader_stage(struct etna_shader *shader)
++etna_shader_stage(struct etna_shader_variant *shader)
+ {
+ switch (shader->processor) {
+ case PIPE_SHADER_VERTEX: return "VERT";
+@@ -237,7 +237,7 @@ etna_shader_stage(struct etna_shader *shader)
+ }
+
+ static void
+-dump_shader_info(struct etna_shader *shader, struct pipe_debug_callback *debug)
++dump_shader_info(struct etna_shader_variant *shader, struct pipe_debug_callback *debug)
+ {
+ if (!unlikely(etna_mesa_debug & ETNA_DBG_SHADERDB))
+ return;
+@@ -271,7 +271,7 @@ etna_create_shader_state(struct pipe_context *pctx,
+ const struct pipe_shader_state *pss)
+ {
+ struct etna_context *ctx = etna_context(pctx);
+- struct etna_shader *shader = etna_compile_shader(&ctx->specs, pss->tokens);
++ struct etna_shader_variant *shader = etna_compile_shader(&ctx->specs, pss->tokens);
+
+ static uint32_t id;
+ shader->id = id++;
+@@ -291,7 +291,7 @@ static void
+ etna_bind_fs_state(struct pipe_context *pctx, void *fss_)
+ {
+ struct etna_context *ctx = etna_context(pctx);
+- struct etna_shader *fss = fss_;
++ struct etna_shader_variant *fss = fss_;
+
+ if (ctx->fs == fss) /* skip if already bound */
+ return;
+@@ -305,7 +305,7 @@ static void
+ etna_bind_vs_state(struct pipe_context *pctx, void *vss_)
+ {
+ struct etna_context *ctx = etna_context(pctx);
+- struct etna_shader *vss = vss_;
++ struct etna_shader_variant *vss = vss_;
+
+ if (ctx->vs == vss) /* skip if already bound */
+ return;
+diff --git a/src/gallium/drivers/etnaviv/etnaviv_uniforms.c b/src/gallium/drivers/etnaviv/etnaviv_uniforms.c
+index 70e5d58..7487426 100644
+--- a/src/gallium/drivers/etnaviv/etnaviv_uniforms.c
++++ b/src/gallium/drivers/etnaviv/etnaviv_uniforms.c
+@@ -59,7 +59,7 @@ get_texrect_scale(const struct etna_context *ctx, bool frag,
+
+ void
+ etna_uniforms_write(const struct etna_context *ctx,
+- const struct etna_shader *sobj,
++ const struct etna_shader_variant *sobj,
+ struct pipe_constant_buffer *cb, uint32_t *uniforms,
+ unsigned *size)
+ {
+@@ -97,7 +97,7 @@ etna_uniforms_write(const struct etna_context *ctx,
+ }
+
+ void
+-etna_set_shader_uniforms_dirty_flags(struct etna_shader *sobj)
++etna_set_shader_uniforms_dirty_flags(struct etna_shader_variant *sobj)
+ {
+ uint32_t dirty = 0;
+
+diff --git a/src/gallium/drivers/etnaviv/etnaviv_uniforms.h b/src/gallium/drivers/etnaviv/etnaviv_uniforms.h
+index 83a3a49..1dacd2a 100644
+--- a/src/gallium/drivers/etnaviv/etnaviv_uniforms.h
++++ b/src/gallium/drivers/etnaviv/etnaviv_uniforms.h
+@@ -30,16 +30,16 @@
+ #include <stdint.h>
+
+ struct etna_context;
+-struct etna_shader;
++struct etna_shader_variant;
+ struct pipe_constant_buffer;
+
+ void
+ etna_uniforms_write(const struct etna_context *ctx,
+- const struct etna_shader *sobj,
++ const struct etna_shader_variant *sobj,
+ struct pipe_constant_buffer *cb, uint32_t *uniforms,
+ unsigned *size);
+
+ void
+-etna_set_shader_uniforms_dirty_flags(struct etna_shader *sobj);
++etna_set_shader_uniforms_dirty_flags(struct etna_shader_variant *sobj);
+
+ #endif /* ETNAVIV_UNIFORMS_H_ */
+--
+2.7.4
+
--- /dev/null
+From 86695a4b2107b0369255cf4e2978f73ad179d087 Mon Sep 17 00:00:00 2001
+From: Christian Gmeiner <christian.gmeiner@gmail.com>
+Date: Tue, 14 Mar 2017 19:57:15 +0100
+Subject: [PATCH 06/14] etnaviv: add basic shader variant support
+
+This commit adds some basic infrastructure to handle shader
+variants. We are still creating exactly one shader variant
+for each shader.
+
+Signed-off-by: Christian Gmeiner <christian.gmeiner@gmail.com>
+---
+ src/gallium/drivers/etnaviv/etnaviv_compiler.h | 3 ++
+ src/gallium/drivers/etnaviv/etnaviv_shader.c | 49 +++++++++++++++++++++++---
+ src/gallium/drivers/etnaviv/etnaviv_shader.h | 12 +++++++
+ 3 files changed, 60 insertions(+), 4 deletions(-)
+
+diff --git a/src/gallium/drivers/etnaviv/etnaviv_compiler.h b/src/gallium/drivers/etnaviv/etnaviv_compiler.h
+index 2a3b4f4..8de0126 100644
+--- a/src/gallium/drivers/etnaviv/etnaviv_compiler.h
++++ b/src/gallium/drivers/etnaviv/etnaviv_compiler.h
+@@ -92,6 +92,9 @@ struct etna_shader_variant {
+
+ /* unknown input property (XX_INPUT_COUNT, field UNK8) */
+ uint32_t input_count_unk8;
++
++ /* shader variants form a linked list */
++ struct etna_shader_variant *next;
+ };
+
+ struct etna_varying {
+diff --git a/src/gallium/drivers/etnaviv/etnaviv_shader.c b/src/gallium/drivers/etnaviv/etnaviv_shader.c
+index 35084e5..d6bc9bc 100644
+--- a/src/gallium/drivers/etnaviv/etnaviv_shader.c
++++ b/src/gallium/drivers/etnaviv/etnaviv_shader.c
+@@ -31,6 +31,7 @@
+ #include "etnaviv_debug.h"
+ #include "etnaviv_util.h"
+
++#include "tgsi/tgsi_parse.h"
+ #include "util/u_math.h"
+ #include "util/u_memory.h"
+
+@@ -266,25 +267,65 @@ etna_shader_update_vertex(struct etna_context *ctx)
+ ctx->vertex_elements);
+ }
+
++static struct etna_shader_variant *
++create_variant(struct etna_shader *shader)
++{
++ struct etna_shader_variant *v;
++
++ v = etna_compile_shader(shader->specs, shader->tokens);
++ if (!v) {
++ debug_error("compile failed!");
++ return NULL;
++ }
++
++ v->id = ++shader->variant_count;
++
++ return v;
++}
++
+ static void *
+ etna_create_shader_state(struct pipe_context *pctx,
+ const struct pipe_shader_state *pss)
+ {
+ struct etna_context *ctx = etna_context(pctx);
+- struct etna_shader_variant *shader = etna_compile_shader(&ctx->specs, pss->tokens);
++ struct etna_shader *shader = CALLOC_STRUCT(etna_shader);
++
++ if (!shader)
++ return NULL;
+
+ static uint32_t id;
+ shader->id = id++;
++ shader->specs = &ctx->specs;
++ shader->tokens = tgsi_dup_tokens(pss->tokens);
+
+- dump_shader_info(shader, &ctx->debug);
++ /* compile new variant */
++ struct etna_shader_variant *v;
+
+- return shader;
++ v = create_variant(shader);
++ if (v) {
++ v->next = shader->variants;
++ shader->variants = v;
++ dump_shader_info(v, &ctx->debug);
++ }
++
++ return v;
+ }
+
+ static void
+ etna_delete_shader_state(struct pipe_context *pctx, void *ss)
+ {
+- etna_destroy_shader(ss);
++ struct etna_shader *shader = ss;
++ struct etna_shader_variant *v, *t;
++
++ v = shader->variants;
++ while (v) {
++ t = v;
++ v = v->next;
++ etna_destroy_shader(t);
++ }
++
++ FREE((void *)shader->tokens);
++ FREE(shader);
+ }
+
+ static void
+diff --git a/src/gallium/drivers/etnaviv/etnaviv_shader.h b/src/gallium/drivers/etnaviv/etnaviv_shader.h
+index 1dbd200..c613c17 100644
+--- a/src/gallium/drivers/etnaviv/etnaviv_shader.h
++++ b/src/gallium/drivers/etnaviv/etnaviv_shader.h
+@@ -30,6 +30,18 @@
+ #include "pipe/p_state.h"
+
+ struct etna_context;
++struct etna_shader_variant;
++
++struct etna_shader {
++ /* shader id (for debug): */
++ uint32_t id;
++ uint32_t variant_count;
++
++ struct tgsi_token *tokens;
++ struct etna_specs *specs;
++
++ struct etna_shader_variant *variants;
++};
+
+ bool
+ etna_shader_link(struct etna_context *ctx);
+--
+2.7.4
+
--- /dev/null
+From 5dfc5e8c5a8974eddd31837f81ae8ffb28575eb6 Mon Sep 17 00:00:00 2001
+From: Christian Gmeiner <christian.gmeiner@gmail.com>
+Date: Tue, 14 Mar 2017 22:25:17 +0100
+Subject: [PATCH 07/14] etnaviv: add struct etna_shader_state
+
+Signed-off-by: Christian Gmeiner <christian.gmeiner@gmail.com>
+---
+ src/gallium/drivers/etnaviv/etnaviv_clear_blit.c | 4 ++--
+ src/gallium/drivers/etnaviv/etnaviv_context.h | 9 +++++----
+ src/gallium/drivers/etnaviv/etnaviv_emit.c | 16 ++++++++--------
+ src/gallium/drivers/etnaviv/etnaviv_shader.c | 16 ++++++++--------
+ src/gallium/drivers/etnaviv/etnaviv_uniforms.c | 2 +-
+ 5 files changed, 24 insertions(+), 23 deletions(-)
+
+diff --git a/src/gallium/drivers/etnaviv/etnaviv_clear_blit.c b/src/gallium/drivers/etnaviv/etnaviv_clear_blit.c
+index 6c61ad5..35d635f 100644
+--- a/src/gallium/drivers/etnaviv/etnaviv_clear_blit.c
++++ b/src/gallium/drivers/etnaviv/etnaviv_clear_blit.c
+@@ -49,11 +49,11 @@ etna_blit_save_state(struct etna_context *ctx)
+ {
+ util_blitter_save_vertex_buffer_slot(ctx->blitter, ctx->vertex_buffer.vb);
+ util_blitter_save_vertex_elements(ctx->blitter, ctx->vertex_elements);
+- util_blitter_save_vertex_shader(ctx->blitter, ctx->vs);
++ util_blitter_save_vertex_shader(ctx->blitter, ctx->shader.vs);
+ util_blitter_save_rasterizer(ctx->blitter, ctx->rasterizer);
+ util_blitter_save_viewport(ctx->blitter, &ctx->viewport_s);
+ util_blitter_save_scissor(ctx->blitter, &ctx->scissor_s);
+- util_blitter_save_fragment_shader(ctx->blitter, ctx->fs);
++ util_blitter_save_fragment_shader(ctx->blitter, ctx->shader.fs);
+ util_blitter_save_blend(ctx->blitter, ctx->blend);
+ util_blitter_save_depth_stencil_alpha(ctx->blitter, ctx->zsa);
+ util_blitter_save_stencil_ref(ctx->blitter, &ctx->stencil_ref_s);
+diff --git a/src/gallium/drivers/etnaviv/etnaviv_context.h b/src/gallium/drivers/etnaviv/etnaviv_context.h
+index 81acc92..b847b65 100644
+--- a/src/gallium/drivers/etnaviv/etnaviv_context.h
++++ b/src/gallium/drivers/etnaviv/etnaviv_context.h
+@@ -79,6 +79,10 @@ struct etna_vertexbuf_state {
+ uint32_t enabled_mask;
+ };
+
++struct etna_shader_state {
++ struct etna_shader_variant *vs, *fs;
++};
++
+ enum etna_immediate_contents {
+ ETNA_IMMEDIATE_UNUSED = 0,
+ ETNA_IMMEDIATE_CONSTANT,
+@@ -155,10 +159,7 @@ struct etna_context {
+ struct pipe_constant_buffer constant_buffer[PIPE_SHADER_TYPES];
+ struct etna_vertexbuf_state vertex_buffer;
+ struct etna_index_buffer index_buffer;
+-
+- /* pointers to the bound state. these are mainly kept around for the blitter */
+- struct etna_shader_variant *vs;
+- struct etna_shader_variant *fs;
++ struct etna_shader_state shader;
+
+ /* saved parameter-like state. these are mainly kept around for the blitter */
+ struct pipe_framebuffer_state framebuffer_s;
+diff --git a/src/gallium/drivers/etnaviv/etnaviv_emit.c b/src/gallium/drivers/etnaviv/etnaviv_emit.c
+index 8394474..af74cbb 100644
+--- a/src/gallium/drivers/etnaviv/etnaviv_emit.c
++++ b/src/gallium/drivers/etnaviv/etnaviv_emit.c
+@@ -253,8 +253,8 @@ required_stream_size(struct etna_context *ctx)
+ size += ctx->vertex_elements->num_elements + 1;
+
+ /* uniforms - worst case (2 words per uniform load) */
+- size += ctx->vs->uniforms.const_count * 2;
+- size += ctx->fs->uniforms.const_count * 2;
++ size += ctx->shader.vs->uniforms.const_count * 2;
++ size += ctx->shader.fs->uniforms.const_count * 2;
+
+ /* shader */
+ size += ctx->shader_state.vs_inst_mem_size + 1;
+@@ -722,14 +722,14 @@ etna_emit_state(struct etna_context *ctx)
+ static const uint32_t uniform_dirty_bits =
+ ETNA_DIRTY_SHADER | ETNA_DIRTY_CONSTBUF;
+
+- if (dirty & (uniform_dirty_bits | ctx->fs->uniforms_dirty_bits))
++ if (dirty & (uniform_dirty_bits | ctx->shader.fs->uniforms_dirty_bits))
+ etna_uniforms_write(
+- ctx, ctx->vs, &ctx->constant_buffer[PIPE_SHADER_VERTEX],
++ ctx, ctx->shader.vs, &ctx->constant_buffer[PIPE_SHADER_VERTEX],
+ ctx->shader_state.VS_UNIFORMS, &ctx->shader_state.vs_uniforms_size);
+
+- if (dirty & (uniform_dirty_bits | ctx->vs->uniforms_dirty_bits))
++ if (dirty & (uniform_dirty_bits | ctx->shader.vs->uniforms_dirty_bits))
+ etna_uniforms_write(
+- ctx, ctx->fs, &ctx->constant_buffer[PIPE_SHADER_FRAGMENT],
++ ctx, ctx->shader.fs, &ctx->constant_buffer[PIPE_SHADER_FRAGMENT],
+ ctx->shader_state.PS_UNIFORMS, &ctx->shader_state.ps_uniforms_size);
+
+ /**** Large dynamically-sized state ****/
+@@ -762,7 +762,7 @@ etna_emit_state(struct etna_context *ctx)
+ ctx->shader_state.ps_uniforms_size * 4);
+ } else {
+ etna_coalesce_start(stream, &coalesce);
+- for (int x = 0; x < ctx->vs->uniforms.const_count; ++x) {
++ for (int x = 0; x < ctx->shader.vs->uniforms.const_count; ++x) {
+ if (ctx->gpu3d.VS_UNIFORMS[x] != ctx->shader_state.VS_UNIFORMS[x]) {
+ /*05000*/ EMIT_STATE(VS_UNIFORMS(x), ctx->shader_state.VS_UNIFORMS[x]);
+ ctx->gpu3d.VS_UNIFORMS[x] = ctx->shader_state.VS_UNIFORMS[x];
+@@ -771,7 +771,7 @@ etna_emit_state(struct etna_context *ctx)
+ etna_coalesce_end(stream, &coalesce);
+
+ etna_coalesce_start(stream, &coalesce);
+- for (int x = 0; x < ctx->fs->uniforms.const_count; ++x) {
++ for (int x = 0; x < ctx->shader.fs->uniforms.const_count; ++x) {
+ if (ctx->gpu3d.PS_UNIFORMS[x] != ctx->shader_state.PS_UNIFORMS[x]) {
+ /*07000*/ EMIT_STATE(PS_UNIFORMS(x), ctx->shader_state.PS_UNIFORMS[x]);
+ ctx->gpu3d.PS_UNIFORMS[x] = ctx->shader_state.PS_UNIFORMS[x];
+diff --git a/src/gallium/drivers/etnaviv/etnaviv_shader.c b/src/gallium/drivers/etnaviv/etnaviv_shader.c
+index d6bc9bc..f89b23f 100644
+--- a/src/gallium/drivers/etnaviv/etnaviv_shader.c
++++ b/src/gallium/drivers/etnaviv/etnaviv_shader.c
+@@ -173,11 +173,11 @@ etna_link_shaders(struct etna_context *ctx, struct compiled_shader_state *cs,
+ bool
+ etna_shader_link(struct etna_context *ctx)
+ {
+- if (!ctx->vs || !ctx->fs)
++ if (!ctx->shader.vs || !ctx->shader.fs)
+ return false;
+
+ /* re-link vs and fs if needed */
+- return etna_link_shaders(ctx, &ctx->shader_state, ctx->vs, ctx->fs);
++ return etna_link_shaders(ctx, &ctx->shader_state, ctx->shader.vs, ctx->shader.fs);
+ }
+
+ static bool
+@@ -197,7 +197,7 @@ etna_shader_update_vs_inputs(struct etna_context *ctx,
+ num_vs_inputs = MAX2(ves->num_elements, vs->infile.num_reg);
+ if (num_vs_inputs != ves->num_elements) {
+ BUG("Number of elements %u does not match the number of VS inputs %zu",
+- ctx->vertex_elements->num_elements, ctx->vs->infile.num_reg);
++ ctx->vertex_elements->num_elements, ctx->shader.vs->infile.num_reg);
+ return false;
+ }
+
+@@ -263,7 +263,7 @@ dump_shader_info(struct etna_shader_variant *shader, struct pipe_debug_callback
+ bool
+ etna_shader_update_vertex(struct etna_context *ctx)
+ {
+- return etna_shader_update_vs_inputs(ctx, &ctx->shader_state, ctx->vs,
++ return etna_shader_update_vs_inputs(ctx, &ctx->shader_state, ctx->shader.vs,
+ ctx->vertex_elements);
+ }
+
+@@ -334,11 +334,11 @@ etna_bind_fs_state(struct pipe_context *pctx, void *fss_)
+ struct etna_context *ctx = etna_context(pctx);
+ struct etna_shader_variant *fss = fss_;
+
+- if (ctx->fs == fss) /* skip if already bound */
++ if (ctx->shader.fs == fss) /* skip if already bound */
+ return;
+
+ assert(fss == NULL || fss->processor == PIPE_SHADER_FRAGMENT);
+- ctx->fs = fss;
++ ctx->shader.fs = fss;
+ ctx->dirty |= ETNA_DIRTY_SHADER;
+ }
+
+@@ -348,11 +348,11 @@ etna_bind_vs_state(struct pipe_context *pctx, void *vss_)
+ struct etna_context *ctx = etna_context(pctx);
+ struct etna_shader_variant *vss = vss_;
+
+- if (ctx->vs == vss) /* skip if already bound */
++ if (ctx->shader.vs == vss) /* skip if already bound */
+ return;
+
+ assert(vss == NULL || vss->processor == PIPE_SHADER_VERTEX);
+- ctx->vs = vss;
++ ctx->shader.vs = vss;
+ ctx->dirty |= ETNA_DIRTY_SHADER;
+ }
+
+diff --git a/src/gallium/drivers/etnaviv/etnaviv_uniforms.c b/src/gallium/drivers/etnaviv/etnaviv_uniforms.c
+index 7487426..a8d970d 100644
+--- a/src/gallium/drivers/etnaviv/etnaviv_uniforms.c
++++ b/src/gallium/drivers/etnaviv/etnaviv_uniforms.c
+@@ -72,7 +72,7 @@ etna_uniforms_write(const struct etna_context *ctx,
+ memcpy(uniforms, cb->user_buffer, size);
+ }
+
+- if (sobj == ctx->fs)
++ if (sobj == ctx->shader.fs)
+ frag = true;
+
+ for (uint32_t i = 0; i < uinfo->imm_count; i++) {
+--
+2.7.4
+
--- /dev/null
+From ecb202b8dde0d4eeb110e82eb0fa1ee739b569f5 Mon Sep 17 00:00:00 2001
+From: Christian Gmeiner <christian.gmeiner@gmail.com>
+Date: Sun, 19 Mar 2017 16:31:47 +0100
+Subject: [PATCH 08/14] etnaviv: make specs const
+
+Signed-off-by: Christian Gmeiner <christian.gmeiner@gmail.com>
+---
+ src/gallium/drivers/etnaviv/etnaviv_shader.h | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/gallium/drivers/etnaviv/etnaviv_shader.h b/src/gallium/drivers/etnaviv/etnaviv_shader.h
+index c613c17..9f26bef 100644
+--- a/src/gallium/drivers/etnaviv/etnaviv_shader.h
++++ b/src/gallium/drivers/etnaviv/etnaviv_shader.h
+@@ -38,7 +38,7 @@ struct etna_shader {
+ uint32_t variant_count;
+
+ struct tgsi_token *tokens;
+- struct etna_specs *specs;
++ const struct etna_specs *specs;
+
+ struct etna_shader_variant *variants;
+ };
+--
+2.7.4
+
--- /dev/null
+From 37844a297c28ae067b20f0b8fa6c1c9a2aeca95b Mon Sep 17 00:00:00 2001
+From: Christian Gmeiner <christian.gmeiner@gmail.com>
+Date: Sun, 19 Mar 2017 16:32:40 +0100
+Subject: [PATCH 09/14] etnaviv: pass a preallocated variant to compiler
+
+In the long run the compiler needs to know the specifc variant
+'key' in order to compile appropriate assembly. With this commit
+the variant knows its shader and we are able pass the preallocated
+variant into etna_compile_shader(..). This saves us from passing
+extra ptrs everywhere.
+
+Signed-off-by: Christian Gmeiner <christian.gmeiner@gmail.com>
+---
+ src/gallium/drivers/etnaviv/etnaviv_compiler.c | 53 +++++++++++-----------
+ src/gallium/drivers/etnaviv/etnaviv_compiler.h | 7 ++-
+ .../drivers/etnaviv/etnaviv_compiler_cmdline.c | 22 +++++++--
+ src/gallium/drivers/etnaviv/etnaviv_shader.c | 18 ++++++--
+ 4 files changed, 62 insertions(+), 38 deletions(-)
+
+diff --git a/src/gallium/drivers/etnaviv/etnaviv_compiler.c b/src/gallium/drivers/etnaviv/etnaviv_compiler.c
+index be3838d..7552a8f 100644
+--- a/src/gallium/drivers/etnaviv/etnaviv_compiler.c
++++ b/src/gallium/drivers/etnaviv/etnaviv_compiler.c
+@@ -54,6 +54,7 @@
+ #include "etnaviv_context.h"
+ #include "etnaviv_debug.h"
+ #include "etnaviv_disasm.h"
++#include "etnaviv_shader.h"
+ #include "etnaviv_uniforms.h"
+ #include "etnaviv_util.h"
+
+@@ -2253,15 +2254,18 @@ copy_uniform_state_to_shader(struct etna_compile *c, struct etna_shader_variant
+ etna_set_shader_uniforms_dirty_flags(sobj);
+ }
+
+-struct etna_shader_variant *
+-etna_compile_shader(const struct etna_specs *specs,
+- const struct tgsi_token *tokens)
++bool
++etna_compile_shader(struct etna_shader_variant *v)
+ {
+ /* Create scratch space that may be too large to fit on stack
+ */
+ bool ret;
+ struct etna_compile *c;
+- struct etna_shader_variant *shader;
++
++ if (unlikely(!v))
++ return false;
++
++ const struct etna_specs *specs = v->shader->specs;
+
+ struct tgsi_lowering_config lconfig = {
+ .lower_SCS = specs->has_sin_cos_sqrt,
+@@ -2278,11 +2282,9 @@ etna_compile_shader(const struct etna_specs *specs,
+
+ c = CALLOC_STRUCT(etna_compile);
+ if (!c)
+- return NULL;
++ return false;
+
+- shader = CALLOC_STRUCT(etna_shader_variant);
+- if (!shader)
+- goto out;
++ const struct tgsi_token *tokens = v->shader->tokens;
+
+ c->specs = specs;
+ c->tokens = tgsi_transform_lowering(&lconfig, tokens, &c->info);
+@@ -2412,30 +2414,27 @@ etna_compile_shader(const struct etna_specs *specs,
+ etna_compile_fill_in_labels(c);
+
+ ret = etna_compile_check_limits(c);
+- if (!ret) {
+- FREE(shader);
+- shader = NULL;
++ if (!ret)
+ goto out;
+- }
+
+ /* fill in output structure */
+- shader->processor = c->info.processor;
+- shader->code_size = c->inst_ptr * 4;
+- shader->code = mem_dup(c->code, c->inst_ptr * 16);
+- shader->num_loops = c->num_loops;
+- shader->num_temps = c->next_free_native;
+- shader->vs_pos_out_reg = -1;
+- shader->vs_pointsize_out_reg = -1;
+- shader->ps_color_out_reg = -1;
+- shader->ps_depth_out_reg = -1;
+- copy_uniform_state_to_shader(c, shader);
++ v->processor = c->info.processor;
++ v->code_size = c->inst_ptr * 4;
++ v->code = mem_dup(c->code, c->inst_ptr * 16);
++ v->num_loops = c->num_loops;
++ v->num_temps = c->next_free_native;
++ v->vs_pos_out_reg = -1;
++ v->vs_pointsize_out_reg = -1;
++ v->ps_color_out_reg = -1;
++ v->ps_depth_out_reg = -1;
++ copy_uniform_state_to_shader(c, v);
+
+ if (c->info.processor == PIPE_SHADER_VERTEX) {
+- fill_in_vs_inputs(shader, c);
+- fill_in_vs_outputs(shader, c);
++ fill_in_vs_inputs(v, c);
++ fill_in_vs_outputs(v, c);
+ } else if (c->info.processor == PIPE_SHADER_FRAGMENT) {
+- fill_in_ps_inputs(shader, c);
+- fill_in_ps_outputs(shader, c);
++ fill_in_ps_inputs(v, c);
++ fill_in_ps_outputs(v, c);
+ }
+
+ out:
+@@ -2445,7 +2444,7 @@ out:
+ FREE(c->labels);
+ FREE(c);
+
+- return shader;
++ return ret;
+ }
+
+ extern const char *tgsi_swizzle_names[];
+diff --git a/src/gallium/drivers/etnaviv/etnaviv_compiler.h b/src/gallium/drivers/etnaviv/etnaviv_compiler.h
+index 8de0126..8582e30 100644
+--- a/src/gallium/drivers/etnaviv/etnaviv_compiler.h
++++ b/src/gallium/drivers/etnaviv/etnaviv_compiler.h
+@@ -95,6 +95,9 @@ struct etna_shader_variant {
+
+ /* shader variants form a linked list */
+ struct etna_shader_variant *next;
++
++ /* replicated here to avoid passing extra ptrs everywhere */
++ struct etna_shader *shader;
+ };
+
+ struct etna_varying {
+@@ -110,8 +113,8 @@ struct etna_shader_link_info {
+ struct etna_varying varyings[ETNA_NUM_INPUTS];
+ };
+
+-struct etna_shader_variant *
+-etna_compile_shader(const struct etna_specs *specs, const struct tgsi_token *tokens);
++bool
++etna_compile_shader(struct etna_shader_variant *shader);
+
+ void
+ etna_dump_shader(const struct etna_shader_variant *shader);
+diff --git a/src/gallium/drivers/etnaviv/etnaviv_compiler_cmdline.c b/src/gallium/drivers/etnaviv/etnaviv_compiler_cmdline.c
+index 48f74b8..035ee86 100644
+--- a/src/gallium/drivers/etnaviv/etnaviv_compiler_cmdline.c
++++ b/src/gallium/drivers/etnaviv/etnaviv_compiler_cmdline.c
+@@ -38,6 +38,9 @@
+ #include "etnaviv_compiler.h"
+ #include "etnaviv_debug.h"
+ #include "etnaviv_internal.h"
++#include "etnaviv_shader.h"
++
++#include "util/u_memory.h"
+
+ static const struct etna_specs specs_gc2000 = {
+ .vs_need_z_div = 0,
+@@ -98,10 +101,16 @@ main(int argc, char **argv)
+ const char *filename;
+ struct tgsi_token toks[65536];
+ struct tgsi_parse_context parse;
+- struct etna_shader_variant *shader_obj;
++ struct etna_shader s = {};
+ void *ptr;
+ size_t size;
+
++ struct etna_shader_variant *v = CALLOC_STRUCT(etna_shader_variant);
++ if (!v) {
++ fprintf(stderr, "malloc failed!\n");
++ return 1;
++ }
++
+ etna_mesa_debug = ETNA_DBG_MSGS;
+
+ while (n < argc) {
+@@ -134,13 +143,16 @@ main(int argc, char **argv)
+
+ tgsi_parse_init(&parse, toks);
+
+- shader_obj = etna_compile_shader(&specs_gc2000, toks);
++ s.specs = &specs_gc2000;
++ s.tokens = toks;
++
++ v->shader = &s;
+
+- if (shader_obj == NULL) {
++ if (!etna_compile_shader(v)) {
+ fprintf(stderr, "compiler failed!\n");
+ return 1;
+ }
+
+- etna_dump_shader(shader_obj);
+- etna_destroy_shader(shader_obj);
++ etna_dump_shader(v);
++ etna_destroy_shader(v);
+ }
+diff --git a/src/gallium/drivers/etnaviv/etnaviv_shader.c b/src/gallium/drivers/etnaviv/etnaviv_shader.c
+index f89b23f..8132bc8 100644
+--- a/src/gallium/drivers/etnaviv/etnaviv_shader.c
++++ b/src/gallium/drivers/etnaviv/etnaviv_shader.c
+@@ -270,17 +270,27 @@ etna_shader_update_vertex(struct etna_context *ctx)
+ static struct etna_shader_variant *
+ create_variant(struct etna_shader *shader)
+ {
+- struct etna_shader_variant *v;
++ struct etna_shader_variant *v = CALLOC_STRUCT(etna_shader_variant);
++ int ret;
+
+- v = etna_compile_shader(shader->specs, shader->tokens);
+- if (!v) {
+- debug_error("compile failed!");
++ if (!v)
+ return NULL;
++
++ v->shader = shader;
++
++ ret = etna_compile_shader(v);
++ if (!ret) {
++ debug_error("compile failed!");
++ goto fail;
+ }
+
+ v->id = ++shader->variant_count;
+
+ return v;
++
++fail:
++ FREE(v);
++ return NULL;
+ }
+
+ static void *
+--
+2.7.4
+
--- /dev/null
+From f531f880b74314ed4f53084126011e59dd2b27b0 Mon Sep 17 00:00:00 2001
+From: Christian Gmeiner <christian.gmeiner@gmail.com>
+Date: Sun, 19 Mar 2017 17:19:10 +0100
+Subject: [PATCH 10/14] etnaviv: add etna_shader_key and generate variants if
+ needed
+
+Signed-off-by: Christian Gmeiner <christian.gmeiner@gmail.com>
+---
+ src/gallium/drivers/etnaviv/etnaviv_clear_blit.c | 4 +-
+ src/gallium/drivers/etnaviv/etnaviv_compiler.c | 4 +-
+ src/gallium/drivers/etnaviv/etnaviv_compiler.h | 2 +
+ .../drivers/etnaviv/etnaviv_compiler_cmdline.c | 2 +
+ src/gallium/drivers/etnaviv/etnaviv_context.c | 38 +++++++++++++++
+ src/gallium/drivers/etnaviv/etnaviv_context.h | 1 +
+ src/gallium/drivers/etnaviv/etnaviv_shader.c | 54 +++++++++++-----------
+ src/gallium/drivers/etnaviv/etnaviv_shader.h | 19 ++++++++
+ 8 files changed, 95 insertions(+), 29 deletions(-)
+
+diff --git a/src/gallium/drivers/etnaviv/etnaviv_clear_blit.c b/src/gallium/drivers/etnaviv/etnaviv_clear_blit.c
+index 35d635f..4a03d82 100644
+--- a/src/gallium/drivers/etnaviv/etnaviv_clear_blit.c
++++ b/src/gallium/drivers/etnaviv/etnaviv_clear_blit.c
+@@ -49,11 +49,11 @@ etna_blit_save_state(struct etna_context *ctx)
+ {
+ util_blitter_save_vertex_buffer_slot(ctx->blitter, ctx->vertex_buffer.vb);
+ util_blitter_save_vertex_elements(ctx->blitter, ctx->vertex_elements);
+- util_blitter_save_vertex_shader(ctx->blitter, ctx->shader.vs);
++ util_blitter_save_vertex_shader(ctx->blitter, ctx->shader.bind_vs);
+ util_blitter_save_rasterizer(ctx->blitter, ctx->rasterizer);
+ util_blitter_save_viewport(ctx->blitter, &ctx->viewport_s);
+ util_blitter_save_scissor(ctx->blitter, &ctx->scissor_s);
+- util_blitter_save_fragment_shader(ctx->blitter, ctx->shader.fs);
++ util_blitter_save_fragment_shader(ctx->blitter, ctx->shader.bind_fs);
+ util_blitter_save_blend(ctx->blitter, ctx->blend);
+ util_blitter_save_depth_stencil_alpha(ctx->blitter, ctx->zsa);
+ util_blitter_save_stencil_ref(ctx->blitter, &ctx->stencil_ref_s);
+diff --git a/src/gallium/drivers/etnaviv/etnaviv_compiler.c b/src/gallium/drivers/etnaviv/etnaviv_compiler.c
+index 7552a8f..ce8a651 100644
+--- a/src/gallium/drivers/etnaviv/etnaviv_compiler.c
++++ b/src/gallium/drivers/etnaviv/etnaviv_compiler.c
+@@ -54,7 +54,6 @@
+ #include "etnaviv_context.h"
+ #include "etnaviv_debug.h"
+ #include "etnaviv_disasm.h"
+-#include "etnaviv_shader.h"
+ #include "etnaviv_uniforms.h"
+ #include "etnaviv_util.h"
+
+@@ -197,6 +196,8 @@ struct etna_compile {
+
+ /* GPU hardware specs */
+ const struct etna_specs *specs;
++
++ const struct etna_shader_key *key;
+ };
+
+ static struct etna_reg_desc *
+@@ -2287,6 +2288,7 @@ etna_compile_shader(struct etna_shader_variant *v)
+ const struct tgsi_token *tokens = v->shader->tokens;
+
+ c->specs = specs;
++ c->key = &v->key;
+ c->tokens = tgsi_transform_lowering(&lconfig, tokens, &c->info);
+ c->free_tokens = !!c->tokens;
+ if (!c->tokens) {
+diff --git a/src/gallium/drivers/etnaviv/etnaviv_compiler.h b/src/gallium/drivers/etnaviv/etnaviv_compiler.h
+index 8582e30..88a093f 100644
+--- a/src/gallium/drivers/etnaviv/etnaviv_compiler.h
++++ b/src/gallium/drivers/etnaviv/etnaviv_compiler.h
+@@ -29,6 +29,7 @@
+
+ #include "etnaviv_context.h"
+ #include "etnaviv_internal.h"
++#include "etnaviv_shader.h"
+ #include "pipe/p_compiler.h"
+ #include "pipe/p_shader_tokens.h"
+
+@@ -98,6 +99,7 @@ struct etna_shader_variant {
+
+ /* replicated here to avoid passing extra ptrs everywhere */
+ struct etna_shader *shader;
++ struct etna_shader_key key;
+ };
+
+ struct etna_varying {
+diff --git a/src/gallium/drivers/etnaviv/etnaviv_compiler_cmdline.c b/src/gallium/drivers/etnaviv/etnaviv_compiler_cmdline.c
+index 035ee86..1fea2d1 100644
+--- a/src/gallium/drivers/etnaviv/etnaviv_compiler_cmdline.c
++++ b/src/gallium/drivers/etnaviv/etnaviv_compiler_cmdline.c
+@@ -102,6 +102,7 @@ main(int argc, char **argv)
+ struct tgsi_token toks[65536];
+ struct tgsi_parse_context parse;
+ struct etna_shader s = {};
++ struct etna_shader_key key = {};
+ void *ptr;
+ size_t size;
+
+@@ -147,6 +148,7 @@ main(int argc, char **argv)
+ s.tokens = toks;
+
+ v->shader = &s;
++ v->key = key;
+
+ if (!etna_compile_shader(v)) {
+ fprintf(stderr, "compiler failed!\n");
+diff --git a/src/gallium/drivers/etnaviv/etnaviv_context.c b/src/gallium/drivers/etnaviv/etnaviv_context.c
+index dfd9e1f..d673440 100644
+--- a/src/gallium/drivers/etnaviv/etnaviv_context.c
++++ b/src/gallium/drivers/etnaviv/etnaviv_context.c
+@@ -106,6 +106,37 @@ etna_update_state_for_draw(struct etna_context *ctx, const struct pipe_draw_info
+ }
+ }
+
++static bool
++etna_get_vs(struct etna_context *ctx, struct etna_shader_key key)
++{
++ const struct etna_shader_variant *old = ctx->shader.vs;
++
++ ctx->shader.vs = etna_shader_variant(ctx->shader.bind_vs, key, &ctx->debug);
++
++ if (!ctx->shader.vs)
++ return false;
++
++ if (old != ctx->shader.vs)
++ ctx->dirty |= ETNA_DIRTY_SHADER;
++
++ return true;
++}
++
++static bool
++etna_get_fs(struct etna_context *ctx, struct etna_shader_key key)
++{
++ const struct etna_shader_variant *old = ctx->shader.fs;
++
++ ctx->shader.fs = etna_shader_variant(ctx->shader.bind_fs, key, &ctx->debug);
++
++ if (!ctx->shader.fs)
++ return false;
++
++ if (old != ctx->shader.fs)
++ ctx->dirty |= ETNA_DIRTY_SHADER;
++
++ return true;
++}
+
+ static void
+ etna_draw_vbo(struct pipe_context *pctx, const struct pipe_draw_info *info)
+@@ -152,6 +183,13 @@ etna_draw_vbo(struct pipe_context *pctx, const struct pipe_draw_info *info)
+ return;
+ }
+
++ struct etna_shader_key key = {};
++
++ if (!etna_get_vs(ctx, key) || !etna_get_fs(ctx, key)) {
++ BUG("compiled shaders are not okay");
++ return;
++ }
++
+ /* Update any derived state */
+ if (!etna_state_update(ctx))
+ return;
+diff --git a/src/gallium/drivers/etnaviv/etnaviv_context.h b/src/gallium/drivers/etnaviv/etnaviv_context.h
+index b847b65..9e00d34 100644
+--- a/src/gallium/drivers/etnaviv/etnaviv_context.h
++++ b/src/gallium/drivers/etnaviv/etnaviv_context.h
+@@ -80,6 +80,7 @@ struct etna_vertexbuf_state {
+ };
+
+ struct etna_shader_state {
++ void *bind_vs, *bind_fs;
+ struct etna_shader_variant *vs, *fs;
+ };
+
+diff --git a/src/gallium/drivers/etnaviv/etnaviv_shader.c b/src/gallium/drivers/etnaviv/etnaviv_shader.c
+index 8132bc8..a5f9315 100644
+--- a/src/gallium/drivers/etnaviv/etnaviv_shader.c
++++ b/src/gallium/drivers/etnaviv/etnaviv_shader.c
+@@ -268,7 +268,7 @@ etna_shader_update_vertex(struct etna_context *ctx)
+ }
+
+ static struct etna_shader_variant *
+-create_variant(struct etna_shader *shader)
++create_variant(struct etna_shader *shader, struct etna_shader_key key)
+ {
+ struct etna_shader_variant *v = CALLOC_STRUCT(etna_shader_variant);
+ int ret;
+@@ -277,6 +277,7 @@ create_variant(struct etna_shader *shader)
+ return NULL;
+
+ v->shader = shader;
++ v->key = key;
+
+ ret = etna_compile_shader(v);
+ if (!ret) {
+@@ -293,6 +294,27 @@ fail:
+ return NULL;
+ }
+
++struct etna_shader_variant *
++etna_shader_variant(struct etna_shader *shader, struct etna_shader_key key,
++ struct pipe_debug_callback *debug)
++{
++ struct etna_shader_variant *v;
++
++ for (v = shader->variants; v; v = v->next)
++ if (etna_shader_key_equal(&key, &v->key))
++ return v;
++
++ /* compile new variant if it doesn't exist already */
++ v = create_variant(shader, key);
++ if (v) {
++ v->next = shader->variants;
++ shader->variants = v;
++ dump_shader_info(v, debug);
++ }
++
++ return v;
++}
++
+ static void *
+ etna_create_shader_state(struct pipe_context *pctx,
+ const struct pipe_shader_state *pss)
+@@ -308,17 +330,7 @@ etna_create_shader_state(struct pipe_context *pctx,
+ shader->specs = &ctx->specs;
+ shader->tokens = tgsi_dup_tokens(pss->tokens);
+
+- /* compile new variant */
+- struct etna_shader_variant *v;
+-
+- v = create_variant(shader);
+- if (v) {
+- v->next = shader->variants;
+- shader->variants = v;
+- dump_shader_info(v, &ctx->debug);
+- }
+-
+- return v;
++ return shader;
+ }
+
+ static void
+@@ -339,30 +351,20 @@ etna_delete_shader_state(struct pipe_context *pctx, void *ss)
+ }
+
+ static void
+-etna_bind_fs_state(struct pipe_context *pctx, void *fss_)
++etna_bind_fs_state(struct pipe_context *pctx, void *hwcso)
+ {
+ struct etna_context *ctx = etna_context(pctx);
+- struct etna_shader_variant *fss = fss_;
+-
+- if (ctx->shader.fs == fss) /* skip if already bound */
+- return;
+
+- assert(fss == NULL || fss->processor == PIPE_SHADER_FRAGMENT);
+- ctx->shader.fs = fss;
++ ctx->shader.bind_fs = hwcso;
+ ctx->dirty |= ETNA_DIRTY_SHADER;
+ }
+
+ static void
+-etna_bind_vs_state(struct pipe_context *pctx, void *vss_)
++etna_bind_vs_state(struct pipe_context *pctx, void *hwcso)
+ {
+ struct etna_context *ctx = etna_context(pctx);
+- struct etna_shader_variant *vss = vss_;
+-
+- if (ctx->shader.vs == vss) /* skip if already bound */
+- return;
+
+- assert(vss == NULL || vss->processor == PIPE_SHADER_VERTEX);
+- ctx->shader.vs = vss;
++ ctx->shader.bind_vs = hwcso;
+ ctx->dirty |= ETNA_DIRTY_SHADER;
+ }
+
+diff --git a/src/gallium/drivers/etnaviv/etnaviv_shader.h b/src/gallium/drivers/etnaviv/etnaviv_shader.h
+index 9f26bef..b0d97a7 100644
+--- a/src/gallium/drivers/etnaviv/etnaviv_shader.h
++++ b/src/gallium/drivers/etnaviv/etnaviv_shader.h
+@@ -32,6 +32,21 @@
+ struct etna_context;
+ struct etna_shader_variant;
+
++struct etna_shader_key
++{
++ union {
++ struct {
++ };
++ uint32_t global;
++ };
++};
++
++static inline bool
++etna_shader_key_equal(struct etna_shader_key *a, struct etna_shader_key *b)
++{
++ return a->global == b->global;
++}
++
+ struct etna_shader {
+ /* shader id (for debug): */
+ uint32_t id;
+@@ -49,6 +64,10 @@ etna_shader_link(struct etna_context *ctx);
+ bool
+ etna_shader_update_vertex(struct etna_context *ctx);
+
++struct etna_shader_variant *
++etna_shader_variant(struct etna_shader *shader, struct etna_shader_key key,
++ struct pipe_debug_callback *debug);
++
+ void
+ etna_shader_init(struct pipe_context *pctx);
+
+--
+2.7.4
+
--- /dev/null
+From 3b76a9d565449855cf7b50935dca1024181030e5 Mon Sep 17 00:00:00 2001
+From: Christian Gmeiner <christian.gmeiner@gmail.com>
+Date: Sun, 19 Mar 2017 22:22:18 +0100
+Subject: [PATCH 11/14] etnaviv: bring back shader-db traces
+
+If shader-db run, create a standard variant immediately
+(as otherwise nothing will trigger the shader to be
+actually compiled).
+
+Signed-off-by: Christian Gmeiner <christian.gmeiner@gmail.com>
+---
+ src/gallium/drivers/etnaviv/etnaviv_shader.c | 9 +++++++++
+ 1 file changed, 9 insertions(+)
+
+diff --git a/src/gallium/drivers/etnaviv/etnaviv_shader.c b/src/gallium/drivers/etnaviv/etnaviv_shader.c
+index a5f9315..b1cac02 100644
+--- a/src/gallium/drivers/etnaviv/etnaviv_shader.c
++++ b/src/gallium/drivers/etnaviv/etnaviv_shader.c
+@@ -330,6 +330,15 @@ etna_create_shader_state(struct pipe_context *pctx,
+ shader->specs = &ctx->specs;
+ shader->tokens = tgsi_dup_tokens(pss->tokens);
+
++ if (etna_mesa_debug & ETNA_DBG_SHADERDB) {
++ /* if shader-db run, create a standard variant immediately
++ * (as otherwise nothing will trigger the shader to be
++ * actually compiled).
++ */
++ struct etna_shader_key key = {};
++ etna_shader_variant(shader, key, &ctx->debug);
++ }
++
+ return shader;
+ }
+
+--
+2.7.4
+
--- /dev/null
+From e7ecda7c7089cdc7eaf4d868d903ef53063e8d02 Mon Sep 17 00:00:00 2001
+From: Christian Gmeiner <christian.gmeiner@gmail.com>
+Date: Sun, 19 Mar 2017 22:27:55 +0100
+Subject: [PATCH 12/14] etnaviv: adopt shader-db output for variant support
+
+Signed-off-by: Christian Gmeiner <christian.gmeiner@gmail.com>
+---
+ src/gallium/drivers/etnaviv/etnaviv_shader.c | 30 ++++++++++++++--------------
+ 1 file changed, 15 insertions(+), 15 deletions(-)
+
+diff --git a/src/gallium/drivers/etnaviv/etnaviv_shader.c b/src/gallium/drivers/etnaviv/etnaviv_shader.c
+index b1cac02..4a0b74b 100644
+--- a/src/gallium/drivers/etnaviv/etnaviv_shader.c
++++ b/src/gallium/drivers/etnaviv/etnaviv_shader.c
+@@ -238,26 +238,26 @@ etna_shader_stage(struct etna_shader_variant *shader)
+ }
+
+ static void
+-dump_shader_info(struct etna_shader_variant *shader, struct pipe_debug_callback *debug)
++dump_shader_info(struct etna_shader_variant *v, struct pipe_debug_callback *debug)
+ {
+ if (!unlikely(etna_mesa_debug & ETNA_DBG_SHADERDB))
+ return;
+
+ pipe_debug_message(debug, SHADER_INFO, "\n"
+- "SHADER-DB: %s prog %d: %u instructions %u temps\n"
+- "SHADER-DB: %s prog %d: %u immediates %u consts\n"
+- "SHADER-DB: %s prog %d: %u loops\n",
+- etna_shader_stage(shader),
+- shader->id,
+- shader->code_size,
+- shader->num_temps,
+- etna_shader_stage(shader),
+- shader->id,
+- shader->uniforms.imm_count,
+- shader->uniforms.const_count,
+- etna_shader_stage(shader),
+- shader->id,
+- shader->num_loops);
++ "SHADER-DB: %s prog %d/%d: %u instructions %u temps\n"
++ "SHADER-DB: %s prog %d/%d: %u immediates %u consts\n"
++ "SHADER-DB: %s prog %d/%d: %u loops\n",
++ etna_shader_stage(v),
++ v->shader->id, v->id,
++ v->code_size,
++ v->num_temps,
++ etna_shader_stage(v),
++ v->shader->id, v->id,
++ v->uniforms.imm_count,
++ v->uniforms.const_count,
++ etna_shader_stage(v),
++ v->shader->id, v->id,
++ v->num_loops);
+ }
+
+ bool
+--
+2.7.4
+
--- /dev/null
+From e5dfde21752602ffe0cd94eceb8d69a241da0a06 Mon Sep 17 00:00:00 2001
+From: Christian Gmeiner <christian.gmeiner@gmail.com>
+Date: Tue, 21 Mar 2017 20:00:31 +0100
+Subject: [PATCH 13/14] etnaviv: add support for rb swap
+
+If we render to rb swapped format we will create a shader variant doing
+the involved swizzing in the pixel shader.
+
+Signed-off-by: Christian Gmeiner <christian.gmeiner@gmail.com>
+---
+ src/gallium/drivers/etnaviv/etnaviv_compiler.c | 17 +++++++++++++++++
+ src/gallium/drivers/etnaviv/etnaviv_compiler_cmdline.c | 8 ++++++++
+ src/gallium/drivers/etnaviv/etnaviv_context.c | 7 +++++++
+ src/gallium/drivers/etnaviv/etnaviv_shader.h | 6 ++++++
+ 4 files changed, 38 insertions(+)
+
+diff --git a/src/gallium/drivers/etnaviv/etnaviv_compiler.c b/src/gallium/drivers/etnaviv/etnaviv_compiler.c
+index ce8a651..eafb511 100644
+--- a/src/gallium/drivers/etnaviv/etnaviv_compiler.c
++++ b/src/gallium/drivers/etnaviv/etnaviv_compiler.c
+@@ -1910,6 +1910,22 @@ etna_compile_add_z_div_if_needed(struct etna_compile *c)
+ }
+ }
+
++static void
++etna_compile_frag_rb_swap(struct etna_compile *c)
++{
++ if (c->info.processor == PIPE_SHADER_FRAGMENT && c->key->frag_rb_swap) {
++ /* find color out */
++ struct etna_reg_desc *color_reg =
++ find_decl_by_semantic(c, TGSI_FILE_OUTPUT, TGSI_SEMANTIC_COLOR, 0);
++
++ emit_inst(c, &(struct etna_inst) {
++ .opcode = INST_OPCODE_MOV,
++ .dst = etna_native_to_dst(color_reg->native, INST_COMPS_X | INST_COMPS_Y | INST_COMPS_Z | INST_COMPS_W),
++ .src[2] = etna_native_to_src(color_reg->native, SWIZZLE(Z, Y, X, W)),
++ });
++ }
++}
++
+ /** add a NOP to the shader if
+ * a) the shader is empty
+ * or
+@@ -2412,6 +2428,7 @@ etna_compile_shader(struct etna_shader_variant *v)
+ /* pass 3: generate instructions */
+ etna_compile_pass_generate_code(c);
+ etna_compile_add_z_div_if_needed(c);
++ etna_compile_frag_rb_swap(c);
+ etna_compile_add_nop_if_needed(c);
+ etna_compile_fill_in_labels(c);
+
+diff --git a/src/gallium/drivers/etnaviv/etnaviv_compiler_cmdline.c b/src/gallium/drivers/etnaviv/etnaviv_compiler_cmdline.c
+index 1fea2d1..bdaa78e 100644
+--- a/src/gallium/drivers/etnaviv/etnaviv_compiler_cmdline.c
++++ b/src/gallium/drivers/etnaviv/etnaviv_compiler_cmdline.c
+@@ -91,6 +91,7 @@ print_usage(void)
+ {
+ printf("Usage: etnaviv_compiler [OPTIONS]... FILE\n");
+ printf(" --verbose - verbose compiler/debug messages\n");
++ printf(" --frag-rb-swap - swap rb in color output (FRAG)\n");
+ printf(" --help - show this message\n");
+ }
+
+@@ -121,6 +122,13 @@ main(int argc, char **argv)
+ continue;
+ }
+
++ if (!strcmp(argv[n], "--frag-rb-swap")) {
++ debug_printf(" %s", argv[n]);
++ key.frag_rb_swap = true;
++ n++;
++ continue;
++ }
++
+ if (!strcmp(argv[n], "--help")) {
+ print_usage();
+ return 0;
+diff --git a/src/gallium/drivers/etnaviv/etnaviv_context.c b/src/gallium/drivers/etnaviv/etnaviv_context.c
+index d673440..555aa12 100644
+--- a/src/gallium/drivers/etnaviv/etnaviv_context.c
++++ b/src/gallium/drivers/etnaviv/etnaviv_context.c
+@@ -184,6 +184,13 @@ etna_draw_vbo(struct pipe_context *pctx, const struct pipe_draw_info *info)
+ }
+
+ struct etna_shader_key key = {};
++ struct etna_surface *cbuf = etna_surface(pfb->cbufs[0]);
++
++ if (cbuf) {
++ struct etna_resource *res = etna_resource(cbuf->base.texture);
++
++ key.frag_rb_swap = !!translate_rs_format_rb_swap(res->base.format);
++ }
+
+ if (!etna_get_vs(ctx, key) || !etna_get_fs(ctx, key)) {
+ BUG("compiled shaders are not okay");
+diff --git a/src/gallium/drivers/etnaviv/etnaviv_shader.h b/src/gallium/drivers/etnaviv/etnaviv_shader.h
+index b0d97a7..2b8618f 100644
+--- a/src/gallium/drivers/etnaviv/etnaviv_shader.h
++++ b/src/gallium/drivers/etnaviv/etnaviv_shader.h
+@@ -36,6 +36,12 @@ struct etna_shader_key
+ {
+ union {
+ struct {
++ /*
++ * Combined Vertex/Fragment shader parameters:
++ */
++
++ /* do we need to swap rb in frag color? */
++ unsigned frag_rb_swap : 1;
+ };
+ uint32_t global;
+ };
+--
+2.7.4
+
--- /dev/null
+From 3005677a4abf4da20e512d63ebec4d8ac6bf47ac Mon Sep 17 00:00:00 2001
+From: Christian Gmeiner <christian.gmeiner@gmail.com>
+Date: Sun, 26 Mar 2017 11:30:29 +0200
+Subject: [PATCH 14/14] Revert "etnaviv: Cannot render to rb-swapped formats"
+
+This reverts commit 658568941d5e232d690e1ffbcddbd6ea9685693a.
+
+With the help of shader variants we can render to rb-swapped
+formats now. Fixes about 60 piglits.
+
+Signed-off-by: Christian Gmeiner <christian.gmeiner@gmail.com>
+---
+ src/gallium/drivers/etnaviv/etnaviv_screen.c | 7 ++-----
+ 1 file changed, 2 insertions(+), 5 deletions(-)
+
+diff --git a/src/gallium/drivers/etnaviv/etnaviv_screen.c b/src/gallium/drivers/etnaviv/etnaviv_screen.c
+index ed7fb64..5dbf781 100644
+--- a/src/gallium/drivers/etnaviv/etnaviv_screen.c
++++ b/src/gallium/drivers/etnaviv/etnaviv_screen.c
+@@ -474,11 +474,8 @@ etna_screen_is_format_supported(struct pipe_screen *pscreen,
+ return FALSE;
+
+ if (usage & PIPE_BIND_RENDER_TARGET) {
+- /* If render target, must be RS-supported format that is not rb swapped.
+- * Exposing rb swapped (or other swizzled) formats for rendering would
+- * involve swizzing in the pixel shader.
+- */
+- if (translate_rs_format(format) != ETNA_NO_MATCH && !translate_rs_format_rb_swap(format)) {
++ /* if render target, must be RS-supported format */
++ if (translate_rs_format(format) != ETNA_NO_MATCH) {
+ /* Validate MSAA; number of samples must be allowed, and render target
+ * must have MSAA'able format. */
+ if (sample_count > 1) {
+--
+2.7.4
+
--- /dev/null
+From 9b0000e2d6fcbcfefc6db7e7eac2a51ac1c6629c Mon Sep 17 00:00:00 2001
+From: Carlos Rafael Giani <dv@pseudoterminal.org>
+Date: Sat, 1 Apr 2017 01:49:18 +0200
+Subject: [PATCH] Enable MESA_ycbcr_texture for GLES1 and GLES2
+
+Signed-off-by: Carlos Rafael Giani <dv@pseudoterminal.org>
+---
+ src/mapi/glapi/registry/gl.xml | 2 +-
+ src/mesa/main/extensions_table.h | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/src/mapi/glapi/registry/gl.xml b/src/mapi/glapi/registry/gl.xml
+index 3fc8863..6470d8c 100644
+--- a/src/mapi/glapi/registry/gl.xml
++++ b/src/mapi/glapi/registry/gl.xml
+@@ -43321,7 +43321,7 @@ typedef unsigned int GLhandleARB;
+ <command name="glWindowPos4svMESA"/>
+ </require>
+ </extension>
+- <extension name="GL_MESA_ycbcr_texture" supported="gl">
++ <extension name="GL_MESA_ycbcr_texture" supported="gl|gles1|gles2">
+ <require>
+ <enum name="GL_UNSIGNED_SHORT_8_8_MESA"/>
+ <enum name="GL_UNSIGNED_SHORT_8_8_REV_MESA"/>
+diff --git a/src/mesa/main/extensions_table.h b/src/mesa/main/extensions_table.h
+index ec71791..d223032 100644
+--- a/src/mesa/main/extensions_table.h
++++ b/src/mesa/main/extensions_table.h
+@@ -311,7 +311,7 @@ EXT(MESA_pack_invert , MESA_pack_invert
+ EXT(MESA_shader_integer_functions , MESA_shader_integer_functions , GLL, GLC, x , 30, 2016)
+ EXT(MESA_texture_signed_rgba , EXT_texture_snorm , GLL, GLC, x , x , 2009)
+ EXT(MESA_window_pos , dummy_true , GLL, x , x , x , 2000)
+-EXT(MESA_ycbcr_texture , MESA_ycbcr_texture , GLL, GLC, x , x , 2002)
++EXT(MESA_ycbcr_texture , MESA_ycbcr_texture , GLL, GLC, ES1, ES2, 2002)
+
+ EXT(NVX_gpu_memory_info , NVX_gpu_memory_info , GLL, GLC, x , x , 2013)
+
+--
+2.7.4
+
--- /dev/null
+From 30853f55a3b4c409802ac470ae0530311c36e0c7 Mon Sep 17 00:00:00 2001
+From: Philipp Zabel <p.zabel@pengutronix.de>
+Date: Thu, 19 Jan 2017 15:05:36 +0100
+Subject: [PATCH 16/19] gallium: add pipe_screen::resource_changed
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Add a hook to tell drivers that an imported resource may have changed
+and they need to update their internal derived resources.
+
+Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
+Reviewed-by: Roland Scheidegger <sroland@vmware.com>
+Reviewed-by: Marek Olšák <marek.olsak@amd.com>
+Signed-off-by: Lucas Stach <l.stach@pengutronix.de>
+---
+ src/gallium/docs/source/screen.rst | 14 ++++++++++++++
+ src/gallium/include/pipe/p_screen.h | 8 ++++++++
+ 2 files changed, 22 insertions(+)
+
+diff --git a/src/gallium/docs/source/screen.rst b/src/gallium/docs/source/screen.rst
+index 64cb0bf..5ae2596 100644
+--- a/src/gallium/docs/source/screen.rst
++++ b/src/gallium/docs/source/screen.rst
+@@ -707,6 +707,20 @@ which isn't multisampled.
+
+
+
++resource_changed
++^^^^^^^^^^^^^^^^
++
++Mark a resource as changed so derived internal resources will be recreated
++on next use.
++
++When importing external images that can't be directly used as texture sampler
++source, internal copies may have to be created that the hardware can sample
++from. When those resources are reimported, the image data may have changed, and
++the previously derived internal resources must be invalidated to avoid sampling
++from old copies.
++
++
++
+ resource_destroy
+ ^^^^^^^^^^^^^^^^
+
+diff --git a/src/gallium/include/pipe/p_screen.h b/src/gallium/include/pipe/p_screen.h
+index f04c2ed..b6203f1 100644
+--- a/src/gallium/include/pipe/p_screen.h
++++ b/src/gallium/include/pipe/p_screen.h
+@@ -224,6 +224,14 @@ struct pipe_screen {
+ struct winsys_handle *handle,
+ unsigned usage);
+
++ /**
++ * Mark the resource as changed so derived internal resources will be
++ * recreated on next use.
++ *
++ * This is necessary when reimporting external images that can't be directly
++ * used as texture sampler source, to avoid sampling from old copies.
++ */
++ void (*resource_changed)(struct pipe_screen *, struct pipe_resource *pt);
+
+ void (*resource_destroy)(struct pipe_screen *,
+ struct pipe_resource *pt);
+--
+2.7.4
+
--- /dev/null
+From 2c95d6dac399ca58c5bf93f03cd4d19dc84c55af Mon Sep 17 00:00:00 2001
+From: Philipp Zabel <p.zabel@pengutronix.de>
+Date: Thu, 19 Jan 2017 15:05:37 +0100
+Subject: [PATCH 17/19] st/dri: ask the driver to update its internal copies on
+ reimport
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+For imported buffers that can't be used directly as a source to the
+texture samplers, the pipe driver might need to create an internal
+copy, for example in a different tiling layout. When buffers are
+reimported they may contain new image data, so the driver internal
+copies need to be recreated.
+
+Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
+Reviewed-by: Marek Olšák <marek.olsak@amd.com>
+Signed-off-by: Lucas Stach <l.stach@pengutronix.de>
+---
+ src/gallium/state_trackers/dri/dri2.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/src/gallium/state_trackers/dri/dri2.c b/src/gallium/state_trackers/dri/dri2.c
+index 77523e9..c4f2c57 100644
+--- a/src/gallium/state_trackers/dri/dri2.c
++++ b/src/gallium/state_trackers/dri/dri2.c
+@@ -1168,6 +1168,10 @@ dri2_from_planar(__DRIimage *image, int plane, void *loaderPrivate)
+ if (img == NULL)
+ return NULL;
+
++ if (img->texture->screen->resource_changed)
++ img->texture->screen->resource_changed(img->texture->screen,
++ img->texture);
++
+ /* set this to 0 for sub images. */
+ img->dri_components = 0;
+ return img;
+--
+2.7.4
+
--- /dev/null
+From 362edc868cf6314dc61d3670aa334f35655975bc Mon Sep 17 00:00:00 2001
+From: Philipp Zabel <p.zabel@pengutronix.de>
+Date: Thu, 19 Jan 2017 15:05:38 +0100
+Subject: [PATCH 18/19] etnaviv: initialize seqno of imported resources
+
+Imported resources already have contents that we want to be copied to
+texture resources derived from them. Set initial seqno of imported
+resources to 1, just as if it had already been rendered to.
+
+Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
+Reviewed-by: Christian Gmeiner <christian.gmeiner@gmail.com>
+Signed-off-by: Lucas Stach <l.stach@pengutronix.de>
+---
+ src/gallium/drivers/etnaviv/etnaviv_resource.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/src/gallium/drivers/etnaviv/etnaviv_resource.c b/src/gallium/drivers/etnaviv/etnaviv_resource.c
+index aefe65b..a8858c5 100644
+--- a/src/gallium/drivers/etnaviv/etnaviv_resource.c
++++ b/src/gallium/drivers/etnaviv/etnaviv_resource.c
+@@ -325,6 +325,8 @@ etna_resource_from_handle(struct pipe_screen *pscreen,
+ if (!rsc->bo)
+ goto fail;
+
++ rsc->seqno = 1;
++
+ level->width = tmpl->width0;
+ level->height = tmpl->height0;
+
+--
+2.7.4
+
--- /dev/null
+From c70ed79e79a717be80d9d480760dcbdb14f06c52 Mon Sep 17 00:00:00 2001
+From: Philipp Zabel <p.zabel@pengutronix.de>
+Date: Thu, 19 Jan 2017 15:05:39 +0100
+Subject: [PATCH 19/19] etnaviv: implement resource_changed to invalidate
+ internal resources derived from imported buffers
+
+Implement the resource_changed pipe callback to invalidate internal
+resources derived from imported buffers. This is needed to update the
+texture for re-imported renderables.
+
+Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
+Reviewed-by: Reviewed-by: Christian Gmeiner <christian.gmeiner@gmail.com>
+Signed-off-by: Lucas Stach <l.stach@pengutronix.de>
+---
+ src/gallium/drivers/etnaviv/etnaviv_resource.c | 13 +++++++++++++
+ 1 file changed, 13 insertions(+)
+
+diff --git a/src/gallium/drivers/etnaviv/etnaviv_resource.c b/src/gallium/drivers/etnaviv/etnaviv_resource.c
+index a8858c5..20ec8f8 100644
+--- a/src/gallium/drivers/etnaviv/etnaviv_resource.c
++++ b/src/gallium/drivers/etnaviv/etnaviv_resource.c
+@@ -275,6 +275,18 @@ etna_resource_create(struct pipe_screen *pscreen,
+ }
+
+ static void
++etna_resource_changed(struct pipe_screen *pscreen, struct pipe_resource *prsc)
++{
++ struct etna_resource *res = etna_resource(prsc);
++
++ /* Make sure texture is older than the imported renderable buffer,
++ * so etna_update_sampler_source will copy the pixel data again.
++ */
++ if (res->texture)
++ etna_resource(res->texture)->seqno = res->seqno - 1;
++}
++
++static void
+ etna_resource_destroy(struct pipe_screen *pscreen, struct pipe_resource *prsc)
+ {
+ struct etna_resource *rsc = etna_resource(prsc);
+@@ -436,5 +448,6 @@ etna_resource_screen_init(struct pipe_screen *pscreen)
+ pscreen->resource_create = etna_resource_create;
+ pscreen->resource_from_handle = etna_resource_from_handle;
+ pscreen->resource_get_handle = etna_resource_get_handle;
++ pscreen->resource_changed = etna_resource_changed;
+ pscreen->resource_destroy = etna_resource_destroy;
+ }
+--
+2.7.4
+
--- /dev/null
+From c276e110f520c8f9e1795b4a85dec3f28ef38d89 Mon Sep 17 00:00:00 2001
+From: Philipp Zabel <p.zabel@pengutronix.de>
+Date: Mon, 11 Apr 2016 18:50:58 +0200
+Subject: [PATCH] WIP: st/dri: Allow YUYV import
+
+Unclear whether this is the right way, but this allows to import
+dma-buffers with YUYV pixel format.
+
+Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
+---
+ src/gallium/state_trackers/dri/dri2.c | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+diff --git a/src/gallium/state_trackers/dri/dri2.c b/src/gallium/state_trackers/dri/dri2.c
+index b50e096443..9c61f01547 100644
+--- a/src/gallium/state_trackers/dri/dri2.c
++++ b/src/gallium/state_trackers/dri/dri2.c
+@@ -84,6 +84,10 @@ static int convert_fourcc(int format, int *dri_components_p)
+ format = __DRI_IMAGE_FORMAT_GR88;
+ dri_components = __DRI_IMAGE_COMPONENTS_RG;
+ break;
++ case __DRI_IMAGE_FOURCC_YUYV:
++ format = __DRI_IMAGE_FOURCC_YUYV;
++ dri_components = __DRI_IMAGE_COMPONENTS_Y_XUXV; /* FIXME */
++ break;
+ /*
+ * For multi-planar YUV formats, we return the format of the first
+ * plane only. Since there is only one caller which supports multi-
+@@ -164,6 +168,9 @@ static enum pipe_format dri2_format_to_pipe_format (int format)
+ case __DRI_IMAGE_FORMAT_GR88:
+ pf = PIPE_FORMAT_RG88_UNORM;
+ break;
++ case __DRI_IMAGE_FOURCC_YUYV:
++ pf = PIPE_FORMAT_YUYV;
++ break;
+ default:
+ pf = PIPE_FORMAT_NONE;
+ break;
+--
+2.11.0
+
--- /dev/null
+From 2db3af601fec44243b1b50d931c22bc06fd5cb25 Mon Sep 17 00:00:00 2001
+From: Philipp Zabel <p.zabel@pengutronix.de>
+Date: Wed, 1 Mar 2017 13:45:03 +0100
+Subject: [PATCH] etnaviv: increment the resource seqno in resource_changed
+
+Just increment the resource seqno instead of setting the texture
+seqno to be lower by one than the resource seqno.
+
+Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
+---
+ src/gallium/drivers/etnaviv/etnaviv_resource.c | 6 +-----
+ 1 file changed, 1 insertion(+), 5 deletions(-)
+
+diff --git a/src/gallium/drivers/etnaviv/etnaviv_resource.c b/src/gallium/drivers/etnaviv/etnaviv_resource.c
+index f76c3ba4d1..aeb123a492 100644
+--- a/src/gallium/drivers/etnaviv/etnaviv_resource.c
++++ b/src/gallium/drivers/etnaviv/etnaviv_resource.c
+@@ -282,11 +282,7 @@ etna_resource_changed(struct pipe_screen *pscreen, struct pipe_resource *prsc)
+ {
+ struct etna_resource *res = etna_resource(prsc);
+
+- /* Make sure texture is older than the imported renderable buffer,
+- * so etna_update_sampler_source will copy the pixel data again.
+- */
+- if (res->texture)
+- etna_resource(res->texture)->seqno = res->seqno - 1;
++ res->seqno++;
+ }
+
+ static void
+--
+2.11.0
+
+FILESEXTRAPATHS_prepend := "${THISDIR}/mesa:"
+
PACKAGECONFIG_remove_imxgpu2d = "egl gles"
PROVIDES_remove_imxgpu2d = "virtual/libgles1 virtual/libgles2 virtual/libopenvg virtual/egl"
PROVIDES_remove_imxgpu3d = "virtual/libgl"
+SRC_URI_append = "file://0001-etnaviv-wire-up-core-pipe_debug_callback.patch \
+ file://0002-etnaviv-shader-db-traces.patch \
+ file://0003-etnaviv-keep-track-of-emitted-loops.patch \
+ file://0004-etnaviv-remove-not-needed-forward-declarations.patch \
+ file://0005-etnaviv-s-etna_shader-etna_shader_variant.patch \
+ file://0006-etnaviv-add-basic-shader-variant-support.patch \
+ file://0007-etnaviv-add-struct-etna_shader_state.patch \
+ file://0008-etnaviv-make-specs-const.patch \
+ file://0009-etnaviv-pass-a-preallocated-variant-to-compiler.patch \
+ file://0010-etnaviv-add-etna_shader_key-and-generate-variants-if.patch \
+ file://0011-etnaviv-bring-back-shader-db-traces.patch \
+ file://0012-etnaviv-adopt-shader-db-output-for-variant-support.patch \
+ file://0013-etnaviv-add-support-for-rb-swap.patch \
+ file://0014-Revert-etnaviv-Cannot-render-to-rb-swapped-formats.patch \
+ file://0015-Enable-MESA_ycbcr_texture-for-GLES1-and-GLES2.patch \
+ file://0016-gallium-add-pipe_screen-resource_changed.patch \
+ file://0017-st-dri-ask-the-driver-to-update-its-internal-copies-.patch \
+ file://0018-etnaviv-initialize-seqno-of-imported-resources.patch \
+ file://0019-etnaviv-implement-resource_changed-to-invalidate-int.patch \
+ file://WIP-st-dri-Allow-YUYV-import.patch \
+"
+
+
# FIXME: mesa should support 'x11-no-tls' option
python () {
overrides = d.getVar("OVERRIDES", True).split(":")