[PATCH v2 2/3] etnaviv: gallium driver for Vivante GPUs

Christian Gmeiner christian.gmeiner at gmail.com
Fri Dec 23 22:04:50 UTC 2016


From: The etnaviv authors <etnaviv at lists.freedesktop.org>

This driver supports a wide range of Vivante IP cores like GC880,
GC1000, GC2000 and GC3000.

Changes from V1 -> V2:
 - added missing files to actually integrate the driver into build system.
 - adapted driver to new renderonly API

Signed-off-by: Christian Gmeiner <christian.gmeiner at gmail.com>
Signed-off-by: Lucas Stach <l.stach at pengutronix.de>
Signed-off-by: Philipp Zabel <p.zabel at pengutronix.de>
Signed-off-by: Rob Herring <robh at kernel.org>
Signed-off-by: Russell King <rmk at arm.linux.org.uk>
Signed-off-by: Wladimir J. van der Laan <laanwj at gmail.com>
---
 configure.ac                                       |    9 +
 src/gallium/Makefile.am                            |    4 +
 .../auxiliary/pipe-loader/pipe_loader_drm.c        |    5 +
 src/gallium/auxiliary/target-helpers/drm_helper.h  |   22 +
 .../auxiliary/target-helpers/drm_helper_public.h   |    3 +
 src/gallium/drivers/etnaviv/.gitignore             |    1 +
 src/gallium/drivers/etnaviv/Automake.inc           |   11 +
 src/gallium/drivers/etnaviv/Makefile.am            |   44 +
 src/gallium/drivers/etnaviv/Makefile.sources       |   26 +
 src/gallium/drivers/etnaviv/etnaviv_asm.c          |  107 +
 src/gallium/drivers/etnaviv/etnaviv_asm.h          |  133 +
 src/gallium/drivers/etnaviv/etnaviv_blend.c        |  109 +
 src/gallium/drivers/etnaviv/etnaviv_blend.h        |   52 +
 src/gallium/drivers/etnaviv/etnaviv_clear_blit.c   |  640 +++++
 src/gallium/drivers/etnaviv/etnaviv_clear_blit.h   |   48 +
 src/gallium/drivers/etnaviv/etnaviv_compiler.c     | 2564 ++++++++++++++++++++
 src/gallium/drivers/etnaviv/etnaviv_compiler.h     |  120 +
 .../drivers/etnaviv/etnaviv_compiler_cmdline.c     |  146 ++
 src/gallium/drivers/etnaviv/etnaviv_context.c      |  323 +++
 src/gallium/drivers/etnaviv/etnaviv_context.h      |  194 ++
 src/gallium/drivers/etnaviv/etnaviv_debug.h        |   79 +
 src/gallium/drivers/etnaviv/etnaviv_disasm.c       |  612 +++++
 src/gallium/drivers/etnaviv/etnaviv_disasm.h       |   40 +
 src/gallium/drivers/etnaviv/etnaviv_emit.c         |  770 ++++++
 src/gallium/drivers/etnaviv/etnaviv_emit.h         |  123 +
 src/gallium/drivers/etnaviv/etnaviv_fence.c        |   87 +
 src/gallium/drivers/etnaviv/etnaviv_fence.h        |   39 +
 src/gallium/drivers/etnaviv/etnaviv_format.c       |  268 ++
 src/gallium/drivers/etnaviv/etnaviv_format.h       |   47 +
 src/gallium/drivers/etnaviv/etnaviv_internal.h     |  259 ++
 src/gallium/drivers/etnaviv/etnaviv_query.c        |  120 +
 src/gallium/drivers/etnaviv/etnaviv_query.h        |   64 +
 src/gallium/drivers/etnaviv/etnaviv_query_sw.c     |  123 +
 src/gallium/drivers/etnaviv/etnaviv_query_sw.h     |   47 +
 src/gallium/drivers/etnaviv/etnaviv_rasterizer.c   |   81 +
 src/gallium/drivers/etnaviv/etnaviv_rasterizer.h   |   57 +
 src/gallium/drivers/etnaviv/etnaviv_resource.c     |  438 ++++
 src/gallium/drivers/etnaviv/etnaviv_resource.h     |  148 ++
 src/gallium/drivers/etnaviv/etnaviv_rs.c           |  127 +
 src/gallium/drivers/etnaviv/etnaviv_rs.h           |   86 +
 src/gallium/drivers/etnaviv/etnaviv_screen.c       |  812 +++++++
 src/gallium/drivers/etnaviv/etnaviv_screen.h       |   95 +
 src/gallium/drivers/etnaviv/etnaviv_shader.c       |  285 +++
 src/gallium/drivers/etnaviv/etnaviv_shader.h       |   45 +
 src/gallium/drivers/etnaviv/etnaviv_state.c        |  664 +++++
 src/gallium/drivers/etnaviv/etnaviv_state.h        |   52 +
 src/gallium/drivers/etnaviv/etnaviv_surface.c      |  152 ++
 src/gallium/drivers/etnaviv/etnaviv_surface.h      |   55 +
 src/gallium/drivers/etnaviv/etnaviv_texture.c      |  338 +++
 src/gallium/drivers/etnaviv/etnaviv_texture.h      |   75 +
 src/gallium/drivers/etnaviv/etnaviv_tiling.c       |   96 +
 src/gallium/drivers/etnaviv/etnaviv_tiling.h       |   56 +
 src/gallium/drivers/etnaviv/etnaviv_transfer.c     |  355 +++
 src/gallium/drivers/etnaviv/etnaviv_transfer.h     |   35 +
 src/gallium/drivers/etnaviv/etnaviv_translate.h    |  516 ++++
 src/gallium/drivers/etnaviv/etnaviv_uniforms.c     |  118 +
 src/gallium/drivers/etnaviv/etnaviv_uniforms.h     |   45 +
 src/gallium/drivers/etnaviv/etnaviv_util.h         |  108 +
 src/gallium/drivers/etnaviv/etnaviv_zsa.c          |  123 +
 src/gallium/drivers/etnaviv/etnaviv_zsa.h          |   52 +
 src/gallium/drivers/etnaviv/hw/cmdstream.xml.h     |  270 +++
 src/gallium/drivers/etnaviv/hw/common.xml.h        |  320 +++
 src/gallium/drivers/etnaviv/hw/isa.xml.h           |  239 ++
 src/gallium/drivers/etnaviv/hw/state.xml.h         |  397 +++
 src/gallium/drivers/etnaviv/hw/state_3d.xml.h      | 1231 ++++++++++
 src/gallium/targets/dri/Makefile.am                |    2 +
 src/gallium/targets/dri/target.c                   |   11 +
 src/gallium/winsys/etnaviv/drm/Makefile.am         |   32 +
 .../winsys/etnaviv/drm/etnaviv_drm_public.h        |   39 +
 .../winsys/etnaviv/drm/etnaviv_drm_winsys.c        |  161 ++
 70 files changed, 14955 insertions(+)
 create mode 100644 src/gallium/drivers/etnaviv/.gitignore
 create mode 100644 src/gallium/drivers/etnaviv/Automake.inc
 create mode 100644 src/gallium/drivers/etnaviv/Makefile.am
 create mode 100644 src/gallium/drivers/etnaviv/Makefile.sources
 create mode 100644 src/gallium/drivers/etnaviv/etnaviv_asm.c
 create mode 100644 src/gallium/drivers/etnaviv/etnaviv_asm.h
 create mode 100644 src/gallium/drivers/etnaviv/etnaviv_blend.c
 create mode 100644 src/gallium/drivers/etnaviv/etnaviv_blend.h
 create mode 100644 src/gallium/drivers/etnaviv/etnaviv_clear_blit.c
 create mode 100644 src/gallium/drivers/etnaviv/etnaviv_clear_blit.h
 create mode 100644 src/gallium/drivers/etnaviv/etnaviv_compiler.c
 create mode 100644 src/gallium/drivers/etnaviv/etnaviv_compiler.h
 create mode 100644 src/gallium/drivers/etnaviv/etnaviv_compiler_cmdline.c
 create mode 100644 src/gallium/drivers/etnaviv/etnaviv_context.c
 create mode 100644 src/gallium/drivers/etnaviv/etnaviv_context.h
 create mode 100644 src/gallium/drivers/etnaviv/etnaviv_debug.h
 create mode 100644 src/gallium/drivers/etnaviv/etnaviv_disasm.c
 create mode 100644 src/gallium/drivers/etnaviv/etnaviv_disasm.h
 create mode 100644 src/gallium/drivers/etnaviv/etnaviv_emit.c
 create mode 100644 src/gallium/drivers/etnaviv/etnaviv_emit.h
 create mode 100644 src/gallium/drivers/etnaviv/etnaviv_fence.c
 create mode 100644 src/gallium/drivers/etnaviv/etnaviv_fence.h
 create mode 100644 src/gallium/drivers/etnaviv/etnaviv_format.c
 create mode 100644 src/gallium/drivers/etnaviv/etnaviv_format.h
 create mode 100644 src/gallium/drivers/etnaviv/etnaviv_internal.h
 create mode 100644 src/gallium/drivers/etnaviv/etnaviv_query.c
 create mode 100644 src/gallium/drivers/etnaviv/etnaviv_query.h
 create mode 100644 src/gallium/drivers/etnaviv/etnaviv_query_sw.c
 create mode 100644 src/gallium/drivers/etnaviv/etnaviv_query_sw.h
 create mode 100644 src/gallium/drivers/etnaviv/etnaviv_rasterizer.c
 create mode 100644 src/gallium/drivers/etnaviv/etnaviv_rasterizer.h
 create mode 100644 src/gallium/drivers/etnaviv/etnaviv_resource.c
 create mode 100644 src/gallium/drivers/etnaviv/etnaviv_resource.h
 create mode 100644 src/gallium/drivers/etnaviv/etnaviv_rs.c
 create mode 100644 src/gallium/drivers/etnaviv/etnaviv_rs.h
 create mode 100644 src/gallium/drivers/etnaviv/etnaviv_screen.c
 create mode 100644 src/gallium/drivers/etnaviv/etnaviv_screen.h
 create mode 100644 src/gallium/drivers/etnaviv/etnaviv_shader.c
 create mode 100644 src/gallium/drivers/etnaviv/etnaviv_shader.h
 create mode 100644 src/gallium/drivers/etnaviv/etnaviv_state.c
 create mode 100644 src/gallium/drivers/etnaviv/etnaviv_state.h
 create mode 100644 src/gallium/drivers/etnaviv/etnaviv_surface.c
 create mode 100644 src/gallium/drivers/etnaviv/etnaviv_surface.h
 create mode 100644 src/gallium/drivers/etnaviv/etnaviv_texture.c
 create mode 100644 src/gallium/drivers/etnaviv/etnaviv_texture.h
 create mode 100644 src/gallium/drivers/etnaviv/etnaviv_tiling.c
 create mode 100644 src/gallium/drivers/etnaviv/etnaviv_tiling.h
 create mode 100644 src/gallium/drivers/etnaviv/etnaviv_transfer.c
 create mode 100644 src/gallium/drivers/etnaviv/etnaviv_transfer.h
 create mode 100644 src/gallium/drivers/etnaviv/etnaviv_translate.h
 create mode 100644 src/gallium/drivers/etnaviv/etnaviv_uniforms.c
 create mode 100644 src/gallium/drivers/etnaviv/etnaviv_uniforms.h
 create mode 100644 src/gallium/drivers/etnaviv/etnaviv_util.h
 create mode 100644 src/gallium/drivers/etnaviv/etnaviv_zsa.c
 create mode 100644 src/gallium/drivers/etnaviv/etnaviv_zsa.h
 create mode 100644 src/gallium/drivers/etnaviv/hw/cmdstream.xml.h
 create mode 100644 src/gallium/drivers/etnaviv/hw/common.xml.h
 create mode 100644 src/gallium/drivers/etnaviv/hw/isa.xml.h
 create mode 100644 src/gallium/drivers/etnaviv/hw/state.xml.h
 create mode 100644 src/gallium/drivers/etnaviv/hw/state_3d.xml.h
 create mode 100644 src/gallium/winsys/etnaviv/drm/Makefile.am
 create mode 100644 src/gallium/winsys/etnaviv/drm/etnaviv_drm_public.h
 create mode 100644 src/gallium/winsys/etnaviv/drm/etnaviv_drm_winsys.c

diff --git a/configure.ac b/configure.ac
index 799f5eb..0b98ce8 100644
--- a/configure.ac
+++ b/configure.ac
@@ -76,6 +76,7 @@ LIBDRM_NVVIEUX_REQUIRED=2.4.66
 LIBDRM_NOUVEAU_REQUIRED=2.4.66
 LIBDRM_FREEDRENO_REQUIRED=2.4.74
 LIBDRM_VC4_REQUIRED=2.4.69
+LIBDRM_ETNAVIV_REQUIRED=2.4.74
 DRI2PROTO_REQUIRED=2.6
 DRI3PROTO_REQUIRED=1.0
 PRESENTPROTO_REQUIRED=1.0
@@ -2506,6 +2507,11 @@ if test -n "$with_gallium_drivers"; then
             PKG_CHECK_MODULES([FREEDRENO], [libdrm_freedreno >= $LIBDRM_FREEDRENO_REQUIRED])
             require_libdrm "freedreno"
             ;;
+        xetnaviv)
+            HAVE_GALLIUM_ETNAVIV=yes
+            PKG_CHECK_MODULES([ETNAVIV], [libdrm_etnaviv >= $LIBDRM_ETNAVIV_REQUIRED])
+            require_libdrm "etnaviv"
+            ;;
         xswrast)
             HAVE_GALLIUM_SOFTPIPE=yes
             if test "x$MESA_LLVM" = x1 && test "x$enable_gallium_llvm" == "xyes";  then
@@ -2624,6 +2630,7 @@ AM_CONDITIONAL(HAVE_GALLIUM_RADEON_COMMON, test "x$HAVE_GALLIUM_R600" = xyes -o
                                                 "x$HAVE_GALLIUM_RADEONSI" = xyes)
 AM_CONDITIONAL(HAVE_GALLIUM_NOUVEAU, test "x$HAVE_GALLIUM_NOUVEAU" = xyes)
 AM_CONDITIONAL(HAVE_GALLIUM_FREEDRENO, test "x$HAVE_GALLIUM_FREEDRENO" = xyes)
+AM_CONDITIONAL(HAVE_GALLIUM_ETNAVIV, test "x$HAVE_GALLIUM_ETNAVIV" = xyes)
 AM_CONDITIONAL(HAVE_GALLIUM_SOFTPIPE, test "x$HAVE_GALLIUM_SOFTPIPE" = xyes)
 AM_CONDITIONAL(HAVE_GALLIUM_LLVMPIPE, test "x$HAVE_GALLIUM_LLVMPIPE" = xyes)
 AM_CONDITIONAL(HAVE_GALLIUM_SWR, test "x$HAVE_GALLIUM_SWR" = xyes)
@@ -2777,6 +2784,7 @@ AC_CONFIG_FILES([Makefile
 		src/gallium/drivers/svga/Makefile
 		src/gallium/drivers/swr/Makefile
 		src/gallium/drivers/trace/Makefile
+		src/gallium/drivers/etnaviv/Makefile
 		src/gallium/drivers/vc4/Makefile
 		src/gallium/drivers/virgl/Makefile
 		src/gallium/state_trackers/clover/Makefile
@@ -2806,6 +2814,7 @@ AC_CONFIG_FILES([Makefile
 		src/gallium/targets/xvmc/Makefile
 		src/gallium/tests/trivial/Makefile
 		src/gallium/tests/unit/Makefile
+		src/gallium/winsys/etnaviv/drm/Makefile
 		src/gallium/winsys/freedreno/drm/Makefile
 		src/gallium/winsys/i915/drm/Makefile
 		src/gallium/winsys/intel/drm/Makefile
diff --git a/src/gallium/Makefile.am b/src/gallium/Makefile.am
index 34671ca..9e47e9f 100644
--- a/src/gallium/Makefile.am
+++ b/src/gallium/Makefile.am
@@ -68,6 +68,10 @@ if NEED_RADEON_DRM_WINSYS
 SUBDIRS += winsys/radeon/drm
 endif
 
+if HAVE_GALLIUM_ETNAVIV
+SUBDIRS += drivers/etnaviv winsys/etnaviv/drm
+endif
+
 ## swrast/softpipe
 if HAVE_GALLIUM_SOFTPIPE
 SUBDIRS += drivers/softpipe
diff --git a/src/gallium/auxiliary/pipe-loader/pipe_loader_drm.c b/src/gallium/auxiliary/pipe-loader/pipe_loader_drm.c
index 2b7ab27..99d9da6 100644
--- a/src/gallium/auxiliary/pipe-loader/pipe_loader_drm.c
+++ b/src/gallium/auxiliary/pipe-loader/pipe_loader_drm.c
@@ -154,6 +154,11 @@ static const struct drm_driver_descriptor driver_descriptors[] = {
         .create_screen = pipe_vc4_create_screen,
         .configuration = configuration_query,
     },
+    {
+        .driver_name = "etnaviv",
+        .create_screen = pipe_etna_create_screen,
+        .configuration = configuration_query,
+    }
 };
 #endif
 
diff --git a/src/gallium/auxiliary/target-helpers/drm_helper.h b/src/gallium/auxiliary/target-helpers/drm_helper.h
index 90820d3..e056c58 100644
--- a/src/gallium/auxiliary/target-helpers/drm_helper.h
+++ b/src/gallium/auxiliary/target-helpers/drm_helper.h
@@ -266,5 +266,27 @@ pipe_vc4_create_screen(int fd)
 
 #endif
 
+#ifdef GALLIUM_ETNAVIV
+#include "etnaviv/drm/etnaviv_drm_public.h"
+
+struct pipe_screen *
+pipe_etna_create_screen(int fd)
+{
+   struct pipe_screen *screen;
+
+   screen = etna_drm_screen_create(fd);
+   return screen ? debug_screen_wrap(screen) : NULL;
+}
+
+#else
+
+struct pipe_screen *
+pipe_etna_create_screen(int fd)
+{
+   fprintf(stderr, "etnaviv: driver missing\n");
+   return NULL;
+}
+
+#endif
 
 #endif /* DRM_HELPER_H */
diff --git a/src/gallium/auxiliary/target-helpers/drm_helper_public.h b/src/gallium/auxiliary/target-helpers/drm_helper_public.h
index d1f9382..73cf1da 100644
--- a/src/gallium/auxiliary/target-helpers/drm_helper_public.h
+++ b/src/gallium/auxiliary/target-helpers/drm_helper_public.h
@@ -34,4 +34,7 @@ pipe_virgl_create_screen(int fd);
 struct pipe_screen *
 pipe_vc4_create_screen(int fd);
 
+struct pipe_screen *
+pipe_etna_create_screen(int fd);
+
 #endif /* _DRM_HELPER_PUBLIC_H */
diff --git a/src/gallium/drivers/etnaviv/.gitignore b/src/gallium/drivers/etnaviv/.gitignore
new file mode 100644
index 0000000..5199dad
--- /dev/null
+++ b/src/gallium/drivers/etnaviv/.gitignore
@@ -0,0 +1 @@
+etnaviv_compiler
diff --git a/src/gallium/drivers/etnaviv/Automake.inc b/src/gallium/drivers/etnaviv/Automake.inc
new file mode 100644
index 0000000..f9b39567
--- /dev/null
+++ b/src/gallium/drivers/etnaviv/Automake.inc
@@ -0,0 +1,11 @@
+if HAVE_GALLIUM_ETNAVIV
+
+TARGET_DRIVERS += etnaviv
+TARGET_CPPFLAGS += -DGALLIUM_ETNAVIV
+TARGET_LIB_DEPS += \
+	$(top_builddir)/src/gallium/winsys/etnaviv/drm/libetnavivdrm.la \
+	$(top_builddir)/src/gallium/drivers/etnaviv/libetnaviv.la \
+	$(ETNAVIV_LIBS) \
+	$(LIBDRM_LIBS)
+
+endif
diff --git a/src/gallium/drivers/etnaviv/Makefile.am b/src/gallium/drivers/etnaviv/Makefile.am
new file mode 100644
index 0000000..47c9115
--- /dev/null
+++ b/src/gallium/drivers/etnaviv/Makefile.am
@@ -0,0 +1,44 @@
+# Copyright © 2013 W.J. van der Laan
+#
+# Permission is hereby granted, free of charge, to any person obtaining a
+# copy of this software and associated documentation files (the "Software"),
+# to deal in the Software without restriction, including without limitation
+# the rights to use, copy, modify, merge, publish, distribute, sublicense,
+# and/or sell copies of the Software, and to permit persons to whom the
+# Software is furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice (including the next
+# paragraph) shall be included in all copies or substantial portions of the
+# Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+# DEALINGS IN THE SOFTWARE.
+
+include Makefile.sources
+include $(top_srcdir)/src/gallium/Automake.inc
+
+noinst_LTLIBRARIES = libetnaviv.la
+
+AM_CPPFLAGS = \
+	$(GALLIUM_DRIVER_CFLAGS) \
+	$(ETNAVIV_CFLAGS)
+
+libetnaviv_la_SOURCES = $(C_SOURCES) $(CPP_SOURCES)
+
+noinst_PROGRAMS = etnaviv_compiler
+
+etnaviv_compiler_SOURCES = \
+	etnaviv_compiler_cmdline.c
+
+etnaviv_compiler_LDADD = \
+	libetnaviv.la \
+	../../auxiliary/libgallium.la \
+	$(top_builddir)/src/util/libmesautil.la \
+	$(GALLIUM_COMMON_LIB_DEPS) \
+	$(ETNAVIV_LIBS)
diff --git a/src/gallium/drivers/etnaviv/Makefile.sources b/src/gallium/drivers/etnaviv/Makefile.sources
new file mode 100644
index 0000000..e6d8b9f
--- /dev/null
+++ b/src/gallium/drivers/etnaviv/Makefile.sources
@@ -0,0 +1,26 @@
+C_SOURCES :=  \
+	etnaviv_asm.c \
+	etnaviv_blend.c \
+	etnaviv_clear_blit.c \
+	etnaviv_compiler.c \
+	etnaviv_context.c \
+	etnaviv_disasm.c \
+	etnaviv_emit.c \
+	etnaviv_fence.c \
+	etnaviv_format.c \
+	etnaviv_query.c \
+	etnaviv_query_sw.c \
+	etnaviv_rasterizer.c \
+	etnaviv_resource.c \
+	etnaviv_rs.c \
+	etnaviv_screen.c \
+	etnaviv_shader.c \
+	etnaviv_state.c \
+	etnaviv_surface.c \
+	etnaviv_tiling.c \
+	etnaviv_texture.c \
+	etnaviv_transfer.c \
+	etnaviv_uniforms.c \
+	etnaviv_zsa.c
+
+CPP_SOURCES :=
diff --git a/src/gallium/drivers/etnaviv/etnaviv_asm.c b/src/gallium/drivers/etnaviv/etnaviv_asm.c
new file mode 100644
index 0000000..7d6270c
--- /dev/null
+++ b/src/gallium/drivers/etnaviv/etnaviv_asm.c
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2012-2015 Etnaviv Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Wladimir J. van der Laan <laanwj at gmail.com>
+ */
+
+#include "etnaviv_asm.h"
+#include "etnaviv_debug.h"
+#include "etnaviv_util.h"
+
+/* An instruction can only read from one distinct uniform.
+ * This function verifies this property and returns true if the instruction
+ * is deemed correct and false otherwise.
+ */
+static bool
+check_uniforms(const struct etna_inst *inst)
+{
+   unsigned uni_rgroup = -1;
+   unsigned uni_reg = -1;
+   bool conflict = false;
+
+   for (unsigned i = 0; i < ETNA_NUM_SRC; i++) {
+      const struct etna_inst_src *src = &inst->src[i];
+
+      if (!etna_rgroup_is_uniform(src->rgroup))
+         continue;
+
+      if (uni_reg == -1) { /* first uniform used */
+         uni_rgroup = src->rgroup;
+         uni_reg = src->reg;
+      } else { /* second or later; check that it is a re-use */
+         if (uni_rgroup != src->rgroup || uni_reg != src->reg) {
+            conflict = true;
+         }
+      }
+   }
+
+   return !conflict;
+}
+
+int
+etna_assemble(uint32_t *out, const struct etna_inst *inst)
+{
+   /* cannot have both src2 and imm */
+   if (inst->imm && inst->src[2].use)
+      return 1;
+
+   if (!check_uniforms(inst))
+      BUG("error: generating instruction that accesses two different uniforms");
+
+   out[0] = VIV_ISA_WORD_0_OPCODE(inst->opcode) |
+            VIV_ISA_WORD_0_COND(inst->cond) |
+            COND(inst->sat, VIV_ISA_WORD_0_SAT) |
+            COND(inst->dst.use, VIV_ISA_WORD_0_DST_USE) |
+            VIV_ISA_WORD_0_DST_AMODE(inst->dst.amode) |
+            VIV_ISA_WORD_0_DST_REG(inst->dst.reg) |
+            VIV_ISA_WORD_0_DST_COMPS(inst->dst.comps) |
+            VIV_ISA_WORD_0_TEX_ID(inst->tex.id);
+   out[1] = VIV_ISA_WORD_1_TEX_AMODE(inst->tex.amode) |
+            VIV_ISA_WORD_1_TEX_SWIZ(inst->tex.swiz) |
+            COND(inst->src[0].use, VIV_ISA_WORD_1_SRC0_USE) |
+            VIV_ISA_WORD_1_SRC0_REG(inst->src[0].reg) |
+            COND(inst->type & 0x4, VIV_ISA_WORD_1_TYPE_BIT2) |
+            VIV_ISA_WORD_1_SRC0_SWIZ(inst->src[0].swiz) |
+            COND(inst->src[0].neg, VIV_ISA_WORD_1_SRC0_NEG) |
+            COND(inst->src[0].abs, VIV_ISA_WORD_1_SRC0_ABS);
+   out[2] = VIV_ISA_WORD_2_SRC0_AMODE(inst->src[0].amode) |
+            VIV_ISA_WORD_2_SRC0_RGROUP(inst->src[0].rgroup) |
+            COND(inst->src[1].use, VIV_ISA_WORD_2_SRC1_USE) |
+            VIV_ISA_WORD_2_SRC1_REG(inst->src[1].reg) |
+            VIV_ISA_WORD_2_SRC1_SWIZ(inst->src[1].swiz) |
+            COND(inst->src[1].neg, VIV_ISA_WORD_2_SRC1_NEG) |
+            COND(inst->src[1].abs, VIV_ISA_WORD_2_SRC1_ABS) |
+            VIV_ISA_WORD_2_SRC1_AMODE(inst->src[1].amode) |
+            VIV_ISA_WORD_2_TYPE_BIT01(inst->type & 0x3);
+   out[3] = VIV_ISA_WORD_3_SRC1_RGROUP(inst->src[1].rgroup) |
+            COND(inst->src[2].use, VIV_ISA_WORD_3_SRC2_USE) |
+            VIV_ISA_WORD_3_SRC2_REG(inst->src[2].reg) |
+            VIV_ISA_WORD_3_SRC2_SWIZ(inst->src[2].swiz) |
+            COND(inst->src[2].neg, VIV_ISA_WORD_3_SRC2_NEG) |
+            COND(inst->src[2].abs, VIV_ISA_WORD_3_SRC2_ABS) |
+            VIV_ISA_WORD_3_SRC2_AMODE(inst->src[2].amode) |
+            VIV_ISA_WORD_3_SRC2_RGROUP(inst->src[2].rgroup);
+   out[3] |= VIV_ISA_WORD_3_SRC2_IMM(inst->imm);
+
+   return 0;
+}
diff --git a/src/gallium/drivers/etnaviv/etnaviv_asm.h b/src/gallium/drivers/etnaviv/etnaviv_asm.h
new file mode 100644
index 0000000..2fe23df
--- /dev/null
+++ b/src/gallium/drivers/etnaviv/etnaviv_asm.h
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2012-2015 Etnaviv Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Wladimir J. van der Laan <laanwj at gmail.com>
+ */
+
+#ifndef H_ETNAVIV_ASM
+#define H_ETNAVIV_ASM
+
+#include <stdint.h>
+#include "hw/isa.xml.h"
+
+/* Size of an instruction in 32-bit words */
+#define ETNA_INST_SIZE (4)
+/* Number of source operands per instruction */
+#define ETNA_NUM_SRC (3)
+
+/* Broadcast swizzle to all four components */
+#define INST_SWIZ_BROADCAST(x) \
+        (INST_SWIZ_X(x) | INST_SWIZ_Y(x) | INST_SWIZ_Z(x) | INST_SWIZ_W(x))
+/* Identity (NOP) swizzle */
+#define INST_SWIZ_IDENTITY \
+        (INST_SWIZ_X(0) | INST_SWIZ_Y(1) | INST_SWIZ_Z(2) | INST_SWIZ_W(3))
+/* Fully specified swizzle */
+#define INST_SWIZ(x,y,z,w) \
+        (INST_SWIZ_X(x) | INST_SWIZ_Y(y) | INST_SWIZ_Z(z) | INST_SWIZ_W(w))
+#define SWIZZLE(c0,c1,c2,c3) \
+        INST_SWIZ(INST_SWIZ_COMP_##c0, \
+                  INST_SWIZ_COMP_##c1, \
+                  INST_SWIZ_COMP_##c2, \
+                  INST_SWIZ_COMP_##c3)
+
+/*** operands ***/
+
+/* destination operand */
+struct etna_inst_dst {
+   unsigned use:1; /* 0: not in use, 1: in use */
+   unsigned amode:3; /* INST_AMODE_* */
+   unsigned reg:7; /* register number 0..127 */
+   unsigned comps:4; /* INST_COMPS_* */
+};
+
+/* texture operand */
+struct etna_inst_tex {
+   unsigned id:5; /* sampler id */
+   unsigned amode:3; /* INST_AMODE_* */
+   unsigned swiz:8; /* INST_SWIZ */
+};
+
+/* source operand */
+struct etna_inst_src {
+   unsigned use:1; /* 0: not in use, 1: in use */
+   unsigned reg:9; /* register or uniform number 0..511 */
+   unsigned swiz:8;   /* INST_SWIZ */
+   unsigned neg:1;    /* negate (flip sign) if set */
+   unsigned abs:1;    /* absolute (remove sign) if set */
+   unsigned amode:3;  /* INST_AMODE_* */
+   unsigned rgroup:3; /* INST_RGROUP_* */
+};
+
+/*** instruction ***/
+struct etna_inst {
+   uint8_t opcode; /* INST_OPCODE_* */
+   uint8_t type; /* INST_TYPE_* */
+   unsigned cond:5; /* INST_CONDITION_* */
+   unsigned sat:1; /* saturate result between 0..1 */
+   struct etna_inst_dst dst; /* destination operand */
+   struct etna_inst_tex tex; /* texture operand */
+   struct etna_inst_src src[ETNA_NUM_SRC]; /* source operand */
+   unsigned imm;  /* takes place of src[2] for BRANCH/CALL */
+};
+
+/* Compose two swizzles (computes swz1.swz2) */
+static inline uint32_t inst_swiz_compose(uint32_t swz1, uint32_t swz2)
+{
+   return INST_SWIZ_X((swz1 >> (((swz2 >> 0)&3)*2))&3) |
+          INST_SWIZ_Y((swz1 >> (((swz2 >> 2)&3)*2))&3) |
+          INST_SWIZ_Z((swz1 >> (((swz2 >> 4)&3)*2))&3) |
+          INST_SWIZ_W((swz1 >> (((swz2 >> 6)&3)*2))&3);
+};
+
+/* Return whether the rgroup is one of the uniforms */
+static inline int
+etna_rgroup_is_uniform(unsigned rgroup)
+{
+   return rgroup == INST_RGROUP_UNIFORM_0 ||
+          rgroup == INST_RGROUP_UNIFORM_1;
+}
+
+/**
+ * Build vivante instruction from structure with
+ *  opcode, cond, sat, dst_use, dst_amode,
+ *  dst_reg, dst_comps, tex_id, tex_amode, tex_swiz,
+ *  src[0-2]_reg, use, swiz, neg, abs, amode, rgroup,
+ *  imm
+ *
+ * Return 0 if successful, and a non-zero
+ * value otherwise.
+ */
+int
+etna_assemble(uint32_t *out, const struct etna_inst *inst);
+
+/**
+ * Set field imm of already-assembled instruction.
+ * This is used for filling in jump destinations in a separate pass.
+ */
+static inline void
+etna_assemble_set_imm(uint32_t *out, uint32_t imm)
+{
+    out[3] |= VIV_ISA_WORD_3_SRC2_IMM(imm);
+}
+
+#endif
diff --git a/src/gallium/drivers/etnaviv/etnaviv_blend.c b/src/gallium/drivers/etnaviv/etnaviv_blend.c
new file mode 100644
index 0000000..ebef75d
--- /dev/null
+++ b/src/gallium/drivers/etnaviv/etnaviv_blend.c
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2012-2015 Etnaviv Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Wladimir J. van der Laan <laanwj at gmail.com>
+ */
+
+#include "etnaviv_blend.h"
+
+#include "etnaviv_context.h"
+#include "etnaviv_translate.h"
+#include "pipe/p_defines.h"
+#include "util/u_memory.h"
+
+void *
+etna_blend_state_create(struct pipe_context *pctx,
+                        const struct pipe_blend_state *so)
+{
+   const struct pipe_rt_blend_state *rt0 = &so->rt[0];
+   struct etna_blend_state *co = CALLOC_STRUCT(etna_blend_state);
+
+   if (!co)
+      return NULL;
+
+   co->base = *so;
+
+   /* Enable blending if
+    * - blend enabled in blend state
+    * - NOT source factor is ONE and destination factor ZERO for both rgb and
+    *   alpha (which would mean that blending is effectively disabled)
+    */
+   bool enable = rt0->blend_enable &&
+                 !(rt0->rgb_src_factor == PIPE_BLENDFACTOR_ONE &&
+                   rt0->rgb_dst_factor == PIPE_BLENDFACTOR_ZERO &&
+                   rt0->alpha_src_factor == PIPE_BLENDFACTOR_ONE &&
+                   rt0->alpha_dst_factor == PIPE_BLENDFACTOR_ZERO);
+
+   /* Enable separate alpha if
+    * - Blending enabled (see above)
+    * - NOT source factor is equal to destination factor for both rgb abd
+    *   alpha (which would effectively that mean alpha is not separate)
+    */
+   bool separate_alpha = enable &&
+                         !(rt0->rgb_src_factor == rt0->alpha_src_factor &&
+                           rt0->rgb_dst_factor == rt0->alpha_dst_factor);
+
+   /* If the complete render target is written, set full_overwrite:
+    * - The color mask is 1111
+    * - No blending is used
+    */
+   bool full_overwrite = (rt0->colormask == 15) && !enable;
+
+   if (enable) {
+      co->PE_ALPHA_CONFIG =
+         VIVS_PE_ALPHA_CONFIG_BLEND_ENABLE_COLOR |
+         COND(separate_alpha, VIVS_PE_ALPHA_CONFIG_BLEND_SEPARATE_ALPHA) |
+         VIVS_PE_ALPHA_CONFIG_SRC_FUNC_COLOR(translate_blend_factor(rt0->rgb_src_factor)) |
+         VIVS_PE_ALPHA_CONFIG_SRC_FUNC_ALPHA(translate_blend_factor(rt0->alpha_src_factor)) |
+         VIVS_PE_ALPHA_CONFIG_DST_FUNC_COLOR(translate_blend_factor(rt0->rgb_dst_factor)) |
+         VIVS_PE_ALPHA_CONFIG_DST_FUNC_ALPHA(translate_blend_factor(rt0->alpha_dst_factor)) |
+         VIVS_PE_ALPHA_CONFIG_EQ_COLOR(translate_blend(rt0->rgb_func)) |
+         VIVS_PE_ALPHA_CONFIG_EQ_ALPHA(translate_blend(rt0->alpha_func));
+   } else {
+      co->PE_ALPHA_CONFIG = 0;
+   }
+
+   co->PE_COLOR_FORMAT =
+         VIVS_PE_COLOR_FORMAT_COMPONENTS(rt0->colormask) |
+         COND(full_overwrite, VIVS_PE_COLOR_FORMAT_OVERWRITE);
+
+   co->PE_LOGIC_OP =
+         VIVS_PE_LOGIC_OP_OP(so->logicop_enable ? so->logicop_func : LOGIC_OP_COPY) |
+         0x000E4000 /* ??? */;
+
+   /* independent_blend_enable not needed: only one rt supported */
+   /* XXX alpha_to_coverage / alpha_to_one? */
+   /* Set dither registers based on dither status. These registers set the
+    * dither pattern,
+    * for now, set the same values as the blob.
+    */
+   if (so->dither) {
+      co->PE_DITHER[0] = 0x6e4ca280;
+      co->PE_DITHER[1] = 0x5d7f91b3;
+   } else {
+      co->PE_DITHER[0] = 0xffffffff;
+      co->PE_DITHER[1] = 0xffffffff;
+   }
+
+   return co;
+}
diff --git a/src/gallium/drivers/etnaviv/etnaviv_blend.h b/src/gallium/drivers/etnaviv/etnaviv_blend.h
new file mode 100644
index 0000000..54e7bab
--- /dev/null
+++ b/src/gallium/drivers/etnaviv/etnaviv_blend.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2012-2015 Etnaviv Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Wladimir J. van der Laan <laanwj at gmail.com>
+ */
+
+#ifndef H_ETNAVIV_BLEND
+#define H_ETNAVIV_BLEND
+
+#include "pipe/p_context.h"
+#include "pipe/p_state.h"
+
+struct etna_blend_state {
+   struct pipe_blend_state base;
+
+   uint32_t PE_ALPHA_CONFIG;
+   uint32_t PE_COLOR_FORMAT;
+   uint32_t PE_LOGIC_OP;
+   uint32_t PE_DITHER[2];
+};
+
+static inline struct etna_blend_state *
+etna_blend_state(struct pipe_blend_state *blend)
+{
+   return (struct etna_blend_state *)blend;
+}
+
+void *
+etna_blend_state_create(struct pipe_context *pctx,
+                        const struct pipe_blend_state *so);
+
+#endif
diff --git a/src/gallium/drivers/etnaviv/etnaviv_clear_blit.c b/src/gallium/drivers/etnaviv/etnaviv_clear_blit.c
new file mode 100644
index 0000000..6c61ad5
--- /dev/null
+++ b/src/gallium/drivers/etnaviv/etnaviv_clear_blit.c
@@ -0,0 +1,640 @@
+/*
+ * Copyright (c) 2012-2015 Etnaviv Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Wladimir J. van der Laan <laanwj at gmail.com>
+ */
+
+#include "etnaviv_clear_blit.h"
+
+#include "hw/common.xml.h"
+
+#include "etnaviv_context.h"
+#include "etnaviv_emit.h"
+#include "etnaviv_emit.h"
+#include "etnaviv_format.h"
+#include "etnaviv_resource.h"
+#include "etnaviv_surface.h"
+#include "etnaviv_translate.h"
+
+#include "pipe/p_defines.h"
+#include "pipe/p_state.h"
+#include "util/u_blitter.h"
+#include "util/u_inlines.h"
+#include "util/u_memory.h"
+#include "util/u_surface.h"
+
+/* Save current state for blitter operation */
+static void
+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_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_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);
+   util_blitter_save_sample_mask(ctx->blitter, ctx->sample_mask);
+   util_blitter_save_framebuffer(ctx->blitter, &ctx->framebuffer_s);
+   util_blitter_save_fragment_sampler_states(ctx->blitter,
+         ctx->num_fragment_samplers, (void **)ctx->sampler);
+   util_blitter_save_fragment_sampler_views(ctx->blitter,
+         ctx->num_fragment_sampler_views, ctx->sampler_view);
+}
+
+/* Generate clear command for a surface (non-fast clear case) */
+void
+etna_rs_gen_clear_surface(struct etna_context *ctx, struct etna_surface *surf,
+                          uint32_t clear_value)
+{
+   struct etna_resource *dst = etna_resource(surf->base.texture);
+   uint32_t format = translate_rs_format(surf->base.format);
+
+   if (format == ETNA_NO_MATCH) {
+      BUG("etna_rs_gen_clear_surface: Unhandled clear fmt %s", util_format_name(surf->base.format));
+      format = RS_FORMAT_A8R8G8B8;
+      assert(0);
+   }
+
+   /* use tiled clear if width is multiple of 16 */
+   bool tiled_clear = (surf->surf.padded_width & ETNA_RS_WIDTH_MASK) == 0 &&
+                      (surf->surf.padded_height & ETNA_RS_HEIGHT_MASK) == 0;
+
+   etna_compile_rs_state( ctx, &surf->clear_command, &(struct rs_state) {
+      .source_format = format,
+      .dest_format = format,
+      .dest = dst->bo,
+      .dest_offset = surf->surf.offset,
+      .dest_stride = surf->surf.stride,
+      .dest_padded_height = surf->surf.padded_height,
+      .dest_tiling = tiled_clear ? dst->layout : ETNA_LAYOUT_LINEAR,
+      .dither = {0xffffffff, 0xffffffff},
+      .width = surf->surf.padded_width, /* These must be padded to 16x4 if !LINEAR, otherwise RS will hang */
+      .height = surf->surf.padded_height,
+      .clear_value = {clear_value},
+      .clear_mode = VIVS_RS_CLEAR_CONTROL_MODE_ENABLED1,
+      .clear_bits = 0xffff
+   });
+}
+
+static void
+etna_blit_clear_color(struct pipe_context *pctx, struct pipe_surface *dst,
+                      const union pipe_color_union *color)
+{
+   struct etna_context *ctx = etna_context(pctx);
+   struct etna_surface *surf = etna_surface(dst);
+   uint32_t new_clear_value = translate_clear_color(surf->base.format, color);
+
+   if (surf->surf.ts_size) { /* TS: use precompiled clear command */
+      ctx->framebuffer.TS_COLOR_CLEAR_VALUE = new_clear_value;
+
+      if (!DBG_ENABLED(ETNA_DBG_NO_AUTODISABLE) &&
+          VIV_FEATURE(ctx->screen, chipMinorFeatures1, AUTO_DISABLE)) {
+         /* Set number of color tiles to be filled */
+         etna_set_state(ctx->stream, VIVS_TS_COLOR_AUTO_DISABLE_COUNT,
+                        surf->surf.padded_width * surf->surf.padded_height / 16);
+         ctx->framebuffer.TS_MEM_CONFIG |= VIVS_TS_MEM_CONFIG_COLOR_AUTO_DISABLE;
+      }
+
+      ctx->dirty |= ETNA_DIRTY_TS;
+   } else if (unlikely(new_clear_value != surf->level->clear_value)) { /* Queue normal RS clear for non-TS surfaces */
+      /* If clear color changed, re-generate stored command */
+      etna_rs_gen_clear_surface(ctx, surf, new_clear_value);
+   }
+
+   etna_submit_rs_state(ctx, &surf->clear_command);
+   surf->level->clear_value = new_clear_value;
+   resource_written(ctx, surf->base.texture);
+   etna_resource(surf->base.texture)->seqno++;
+}
+
+static void
+etna_blit_clear_zs(struct pipe_context *pctx, struct pipe_surface *dst,
+                   unsigned buffers, double depth, unsigned stencil)
+{
+   struct etna_context *ctx = etna_context(pctx);
+   struct etna_surface *surf = etna_surface(dst);
+   uint32_t new_clear_value = translate_clear_depth_stencil(surf->base.format, depth, stencil);
+   uint32_t new_clear_bits = 0, clear_bits_depth, clear_bits_stencil;
+
+   /* Get the channels to clear */
+   switch (surf->base.format) {
+   case PIPE_FORMAT_Z16_UNORM:
+      clear_bits_depth = 0xffff;
+      clear_bits_stencil = 0;
+      break;
+   case PIPE_FORMAT_X8Z24_UNORM:
+   case PIPE_FORMAT_S8_UINT_Z24_UNORM:
+      clear_bits_depth = 0xeeee;
+      clear_bits_stencil = 0x1111;
+      break;
+   default:
+      clear_bits_depth = clear_bits_stencil = 0xffff;
+      break;
+   }
+
+   if (buffers & PIPE_CLEAR_DEPTH)
+      new_clear_bits |= clear_bits_depth;
+   if (buffers & PIPE_CLEAR_STENCIL)
+      new_clear_bits |= clear_bits_stencil;
+
+   /* FIXME: when tile status is enabled, this becomes more complex as
+    * we may separately clear the depth from the stencil.  In this case,
+    * we want to resolve the surface, and avoid using the tile status.
+    * We may be better off recording the pending clear operation,
+    * delaying the actual clear to the first use.  This way, we can merge
+    * consecutive clears together. */
+   if (surf->surf.ts_size) { /* TS: use precompiled clear command */
+      /* Set new clear depth value */
+      ctx->framebuffer.TS_DEPTH_CLEAR_VALUE = new_clear_value;
+      if (!DBG_ENABLED(ETNA_DBG_NO_AUTODISABLE) &&
+          VIV_FEATURE(ctx->screen, chipMinorFeatures1, AUTO_DISABLE)) {
+         /* Set number of depth tiles to be filled */
+         etna_set_state(ctx->stream, VIVS_TS_DEPTH_AUTO_DISABLE_COUNT,
+                        surf->surf.padded_width * surf->surf.padded_height / 16);
+         ctx->framebuffer.TS_MEM_CONFIG |= VIVS_TS_MEM_CONFIG_DEPTH_AUTO_DISABLE;
+      }
+
+      ctx->dirty |= ETNA_DIRTY_TS;
+   } else {
+      if (unlikely(new_clear_value != surf->level->clear_value)) { /* Queue normal RS clear for non-TS surfaces */
+         /* If clear depth value changed, re-generate stored command */
+         etna_rs_gen_clear_surface(ctx, surf, new_clear_value);
+      }
+      /* Update the channels to be cleared */
+      etna_modify_rs_clearbits(&surf->clear_command, new_clear_bits);
+   }
+
+   etna_submit_rs_state(ctx, &surf->clear_command);
+   surf->level->clear_value = new_clear_value;
+   resource_written(ctx, surf->base.texture);
+   etna_resource(surf->base.texture)->seqno++;
+}
+
+static void
+etna_clear(struct pipe_context *pctx, unsigned buffers,
+           const union pipe_color_union *color, double depth, unsigned stencil)
+{
+   struct etna_context *ctx = etna_context(pctx);
+
+   /* Flush color and depth cache before clearing anything.
+    * This is especially important when coming from another surface, as
+    * otherwise it may clear part of the old surface instead. */
+   etna_set_state(ctx->stream, VIVS_GL_FLUSH_CACHE, VIVS_GL_FLUSH_CACHE_COLOR | VIVS_GL_FLUSH_CACHE_DEPTH);
+   etna_stall(ctx->stream, SYNC_RECIPIENT_RA, SYNC_RECIPIENT_PE);
+
+   /* Preparation: Flush the TS if needed. This must be done after flushing
+    * color and depth, otherwise it can result in crashes */
+   bool need_ts_flush = false;
+   if ((buffers & PIPE_CLEAR_COLOR) && ctx->framebuffer_s.nr_cbufs) {
+      struct etna_surface *surf = etna_surface(ctx->framebuffer_s.cbufs[0]);
+      if (surf->surf.ts_size)
+         need_ts_flush = true;
+   }
+   if ((buffers & PIPE_CLEAR_DEPTHSTENCIL) && ctx->framebuffer_s.zsbuf != NULL) {
+      struct etna_surface *surf = etna_surface(ctx->framebuffer_s.zsbuf);
+
+      if (surf->surf.ts_size)
+         need_ts_flush = true;
+   }
+
+   if (need_ts_flush)
+      etna_set_state(ctx->stream, VIVS_TS_FLUSH_CACHE, VIVS_TS_FLUSH_CACHE_FLUSH);
+
+   /* No need to set up the TS here as RS clear operations (in contrast to
+    * resolve and copy) do not require the TS state.
+    */
+   if (buffers & PIPE_CLEAR_COLOR) {
+      for (int idx = 0; idx < ctx->framebuffer_s.nr_cbufs; ++idx) {
+         etna_blit_clear_color(pctx, ctx->framebuffer_s.cbufs[idx],
+                               &color[idx]);
+      }
+   }
+
+   /* Flush the color and depth caches before each RS clear operation
+    * This fixes a hang on GC600. */
+   if (buffers & PIPE_CLEAR_DEPTHSTENCIL && buffers & PIPE_CLEAR_COLOR)
+      etna_set_state(ctx->stream, VIVS_GL_FLUSH_CACHE,
+                     VIVS_GL_FLUSH_CACHE_COLOR | VIVS_GL_FLUSH_CACHE_DEPTH);
+
+   if ((buffers & PIPE_CLEAR_DEPTHSTENCIL) && ctx->framebuffer_s.zsbuf != NULL)
+      etna_blit_clear_zs(pctx, ctx->framebuffer_s.zsbuf, buffers, depth, stencil);
+
+   etna_stall(ctx->stream, SYNC_RECIPIENT_RA, SYNC_RECIPIENT_PE);
+}
+
+static void
+etna_clear_render_target(struct pipe_context *pctx, struct pipe_surface *dst,
+                         const union pipe_color_union *color, unsigned dstx,
+                         unsigned dsty, unsigned width, unsigned height,
+                         bool render_condition_enabled)
+{
+   struct etna_context *ctx = etna_context(pctx);
+
+   /* XXX could fall back to RS when target area is full screen / resolveable
+    * and no TS. */
+   etna_blit_save_state(ctx);
+   util_blitter_clear_render_target(ctx->blitter, dst, color, dstx, dsty, width, height);
+}
+
+static void
+etna_clear_depth_stencil(struct pipe_context *pctx, struct pipe_surface *dst,
+                         unsigned clear_flags, double depth, unsigned stencil,
+                         unsigned dstx, unsigned dsty, unsigned width,
+                         unsigned height, bool render_condition_enabled)
+{
+   struct etna_context *ctx = etna_context(pctx);
+
+   /* XXX could fall back to RS when target area is full screen / resolveable
+    * and no TS. */
+   etna_blit_save_state(ctx);
+   util_blitter_clear_depth_stencil(ctx->blitter, dst, clear_flags, depth,
+                                    stencil, dstx, dsty, width, height);
+}
+
+static void
+etna_resource_copy_region(struct pipe_context *pctx, struct pipe_resource *dst,
+                          unsigned dst_level, unsigned dstx, unsigned dsty,
+                          unsigned dstz, struct pipe_resource *src,
+                          unsigned src_level, const struct pipe_box *src_box)
+{
+   struct etna_context *ctx = etna_context(pctx);
+
+   /* The resource must be of the same format. */
+   assert(src->format == dst->format);
+   /* Resources with nr_samples > 1 are not allowed. */
+   assert(src->nr_samples <= 1 && dst->nr_samples <= 1);
+
+   /* XXX we can use the RS as a literal copy engine here
+    * the only complexity is tiling; the size of the boxes needs to be aligned
+    * to the tile size
+    * how to handle the case where a resource is copied from/to a non-aligned
+    * position?
+    * from non-aligned: can fall back to rendering-based copy?
+    * to non-aligned: can fall back to rendering-based copy?
+    * XXX this goes wrong when source surface is supertiled.
+    */
+   if (util_blitter_is_copy_supported(ctx->blitter, dst, src)) {
+      etna_blit_save_state(ctx);
+      util_blitter_copy_texture(ctx->blitter, dst, dst_level, dstx, dsty, dstz,
+                                src, src_level, src_box);
+   } else {
+      util_resource_copy_region(pctx, dst, dst_level, dstx, dsty, dstz, src,
+                                src_level, src_box);
+   }
+}
+
+static bool
+etna_manual_blit(struct etna_resource *dst, struct etna_resource_level *dst_lev,
+                 unsigned int dst_offset, struct etna_resource *src,
+                 struct etna_resource_level *src_lev, unsigned int src_offset,
+                 const struct pipe_blit_info *blit_info)
+{
+   void *smap, *srow, *dmap, *drow;
+   size_t tile_size;
+
+   assert(src->layout == ETNA_LAYOUT_TILED);
+   assert(dst->layout == ETNA_LAYOUT_TILED);
+   assert(src->base.nr_samples == 0);
+   assert(dst->base.nr_samples == 0);
+
+   tile_size = util_format_get_blocksize(blit_info->src.format) * 4 * 4;
+
+   smap = etna_bo_map(src->bo);
+   if (!smap)
+      return false;
+
+   dmap = etna_bo_map(dst->bo);
+   if (!dmap)
+      return false;
+
+   srow = smap + src_offset;
+   drow = dmap + dst_offset;
+
+   etna_bo_cpu_prep(src->bo, DRM_ETNA_PREP_READ);
+   etna_bo_cpu_prep(dst->bo, DRM_ETNA_PREP_WRITE);
+
+   for (int y = 0; y < blit_info->src.box.height; y += 4) {
+      memcpy(drow, srow, tile_size * blit_info->src.box.width);
+      srow += src_lev->stride * 4;
+      drow += dst_lev->stride * 4;
+   }
+
+   etna_bo_cpu_fini(dst->bo);
+   etna_bo_cpu_fini(src->bo);
+
+   return true;
+}
+
+static bool
+etna_try_rs_blit(struct pipe_context *pctx,
+                 const struct pipe_blit_info *blit_info)
+{
+   struct etna_context *ctx = etna_context(pctx);
+   struct etna_resource *src = etna_resource(blit_info->src.resource);
+   struct etna_resource *dst = etna_resource(blit_info->dst.resource);
+   struct compiled_rs_state copy_to_screen;
+   uint32_t ts_mem_config = 0;
+   int msaa_xscale = 1, msaa_yscale = 1;
+
+   /* Ensure that the level is valid */
+   assert(blit_info->src.level <= src->base.last_level);
+   assert(blit_info->dst.level <= dst->base.last_level);
+
+   if (!translate_samples_to_xyscale(src->base.nr_samples, &msaa_xscale, &msaa_yscale, NULL))
+      return FALSE;
+
+   /* The width/height are in pixels; they do not change as a result of
+    * multi-sampling. So, when blitting from a 4x multisampled surface
+    * to a non-multisampled surface, the width and height will be
+    * identical. As we do not support scaling, reject different sizes. */
+   if (blit_info->dst.box.width != blit_info->src.box.width ||
+       blit_info->dst.box.height != blit_info->src.box.height) {
+      DBG("scaling requested: source %dx%d destination %dx%d",
+          blit_info->src.box.width, blit_info->src.box.height,
+          blit_info->dst.box.width, blit_info->dst.box.height);
+      return FALSE;
+   }
+
+   /* No masks - RS can't copy specific channels */
+   unsigned mask = util_format_get_mask(blit_info->dst.format);
+   if ((blit_info->mask & mask) != mask) {
+      DBG("sub-mask requested: 0x%02x vs format mask 0x%02x", blit_info->mask, mask);
+      return FALSE;
+   }
+
+   unsigned src_format = etna_compatible_rs_format(blit_info->src.format);
+   unsigned dst_format = etna_compatible_rs_format(blit_info->src.format);
+   if (translate_rs_format(src_format) == ETNA_NO_MATCH ||
+       translate_rs_format(dst_format) == ETNA_NO_MATCH ||
+       blit_info->scissor_enable || blit_info->src.box.x != 0 ||
+       blit_info->src.box.y != 0 || blit_info->dst.box.x != 0 ||
+       blit_info->dst.box.y != 0 ||
+       blit_info->dst.box.depth != blit_info->src.box.depth ||
+       blit_info->dst.box.depth != 1) {
+      return FALSE;
+   }
+
+   /* Ensure that the Z coordinate is sane */
+   if (dst->base.target != PIPE_TEXTURE_CUBE)
+      assert(blit_info->dst.box.z == 0);
+   if (src->base.target != PIPE_TEXTURE_CUBE)
+      assert(blit_info->src.box.z == 0);
+
+   assert(blit_info->src.box.z < src->base.array_size);
+   assert(blit_info->dst.box.z < dst->base.array_size);
+
+   struct etna_resource_level *src_lev = &src->levels[blit_info->src.level];
+   struct etna_resource_level *dst_lev = &dst->levels[blit_info->dst.level];
+
+   /* we may be given coordinates up to the padded width to avoid
+    * any alignment issues with different tiling formats */
+   assert((blit_info->src.box.x + blit_info->src.box.width) * msaa_xscale <= src_lev->padded_width);
+   assert((blit_info->src.box.y + blit_info->src.box.height) * msaa_yscale <= src_lev->padded_height);
+   assert(blit_info->dst.box.x + blit_info->dst.box.width <= dst_lev->padded_width);
+   assert(blit_info->dst.box.y + blit_info->dst.box.height <= dst_lev->padded_height);
+
+   unsigned src_offset =
+      src_lev->offset + blit_info->src.box.z * src_lev->layer_stride;
+   unsigned dst_offset =
+      dst_lev->offset + blit_info->dst.box.z * dst_lev->layer_stride;
+
+   if (src_lev->padded_width <= ETNA_RS_WIDTH_MASK ||
+       dst_lev->padded_width <= ETNA_RS_WIDTH_MASK ||
+       src_lev->padded_height <= ETNA_RS_HEIGHT_MASK ||
+       dst_lev->padded_height <= ETNA_RS_HEIGHT_MASK)
+      goto manual;
+
+   /* If the width is not aligned to the RS width, but is within our
+    * padding, adjust the width to suite the RS width restriction.
+    * Note: the RS width/height are converted to source samples here. */
+   unsigned int width = blit_info->src.box.width * msaa_xscale;
+   unsigned int height = blit_info->src.box.height * msaa_yscale;
+   unsigned int w_align = ETNA_RS_WIDTH_MASK + 1;
+   unsigned int h_align = (ETNA_RS_HEIGHT_MASK + 1) * ctx->specs.pixel_pipes;
+
+   if (width & (w_align - 1) && width >= src_lev->width * msaa_xscale && width >= dst_lev->width)
+      width = align(width, w_align);
+
+   if (height & (h_align - 1) && height >= src_lev->height * msaa_yscale && height >= dst_lev->height)
+      height = align(height, h_align);
+
+   /* The padded dimensions are in samples */
+   if (width > src_lev->padded_width ||
+       width > dst_lev->padded_width * msaa_xscale ||
+       height > src_lev->padded_height ||
+       height > dst_lev->padded_height * msaa_yscale)
+      goto manual;
+
+   if (src->base.nr_samples > 1) {
+      uint32_t msaa_format = translate_msaa_format(src_format);
+      assert(msaa_format != ETNA_NO_MATCH);
+      ts_mem_config |= VIVS_TS_MEM_CONFIG_MSAA | msaa_format;
+   }
+
+   uint32_t to_flush = 0;
+
+   if (src->base.bind & PIPE_BIND_RENDER_TARGET)
+      to_flush |= VIVS_GL_FLUSH_CACHE_COLOR;
+   if (src->base.bind & PIPE_BIND_DEPTH_STENCIL)
+      to_flush |= VIVS_GL_FLUSH_CACHE_DEPTH;
+
+   if (to_flush) {
+      etna_set_state(ctx->stream, VIVS_GL_FLUSH_CACHE, to_flush);
+      etna_stall(ctx->stream, SYNC_RECIPIENT_RA, SYNC_RECIPIENT_PE);
+   }
+
+   /* Set up color TS to source surface before blit, if needed */
+   if (src->levels[blit_info->src.level].ts_size) {
+      struct etna_reloc reloc;
+      unsigned ts_offset =
+         src_lev->ts_offset + blit_info->src.box.z * src_lev->ts_layer_stride;
+
+      etna_set_state(ctx->stream, VIVS_TS_MEM_CONFIG,
+                     VIVS_TS_MEM_CONFIG_COLOR_FAST_CLEAR | ts_mem_config);
+
+      memset(&reloc, 0, sizeof(struct etna_reloc));
+      reloc.bo = src->ts_bo;
+      reloc.offset = ts_offset;
+      reloc.flags = ETNA_RELOC_READ;
+      etna_set_state_reloc(ctx->stream, VIVS_TS_COLOR_STATUS_BASE, &reloc);
+
+      memset(&reloc, 0, sizeof(struct etna_reloc));
+      reloc.bo = src->bo;
+      reloc.offset = src_offset;
+      reloc.flags = ETNA_RELOC_READ;
+      etna_set_state_reloc(ctx->stream, VIVS_TS_COLOR_SURFACE_BASE, &reloc);
+
+      etna_set_state(ctx->stream, VIVS_TS_COLOR_CLEAR_VALUE,
+                     src->levels[blit_info->src.level].clear_value);
+   } else {
+      etna_set_state(ctx->stream, VIVS_TS_MEM_CONFIG, ts_mem_config);
+   }
+   ctx->dirty |= ETNA_DIRTY_TS;
+
+   /* Kick off RS here */
+   etna_compile_rs_state(ctx, &copy_to_screen, &(struct rs_state) {
+      .source_format = translate_rs_format(src_format),
+      .source_tiling = src->layout,
+      .source = src->bo,
+      .source_offset = src_offset,
+      .source_stride = src_lev->stride,
+      .source_padded_height = src_lev->padded_height,
+      .dest_format = translate_rs_format(dst_format),
+      .dest_tiling = dst->layout,
+      .dest = dst->bo,
+      .dest_offset = dst_offset,
+      .dest_stride = dst_lev->stride,
+      .dest_padded_height = dst_lev->padded_height,
+      .downsample_x = msaa_xscale > 1,
+      .downsample_y = msaa_yscale > 1,
+      .swap_rb = translate_rb_src_dst_swap(src->base.format, dst->base.format),
+      .dither = {0xffffffff, 0xffffffff}, // XXX dither when going from 24 to 16 bit?
+      .clear_mode = VIVS_RS_CLEAR_CONTROL_MODE_DISABLED,
+      .width = width,
+      .height = height
+   });
+
+   etna_submit_rs_state(ctx, &copy_to_screen);
+   resource_written(ctx, &dst->base);
+   dst->seqno++;
+
+   return TRUE;
+
+manual:
+   if (src->layout == ETNA_LAYOUT_TILED && dst->layout == ETNA_LAYOUT_TILED) {
+      etna_resource_wait(pctx, dst);
+      etna_resource_wait(pctx, src);
+      return etna_manual_blit(dst, dst_lev, dst_offset, src, src_lev, src_offset, blit_info);
+   }
+
+   return FALSE;
+}
+
+static void
+etna_blit(struct pipe_context *pctx, const struct pipe_blit_info *blit_info)
+{
+   /* This is a more extended version of resource_copy_region */
+   /* TODO Some cases can be handled by RS; if not, fall back to rendering or
+    * even CPU copy block of pixels from info->src to info->dst
+    * (resource, level, box, format);
+    * function is used for scaling, flipping in x and y direction (negative
+    * width/height), format conversion, mask and filter and even a scissor rectangle
+    *
+    * What can the RS do for us:
+    *   convert between tiling formats (layouts)
+    *   downsample 2x in x and y
+    *   convert between a limited number of pixel formats
+    *
+    * For the rest, fall back to util_blitter
+    * XXX this goes wrong when source surface is supertiled. */
+   struct etna_context *ctx = etna_context(pctx);
+   struct pipe_blit_info info = *blit_info;
+
+   if (info.src.resource->nr_samples > 1 &&
+       info.dst.resource->nr_samples <= 1 &&
+       !util_format_is_depth_or_stencil(info.src.resource->format) &&
+       !util_format_is_pure_integer(info.src.resource->format)) {
+      DBG("color resolve unimplemented");
+      return;
+   }
+
+   if (etna_try_rs_blit(pctx, blit_info))
+      return;
+
+   if (util_try_blit_via_copy_region(pctx, blit_info))
+      return;
+
+   if (info.mask & PIPE_MASK_S) {
+      DBG("cannot blit stencil, skipping");
+      info.mask &= ~PIPE_MASK_S;
+   }
+
+   if (!util_blitter_is_blit_supported(ctx->blitter, &info)) {
+      DBG("blit unsupported %s -> %s",
+          util_format_short_name(info.src.resource->format),
+          util_format_short_name(info.dst.resource->format));
+      return;
+   }
+
+   etna_blit_save_state(ctx);
+   util_blitter_blit(ctx->blitter, &info);
+}
+
+static void
+etna_flush_resource(struct pipe_context *pctx, struct pipe_resource *prsc)
+{
+   struct etna_resource *rsc = etna_resource(prsc);
+
+   if (rsc->scanout)
+      etna_copy_resource(pctx, rsc->scanout->prime, prsc, 0, 0);
+}
+
+void
+etna_copy_resource(struct pipe_context *pctx, struct pipe_resource *dst,
+                   struct pipe_resource *src, int first_level, int last_level)
+{
+   struct etna_resource *src_priv = etna_resource(src);
+   struct etna_resource *dst_priv = etna_resource(dst);
+
+   assert(src->format == dst->format);
+   assert(src->array_size == dst->array_size);
+   assert(last_level <= dst->last_level && last_level <= src->last_level);
+
+   struct pipe_blit_info blit = {};
+   blit.mask = util_format_get_mask(dst->format);
+   blit.filter = PIPE_TEX_FILTER_NEAREST;
+   blit.src.resource = src;
+   blit.src.format = src->format;
+   blit.dst.resource = dst;
+   blit.dst.format = dst->format;
+   blit.dst.box.depth = blit.src.box.depth = 1;
+
+   /* Copy each level and each layer */
+   for (int level = first_level; level <= last_level; level++) {
+      blit.src.level = blit.dst.level = level;
+      blit.src.box.width = blit.dst.box.width =
+         MIN2(src_priv->levels[level].width, dst_priv->levels[level].width);
+      blit.src.box.height = blit.dst.box.height =
+         MIN2(src_priv->levels[level].height, dst_priv->levels[level].height);
+
+      for (int layer = 0; layer < dst->array_size; layer++) {
+         blit.src.box.z = blit.dst.box.z = layer;
+         pctx->blit(pctx, &blit);
+      }
+   }
+}
+
+void
+etna_clear_blit_init(struct pipe_context *pctx)
+{
+   pctx->clear = etna_clear;
+   pctx->clear_render_target = etna_clear_render_target;
+   pctx->clear_depth_stencil = etna_clear_depth_stencil;
+   pctx->resource_copy_region = etna_resource_copy_region;
+   pctx->blit = etna_blit;
+   pctx->flush_resource = etna_flush_resource;
+}
diff --git a/src/gallium/drivers/etnaviv/etnaviv_clear_blit.h b/src/gallium/drivers/etnaviv/etnaviv_clear_blit.h
new file mode 100644
index 0000000..73d0704
--- /dev/null
+++ b/src/gallium/drivers/etnaviv/etnaviv_clear_blit.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2012-2013 Etnaviv Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Wladimir J. van der Laan <laanwj at gmail.com>
+ */
+
+#ifndef H_ETNAVIV_CLEAR_BLIT
+#define H_ETNAVIV_CLEAR_BLIT
+
+#include <stdint.h>
+
+struct etna_context;
+struct etna_surface;
+
+#include "pipe/p_context.h"
+
+void
+etna_rs_gen_clear_surface(struct etna_context *ctx, struct etna_surface *surf,
+                          uint32_t clear_value);
+
+void
+etna_copy_resource(struct pipe_context *pctx, struct pipe_resource *dst,
+                   struct pipe_resource *src, int first_level, int last_level);
+
+void
+etna_clear_blit_init(struct pipe_context *pctx);
+
+#endif
diff --git a/src/gallium/drivers/etnaviv/etnaviv_compiler.c b/src/gallium/drivers/etnaviv/etnaviv_compiler.c
new file mode 100644
index 0000000..de03c52
--- /dev/null
+++ b/src/gallium/drivers/etnaviv/etnaviv_compiler.c
@@ -0,0 +1,2564 @@
+/*
+ * Copyright (c) 2012-2015 Etnaviv Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Wladimir J. van der Laan <laanwj at gmail.com>
+ */
+
+/* TGSI->Vivante shader ISA conversion */
+
+/* What does the compiler return (see etna_shader_object)?
+ *  1) instruction data
+ *  2) input-to-temporary mapping (fixed for ps)
+ *      *) in case of ps, semantic -> varying id mapping
+ *      *) for each varying: number of components used (r, rg, rgb, rgba)
+ *  3) temporary-to-output mapping (in case of vs, fixed for ps)
+ *  4) for each input/output: possible semantic (position, color, glpointcoord, ...)
+ *  5) immediates base offset, immediates data
+ *  6) used texture units (and possibly the TGSI_TEXTURE_* type); not needed to
+ *     configure the hw, but useful for error checking
+ *  7) enough information to add the z=(z+w)/2.0 necessary for older chips
+ *     (output reg id is enough)
+ *
+ *  Empty shaders are not allowed, should always at least generate a NOP. Also
+ *  if there is a label at the end of the shader, an extra NOP should be
+ *  generated as jump target.
+ *
+ * TODO
+ * * Use an instruction scheduler
+ * * Indirect access to uniforms / temporaries using amode
+ */
+
+#include "etnaviv_compiler.h"
+
+#include "etnaviv_asm.h"
+#include "etnaviv_context.h"
+#include "etnaviv_debug.h"
+#include "etnaviv_disasm.h"
+#include "etnaviv_uniforms.h"
+#include "etnaviv_util.h"
+
+#include "pipe/p_shader_tokens.h"
+#include "tgsi/tgsi_info.h"
+#include "tgsi/tgsi_iterate.h"
+#include "tgsi/tgsi_lowering.h"
+#include "tgsi/tgsi_strings.h"
+#include "tgsi/tgsi_util.h"
+#include "util/u_math.h"
+#include "util/u_memory.h"
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#define ETNA_MAX_INNER_TEMPS 2
+
+static const float sincos_const[2][4] = {
+   {
+      2., -1., 4., -4.,
+   },
+   {
+      1. / (2. * M_PI), 0.75, 0.5, 0.0,
+   },
+};
+
+/* Native register description structure */
+struct etna_native_reg {
+   unsigned valid : 1;
+   unsigned is_tex : 1; /* is texture unit, overrides rgroup */
+   unsigned rgroup : 3;
+   unsigned id : 9;
+};
+
+/* Register description */
+struct etna_reg_desc {
+   enum tgsi_file_type file; /* IN, OUT, TEMP, ... */
+   int idx; /* index into file */
+   bool active; /* used in program */
+   int first_use; /* instruction id of first use (scope begin) */
+   int last_use; /* instruction id of last use (scope end, inclusive) */
+
+   struct etna_native_reg native; /* native register to map to */
+   unsigned usage_mask : 4; /* usage, per channel */
+   bool has_semantic; /* register has associated TGSI semantic */
+   struct tgsi_declaration_semantic semantic; /* TGSI semantic */
+   struct tgsi_declaration_interp interp; /* Interpolation type */
+};
+
+/* Label information structure */
+struct etna_compile_label {
+   int inst_idx; /* Instruction id that label points to */
+};
+
+enum etna_compile_frame_type {
+   ETNA_COMPILE_FRAME_IF, /* IF/ELSE/ENDIF */
+   ETNA_COMPILE_FRAME_LOOP,
+};
+
+/* nesting scope frame (LOOP, IF, ...) during compilation
+ */
+struct etna_compile_frame {
+   enum etna_compile_frame_type type;
+   struct etna_compile_label *lbl_else;
+   struct etna_compile_label *lbl_endif;
+   struct etna_compile_label *lbl_loop_bgn;
+   struct etna_compile_label *lbl_loop_end;
+};
+
+struct etna_compile_file {
+   /* Number of registers in each TGSI file (max register+1) */
+   size_t reg_size;
+   /* Register descriptions, per register index */
+   struct etna_reg_desc *reg;
+};
+
+#define array_insert(arr, val)                          \
+   do {                                                 \
+      if (arr##_count == arr##_sz) {                    \
+         arr##_sz = MAX2(2 * arr##_sz, 16);             \
+         arr = realloc(arr, arr##_sz * sizeof(arr[0])); \
+      }                                                 \
+      arr[arr##_count++] = val;                         \
+   } while (0)
+
+
+/* scratch area for compiling shader, freed after compilation finishes */
+struct etna_compile {
+   const struct tgsi_token *tokens;
+   bool free_tokens;
+
+   struct tgsi_shader_info info;
+
+   /* Register descriptions, per TGSI file, per register index */
+   struct etna_compile_file file[TGSI_FILE_COUNT];
+
+   /* Keep track of TGSI register declarations */
+   struct etna_reg_desc decl[ETNA_MAX_DECL];
+   uint total_decls;
+
+   /* Bitmap of dead instructions which are removed in a separate pass */
+   bool dead_inst[ETNA_MAX_TOKENS];
+
+   /* Immediate data */
+   enum etna_immediate_contents imm_contents[ETNA_MAX_IMM];
+   uint32_t imm_data[ETNA_MAX_IMM];
+   uint32_t imm_base; /* base of immediates (in 32 bit units) */
+   uint32_t imm_size; /* size of immediates (in 32 bit units) */
+
+   /* Next free native register, for register allocation */
+   uint32_t next_free_native;
+
+   /* Temporary register for use within translated TGSI instruction,
+    * only allocated when needed.
+    */
+   int inner_temps; /* number of inner temps used; only up to one available at
+                       this point */
+   struct etna_native_reg inner_temp[ETNA_MAX_INNER_TEMPS];
+
+   /* Fields for handling nested conditionals */
+   struct etna_compile_frame frame_stack[ETNA_MAX_DEPTH];
+   int frame_sp;
+   struct etna_compile_label *lbl_usage[ETNA_MAX_INSTRUCTIONS];
+
+   unsigned labels_count, labels_sz;
+   struct etna_compile_label *labels;
+
+   /* Code generation */
+   int inst_ptr; /* current instruction pointer */
+   uint32_t code[ETNA_MAX_INSTRUCTIONS * ETNA_INST_SIZE];
+
+   /* I/O */
+
+   /* Number of varyings (PS only) */
+   int num_varyings;
+
+   /* GPU hardware specs */
+   const struct etna_specs *specs;
+};
+
+static struct etna_reg_desc *
+etna_get_dst_reg(struct etna_compile *c, struct tgsi_dst_register dst)
+{
+   return &c->file[dst.File].reg[dst.Index];
+}
+
+static struct etna_reg_desc *
+etna_get_src_reg(struct etna_compile *c, struct tgsi_src_register src)
+{
+   return &c->file[src.File].reg[src.Index];
+}
+
+static struct etna_native_reg
+etna_native_temp(unsigned reg)
+{
+   return (struct etna_native_reg) {
+      .valid = 1,
+      .rgroup = INST_RGROUP_TEMP,
+      .id = reg
+   };
+}
+
+/** Register allocation **/
+enum reg_sort_order {
+   FIRST_USE_ASC,
+   FIRST_USE_DESC,
+   LAST_USE_ASC,
+   LAST_USE_DESC
+};
+
+/* Augmented register description for sorting */
+struct sort_rec {
+   struct etna_reg_desc *ptr;
+   int key;
+};
+
+static int
+sort_rec_compar(const struct sort_rec *a, const struct sort_rec *b)
+{
+   if (a->key < b->key)
+      return -1;
+
+   if (a->key > b->key)
+      return 1;
+
+   return 0;
+}
+
+/* create an index on a register set based on certain criteria. */
+static int
+sort_registers(struct sort_rec *sorted, struct etna_compile_file *file,
+               enum reg_sort_order so)
+{
+   struct etna_reg_desc *regs = file->reg;
+   int ptr = 0;
+
+   /* pre-populate keys from active registers */
+   for (int idx = 0; idx < file->reg_size; ++idx) {
+      /* only interested in active registers now; will only assign inactive ones
+       * if no space in active ones */
+      if (regs[idx].active) {
+         sorted[ptr].ptr = &regs[idx];
+
+         switch (so) {
+         case FIRST_USE_ASC:
+            sorted[ptr].key = regs[idx].first_use;
+            break;
+         case LAST_USE_ASC:
+            sorted[ptr].key = regs[idx].last_use;
+            break;
+         case FIRST_USE_DESC:
+            sorted[ptr].key = -regs[idx].first_use;
+            break;
+         case LAST_USE_DESC:
+            sorted[ptr].key = -regs[idx].last_use;
+            break;
+         }
+         ptr++;
+      }
+   }
+
+   /* sort index by key */
+   qsort(sorted, ptr, sizeof(struct sort_rec),
+         (int (*)(const void *, const void *))sort_rec_compar);
+
+   return ptr;
+}
+
+/* Allocate a new, unused, native temp register */
+static struct etna_native_reg
+alloc_new_native_reg(struct etna_compile *c)
+{
+   assert(c->next_free_native < ETNA_MAX_TEMPS);
+   return etna_native_temp(c->next_free_native++);
+}
+
+/* assign TEMPs to native registers */
+static void
+assign_temporaries_to_native(struct etna_compile *c,
+                             struct etna_compile_file *file)
+{
+   struct etna_reg_desc *temps = file->reg;
+
+   for (int idx = 0; idx < file->reg_size; ++idx)
+      temps[idx].native = alloc_new_native_reg(c);
+}
+
+/* assign inputs and outputs to temporaries
+ * Gallium assumes that the hardware has separate registers for taking input and
+ * output, however Vivante GPUs use temporaries both for passing in inputs and
+ * passing back outputs.
+ * Try to re-use temporary registers where possible. */
+static void
+assign_inouts_to_temporaries(struct etna_compile *c, uint file)
+{
+   bool mode_inputs = (file == TGSI_FILE_INPUT);
+   int inout_ptr = 0, num_inouts;
+   int temp_ptr = 0, num_temps;
+   struct sort_rec inout_order[ETNA_MAX_TEMPS];
+   struct sort_rec temps_order[ETNA_MAX_TEMPS];
+   num_inouts = sort_registers(inout_order, &c->file[file],
+                               mode_inputs ? LAST_USE_ASC : FIRST_USE_ASC);
+   num_temps = sort_registers(temps_order, &c->file[TGSI_FILE_TEMPORARY],
+                              mode_inputs ? FIRST_USE_ASC : LAST_USE_ASC);
+
+   while (inout_ptr < num_inouts && temp_ptr < num_temps) {
+      struct etna_reg_desc *inout = inout_order[inout_ptr].ptr;
+      struct etna_reg_desc *temp = temps_order[temp_ptr].ptr;
+
+      if (!inout->active || inout->native.valid) { /* Skip if already a native register assigned */
+         inout_ptr++;
+         continue;
+      }
+
+      /* last usage of this input is before or in same instruction of first use
+       * of temporary? */
+      if (mode_inputs ? (inout->last_use <= temp->first_use)
+                      : (inout->first_use >= temp->last_use)) {
+         /* assign it and advance to next input */
+         inout->native = temp->native;
+         inout_ptr++;
+      }
+
+      temp_ptr++;
+   }
+
+   /* if we couldn't reuse current ones, allocate new temporaries */
+   for (inout_ptr = 0; inout_ptr < num_inouts; ++inout_ptr) {
+      struct etna_reg_desc *inout = inout_order[inout_ptr].ptr;
+
+      if (inout->active && !inout->native.valid)
+         inout->native = alloc_new_native_reg(c);
+   }
+}
+
+/* Allocate an immediate with a certain value and return the index. If
+ * there is already an immediate with that value, return that.
+ */
+static struct etna_inst_src
+alloc_imm(struct etna_compile *c, enum etna_immediate_contents contents,
+          uint32_t value)
+{
+   int idx;
+
+   /* Could use a hash table to speed this up */
+   for (idx = 0; idx < c->imm_size; ++idx) {
+      if (c->imm_contents[idx] == contents && c->imm_data[idx] == value)
+         break;
+   }
+
+   /* look if there is an unused slot */
+   if (idx == c->imm_size) {
+      for (idx = 0; idx < c->imm_size; ++idx) {
+         if (c->imm_contents[idx] == ETNA_IMMEDIATE_UNUSED)
+            break;
+      }
+   }
+
+   /* allocate new immediate */
+   if (idx == c->imm_size) {
+      assert(c->imm_size < ETNA_MAX_IMM);
+      idx = c->imm_size++;
+      c->imm_data[idx] = value;
+      c->imm_contents[idx] = contents;
+   }
+
+   /* swizzle so that component with value is returned in all components */
+   idx += c->imm_base;
+   struct etna_inst_src imm_src = {
+      .use = 1,
+      .rgroup = INST_RGROUP_UNIFORM_0,
+      .reg = idx / 4,
+      .swiz = INST_SWIZ_BROADCAST(idx & 3)
+   };
+
+   return imm_src;
+}
+
+static struct etna_inst_src
+alloc_imm_u32(struct etna_compile *c, uint32_t value)
+{
+   return alloc_imm(c, ETNA_IMMEDIATE_CONSTANT, value);
+}
+
+static struct etna_inst_src
+alloc_imm_vec4u(struct etna_compile *c, enum etna_immediate_contents contents,
+                const uint32_t *values)
+{
+   struct etna_inst_src imm_src = { };
+   int idx, i;
+
+   for (idx = 0; idx + 3 < c->imm_size; idx += 4) {
+      /* What if we can use a uniform with a different swizzle? */
+      for (i = 0; i < 4; i++)
+         if (c->imm_contents[idx + i] != contents || c->imm_data[idx + i] != values[i])
+            break;
+      if (i == 4)
+         break;
+   }
+
+   if (idx + 3 >= c->imm_size) {
+      idx = align(c->imm_size, 4);
+      assert(idx + 4 <= ETNA_MAX_IMM);
+
+      for (i = 0; i < 4; i++) {
+         c->imm_data[idx + i] = values[i];
+         c->imm_contents[idx + i] = contents;
+      }
+
+      c->imm_size = idx + 4;
+   }
+
+   assert((c->imm_base & 3) == 0);
+   idx += c->imm_base;
+   imm_src.use = 1;
+   imm_src.rgroup = INST_RGROUP_UNIFORM_0;
+   imm_src.reg = idx / 4;
+   imm_src.swiz = INST_SWIZ_IDENTITY;
+
+   return imm_src;
+}
+
+static uint32_t
+get_imm_u32(struct etna_compile *c, const struct etna_inst_src *imm,
+            unsigned swiz_idx)
+{
+   assert(imm->use == 1 && imm->rgroup == INST_RGROUP_UNIFORM_0);
+   unsigned int idx = imm->reg * 4 + ((imm->swiz >> (swiz_idx * 2)) & 3);
+
+   return c->imm_data[idx];
+}
+
+/* Allocate immediate with a certain float value. If there is already an
+ * immediate with that value, return that.
+ */
+static struct etna_inst_src
+alloc_imm_f32(struct etna_compile *c, float value)
+{
+   return alloc_imm_u32(c, fui(value));
+}
+
+static struct etna_inst_src
+etna_imm_vec4f(struct etna_compile *c, const float *vec4)
+{
+   uint32_t val[4];
+
+   for (int i = 0; i < 4; i++)
+      val[i] = fui(vec4[i]);
+
+   return alloc_imm_vec4u(c, ETNA_IMMEDIATE_CONSTANT, val);
+}
+
+/* Pass -- check register file declarations and immediates */
+static void
+etna_compile_parse_declarations(struct etna_compile *c)
+{
+   struct tgsi_parse_context ctx = { };
+   unsigned status = TGSI_PARSE_OK;
+   status = tgsi_parse_init(&ctx, c->tokens);
+   assert(status == TGSI_PARSE_OK);
+
+   while (!tgsi_parse_end_of_tokens(&ctx)) {
+      tgsi_parse_token(&ctx);
+
+      switch (ctx.FullToken.Token.Type) {
+      case TGSI_TOKEN_TYPE_IMMEDIATE: {
+         /* immediates are handled differently from other files; they are
+          * not declared explicitly, and always add four components */
+         const struct tgsi_full_immediate *imm = &ctx.FullToken.FullImmediate;
+         assert(c->imm_size <= (ETNA_MAX_IMM - 4));
+
+         for (int i = 0; i < 4; ++i) {
+            unsigned idx = c->imm_size++;
+
+            c->imm_data[idx] = imm->u[i].Uint;
+            c->imm_contents[idx] = ETNA_IMMEDIATE_CONSTANT;
+         }
+      }
+      break;
+      }
+   }
+
+   tgsi_parse_free(&ctx);
+}
+
+/* Allocate register declarations for the registers in all register files */
+static void
+etna_allocate_decls(struct etna_compile *c)
+{
+   uint idx = 0;
+
+   for (int x = 0; x < TGSI_FILE_COUNT; ++x) {
+      c->file[x].reg = &c->decl[idx];
+      c->file[x].reg_size = c->info.file_max[x] + 1;
+
+      for (int sub = 0; sub < c->file[x].reg_size; ++sub) {
+         c->decl[idx].file = x;
+         c->decl[idx].idx = sub;
+         idx++;
+      }
+   }
+
+   c->total_decls = idx;
+}
+
+/* Pass -- check and record usage of temporaries, inputs, outputs */
+static void
+etna_compile_pass_check_usage(struct etna_compile *c)
+{
+   struct tgsi_parse_context ctx = { };
+   unsigned status = TGSI_PARSE_OK;
+   status = tgsi_parse_init(&ctx, c->tokens);
+   assert(status == TGSI_PARSE_OK);
+
+   for (int idx = 0; idx < c->total_decls; ++idx) {
+      c->decl[idx].active = false;
+      c->decl[idx].first_use = c->decl[idx].last_use = -1;
+   }
+
+   int inst_idx = 0;
+   while (!tgsi_parse_end_of_tokens(&ctx)) {
+      tgsi_parse_token(&ctx);
+      /* find out max register #s used
+       * For every register mark first and last instruction index where it's
+       * used this allows finding ranges where the temporary can be borrowed
+       * as input and/or output register
+       *
+       * XXX in the case of loops this needs special care, or even be completely
+       * disabled, as
+       * the last usage of a register inside a loop means it can still be used
+       * on next loop
+       * iteration (execution is no longer * chronological). The register can
+       * only be
+       * declared "free" after the loop finishes.
+       *
+       * Same for inputs: the first usage of a register inside a loop doesn't
+       * mean that the register
+       * won't have been overwritten in previous iteration. The register can
+       * only be declared free before the loop
+       * starts.
+       * The proper way would be to do full dominator / post-dominator analysis
+       * (especially with more complicated
+       * control flow such as direct branch instructions) but not for now...
+       */
+      switch (ctx.FullToken.Token.Type) {
+      case TGSI_TOKEN_TYPE_DECLARATION: {
+         /* Declaration: fill in file details */
+         const struct tgsi_full_declaration *decl = &ctx.FullToken.FullDeclaration;
+         struct etna_compile_file *file = &c->file[decl->Declaration.File];
+
+         for (int idx = decl->Range.First; idx <= decl->Range.Last; ++idx) {
+            file->reg[idx].usage_mask = 0; // we'll compute this ourselves
+            file->reg[idx].has_semantic = decl->Declaration.Semantic;
+            file->reg[idx].semantic = decl->Semantic;
+            file->reg[idx].interp = decl->Interp;
+         }
+      } break;
+      case TGSI_TOKEN_TYPE_INSTRUCTION: {
+         /* Instruction: iterate over operands of instruction */
+         const struct tgsi_full_instruction *inst = &ctx.FullToken.FullInstruction;
+
+         /* iterate over destination registers */
+         for (int idx = 0; idx < inst->Instruction.NumDstRegs; ++idx) {
+            struct etna_reg_desc *reg_desc = &c->file[inst->Dst[idx].Register.File].reg[inst->Dst[idx].Register.Index];
+
+            if (reg_desc->first_use == -1)
+               reg_desc->first_use = inst_idx;
+
+            reg_desc->last_use = inst_idx;
+            reg_desc->active = true;
+         }
+
+         /* iterate over source registers */
+         for (int idx = 0; idx < inst->Instruction.NumSrcRegs; ++idx) {
+            struct etna_reg_desc *reg_desc = &c->file[inst->Src[idx].Register.File].reg[inst->Src[idx].Register.Index];
+
+            if (reg_desc->first_use == -1)
+               reg_desc->first_use = inst_idx;
+
+            reg_desc->last_use = inst_idx;
+            reg_desc->active = true;
+            /* accumulate usage mask for register, this is used to determine how
+             * many slots for varyings
+             * should be allocated */
+            reg_desc->usage_mask |= tgsi_util_get_inst_usage_mask(inst, idx);
+         }
+         inst_idx += 1;
+      } break;
+      default:
+         break;
+      }
+   }
+
+   tgsi_parse_free(&ctx);
+}
+
+/* assign inputs that need to be assigned to specific registers */
+static void
+assign_special_inputs(struct etna_compile *c)
+{
+   if (c->info.processor == PIPE_SHADER_FRAGMENT) {
+      /* never assign t0 as it is the position output, start assigning at t1 */
+      c->next_free_native = 1;
+
+      /* hardwire TGSI_SEMANTIC_POSITION (input and output) to t0 */
+      for (int idx = 0; idx < c->total_decls; ++idx) {
+         struct etna_reg_desc *reg = &c->decl[idx];
+
+         if (reg->active && reg->semantic.Name == TGSI_SEMANTIC_POSITION)
+            reg->native = etna_native_temp(0);
+      }
+   }
+}
+
+/* Check that a move instruction does not swizzle any of the components
+ * that it writes.
+ */
+static bool
+etna_mov_check_no_swizzle(const struct tgsi_dst_register dst,
+                          const struct tgsi_src_register src)
+{
+   return (!(dst.WriteMask & TGSI_WRITEMASK_X) || src.SwizzleX == TGSI_SWIZZLE_X) &&
+          (!(dst.WriteMask & TGSI_WRITEMASK_Y) || src.SwizzleY == TGSI_SWIZZLE_Y) &&
+          (!(dst.WriteMask & TGSI_WRITEMASK_Z) || src.SwizzleZ == TGSI_SWIZZLE_Z) &&
+          (!(dst.WriteMask & TGSI_WRITEMASK_W) || src.SwizzleW == TGSI_SWIZZLE_W);
+}
+
+/* Pass -- optimize outputs
+ * Mesa tends to generate code like this at the end if their shaders
+ *   MOV OUT[1], TEMP[2]
+ *   MOV OUT[0], TEMP[0]
+ *   MOV OUT[2], TEMP[1]
+ * Recognize if
+ * a) there is only a single assignment to an output register and
+ * b) the temporary is not used after that
+ * Also recognize direct assignment of IN to OUT (passthrough)
+ **/
+static void
+etna_compile_pass_optimize_outputs(struct etna_compile *c)
+{
+   struct tgsi_parse_context ctx = { };
+   int inst_idx = 0;
+   unsigned status = TGSI_PARSE_OK;
+   status = tgsi_parse_init(&ctx, c->tokens);
+   assert(status == TGSI_PARSE_OK);
+
+   while (!tgsi_parse_end_of_tokens(&ctx)) {
+      tgsi_parse_token(&ctx);
+
+      switch (ctx.FullToken.Token.Type) {
+      case TGSI_TOKEN_TYPE_INSTRUCTION: {
+         const struct tgsi_full_instruction *inst = &ctx.FullToken.FullInstruction;
+
+         /* iterate over operands */
+         switch (inst->Instruction.Opcode) {
+         case TGSI_OPCODE_MOV: {
+            /* We are only interested in eliminating MOVs which write to
+             * the shader outputs. Test for this early. */
+            if (inst->Dst[0].Register.File != TGSI_FILE_OUTPUT)
+               break;
+            /* Elimination of a MOV must have no visible effect on the
+             * resulting shader: this means the MOV must not swizzle or
+             * saturate, and its source must not have the negate or
+             * absolute modifiers. */
+            if (!etna_mov_check_no_swizzle(inst->Dst[0].Register, inst->Src[0].Register) ||
+                inst->Instruction.Saturate || inst->Src[0].Register.Negate ||
+                inst->Src[0].Register.Absolute)
+               break;
+
+            uint out_idx = inst->Dst[0].Register.Index;
+            uint in_idx = inst->Src[0].Register.Index;
+            /* assignment of temporary to output --
+             * and the output doesn't yet have a native register assigned
+             * and the last use of the temporary is this instruction
+             * and the MOV does not do a swizzle
+             */
+            if (inst->Src[0].Register.File == TGSI_FILE_TEMPORARY &&
+                !c->file[TGSI_FILE_OUTPUT].reg[out_idx].native.valid &&
+                c->file[TGSI_FILE_TEMPORARY].reg[in_idx].last_use == inst_idx) {
+               c->file[TGSI_FILE_OUTPUT].reg[out_idx].native =
+                  c->file[TGSI_FILE_TEMPORARY].reg[in_idx].native;
+               /* prevent temp from being re-used for the rest of the shader */
+               c->file[TGSI_FILE_TEMPORARY].reg[in_idx].last_use = ETNA_MAX_TOKENS;
+               /* mark this MOV instruction as a no-op */
+               c->dead_inst[inst_idx] = true;
+            }
+            /* direct assignment of input to output --
+             * and the input or output doesn't yet have a native register
+             * assigned
+             * and the output is only used in this instruction,
+             * allocate a new register, and associate both input and output to
+             * it
+             * and the MOV does not do a swizzle
+             */
+            if (inst->Src[0].Register.File == TGSI_FILE_INPUT &&
+                !c->file[TGSI_FILE_INPUT].reg[in_idx].native.valid &&
+                !c->file[TGSI_FILE_OUTPUT].reg[out_idx].native.valid &&
+                c->file[TGSI_FILE_OUTPUT].reg[out_idx].last_use == inst_idx &&
+                c->file[TGSI_FILE_OUTPUT].reg[out_idx].first_use == inst_idx) {
+               c->file[TGSI_FILE_OUTPUT].reg[out_idx].native =
+                  c->file[TGSI_FILE_INPUT].reg[in_idx].native =
+                     alloc_new_native_reg(c);
+               /* mark this MOV instruction as a no-op */
+               c->dead_inst[inst_idx] = true;
+            }
+         } break;
+         default:;
+         }
+         inst_idx += 1;
+      } break;
+      }
+   }
+
+   tgsi_parse_free(&ctx);
+}
+
+/* Get a temporary to be used within one TGSI instruction.
+ * The first time that this function is called the temporary will be allocated.
+ * Each call to this function will return the same temporary.
+ */
+static struct etna_native_reg
+etna_compile_get_inner_temp(struct etna_compile *c)
+{
+   int inner_temp = c->inner_temps;
+
+   if (inner_temp < ETNA_MAX_INNER_TEMPS) {
+      if (!c->inner_temp[inner_temp].valid)
+         c->inner_temp[inner_temp] = alloc_new_native_reg(c);
+
+      /* alloc_new_native_reg() handles lack of registers */
+      c->inner_temps += 1;
+   } else {
+      BUG("Too many inner temporaries (%i) requested in one instruction",
+          inner_temp + 1);
+   }
+
+   return c->inner_temp[inner_temp];
+}
+
+static struct etna_inst_dst
+etna_native_to_dst(struct etna_native_reg native, unsigned comps)
+{
+   /* Can only assign to temporaries */
+   assert(native.valid && !native.is_tex && native.rgroup == INST_RGROUP_TEMP);
+
+   struct etna_inst_dst rv = {
+      .comps = comps,
+      .use = 1,
+      .reg = native.id,
+   };
+
+   return rv;
+}
+
+static struct etna_inst_src
+etna_native_to_src(struct etna_native_reg native, uint32_t swizzle)
+{
+   assert(native.valid && !native.is_tex);
+
+   struct etna_inst_src rv = {
+      .use = 1,
+      .swiz = swizzle,
+      .rgroup = native.rgroup,
+      .reg = native.id,
+      .amode = INST_AMODE_DIRECT,
+   };
+
+   return rv;
+}
+
+static inline struct etna_inst_src
+negate(struct etna_inst_src src)
+{
+   src.neg = !src.neg;
+
+   return src;
+}
+
+static inline struct etna_inst_src
+absolute(struct etna_inst_src src)
+{
+   src.abs = 1;
+
+   return src;
+}
+
+static inline struct etna_inst_src
+swizzle(struct etna_inst_src src, unsigned swizzle)
+{
+   src.swiz = inst_swiz_compose(src.swiz, swizzle);
+
+   return src;
+}
+
+/* Emit instruction and append it to program */
+static void
+emit_inst(struct etna_compile *c, struct etna_inst *inst)
+{
+   assert(c->inst_ptr <= ETNA_MAX_INSTRUCTIONS);
+
+   /* Check for uniform conflicts (each instruction can only access one
+    * uniform),
+    * if detected, use an intermediate temporary */
+   unsigned uni_rgroup = -1;
+   unsigned uni_reg = -1;
+
+   for (int src = 0; src < ETNA_NUM_SRC; ++src) {
+      if (etna_rgroup_is_uniform(inst->src[src].rgroup)) {
+         if (uni_reg == -1) { /* first unique uniform used */
+            uni_rgroup = inst->src[src].rgroup;
+            uni_reg = inst->src[src].reg;
+         } else { /* second or later; check that it is a re-use */
+            if (uni_rgroup != inst->src[src].rgroup ||
+                uni_reg != inst->src[src].reg) {
+               DBG_F(ETNA_DBG_COMPILER_MSGS, "perf warning: instruction that "
+                                             "accesses different uniforms, "
+                                             "need to generate extra MOV");
+               struct etna_native_reg inner_temp = etna_compile_get_inner_temp(c);
+
+               /* Generate move instruction to temporary */
+               etna_assemble(&c->code[c->inst_ptr * 4], &(struct etna_inst) {
+                  .opcode = INST_OPCODE_MOV,
+                  .dst = etna_native_to_dst(inner_temp, INST_COMPS_X | INST_COMPS_Y |
+                                                        INST_COMPS_Z | INST_COMPS_W),
+                  .src[2] = inst->src[src]
+               });
+
+               c->inst_ptr++;
+
+               /* Modify instruction to use temp register instead of uniform */
+               inst->src[src].use = 1;
+               inst->src[src].rgroup = INST_RGROUP_TEMP;
+               inst->src[src].reg = inner_temp.id;
+               inst->src[src].swiz = INST_SWIZ_IDENTITY; /* swizzling happens on MOV */
+               inst->src[src].neg = 0; /* negation happens on MOV */
+               inst->src[src].abs = 0; /* abs happens on MOV */
+               inst->src[src].amode = 0; /* amode effects happen on MOV */
+            }
+         }
+      }
+   }
+
+   /* Finally assemble the actual instruction */
+   etna_assemble(&c->code[c->inst_ptr * 4], inst);
+   c->inst_ptr++;
+}
+
+static unsigned int
+etna_amode(struct tgsi_ind_register indirect)
+{
+   assert(indirect.File == TGSI_FILE_ADDRESS);
+   assert(indirect.Index == 0);
+
+   switch (indirect.Swizzle) {
+   case TGSI_SWIZZLE_X:
+      return INST_AMODE_ADD_A_X;
+   case TGSI_SWIZZLE_Y:
+      return INST_AMODE_ADD_A_Y;
+   case TGSI_SWIZZLE_Z:
+      return INST_AMODE_ADD_A_Z;
+   case TGSI_SWIZZLE_W:
+      return INST_AMODE_ADD_A_W;
+   default:
+      assert(!"Invalid swizzle");
+   }
+}
+
+/* convert destination operand */
+static struct etna_inst_dst
+convert_dst(struct etna_compile *c, const struct tgsi_full_dst_register *in)
+{
+   struct etna_inst_dst rv = {
+      /// XXX .amode
+      .comps = in->Register.WriteMask,
+   };
+
+   if (in->Register.File == TGSI_FILE_ADDRESS) {
+      assert(in->Register.Index == 0);
+      rv.reg = in->Register.Index;
+      rv.use = 0;
+   } else {
+      rv = etna_native_to_dst(etna_get_dst_reg(c, in->Register)->native,
+                              in->Register.WriteMask);
+   }
+
+   if (in->Register.Indirect)
+      rv.amode = etna_amode(in->Indirect);
+
+   return rv;
+}
+
+/* convert texture operand */
+static struct etna_inst_tex
+convert_tex(struct etna_compile *c, const struct tgsi_full_src_register *in,
+            const struct tgsi_instruction_texture *tex)
+{
+   struct etna_native_reg native_reg = etna_get_src_reg(c, in->Register)->native;
+   struct etna_inst_tex rv = {
+      // XXX .amode (to allow for an array of samplers?)
+      .swiz = INST_SWIZ_IDENTITY
+   };
+
+   assert(native_reg.is_tex && native_reg.valid);
+   rv.id = native_reg.id;
+
+   return rv;
+}
+
+/* convert source operand */
+static struct etna_inst_src
+etna_create_src(const struct tgsi_full_src_register *tgsi,
+                const struct etna_native_reg *native)
+{
+   const struct tgsi_src_register *reg = &tgsi->Register;
+   struct etna_inst_src rv = {
+      .use = 1,
+      .swiz = INST_SWIZ(reg->SwizzleX, reg->SwizzleY, reg->SwizzleZ, reg->SwizzleW),
+      .neg = reg->Negate,
+      .abs = reg->Absolute,
+      .rgroup = native->rgroup,
+      .reg = native->id,
+      .amode = INST_AMODE_DIRECT,
+   };
+
+   assert(native->valid && !native->is_tex);
+
+   if (reg->Indirect)
+      rv.amode = etna_amode(tgsi->Indirect);
+
+   return rv;
+}
+
+static struct etna_inst_src
+etna_mov_src_to_temp(struct etna_compile *c, struct etna_inst_src src,
+                     struct etna_native_reg temp)
+{
+   struct etna_inst mov = { };
+
+   mov.opcode = INST_OPCODE_MOV;
+   mov.sat = 0;
+   mov.dst = etna_native_to_dst(temp, INST_COMPS_X | INST_COMPS_Y |
+                                      INST_COMPS_Z | INST_COMPS_W);
+   mov.src[2] = src;
+   emit_inst(c, &mov);
+
+   src.swiz = INST_SWIZ_IDENTITY;
+   src.neg = src.abs = 0;
+   src.rgroup = temp.rgroup;
+   src.reg = temp.id;
+
+   return src;
+}
+
+static struct etna_inst_src
+etna_mov_src(struct etna_compile *c, struct etna_inst_src src)
+{
+   struct etna_native_reg temp = etna_compile_get_inner_temp(c);
+
+   return etna_mov_src_to_temp(c, src, temp);
+}
+
+static bool
+etna_src_uniforms_conflict(struct etna_inst_src a, struct etna_inst_src b)
+{
+   return etna_rgroup_is_uniform(a.rgroup) &&
+          etna_rgroup_is_uniform(b.rgroup) &&
+          (a.rgroup != b.rgroup || a.reg != b.reg);
+}
+
+/* create a new label */
+static struct etna_compile_label *
+alloc_new_label(struct etna_compile *c)
+{
+   struct etna_compile_label label = {
+      .inst_idx = -1, /* start by point to no specific instruction */
+   };
+
+   array_insert(c->labels, label);
+
+   return &c->labels[c->labels_count - 1];
+}
+
+/* place label at current instruction pointer */
+static void
+label_place(struct etna_compile *c, struct etna_compile_label *label)
+{
+   label->inst_idx = c->inst_ptr;
+}
+
+/* mark label use at current instruction.
+ * target of the label will be filled in in the marked instruction's src2.imm
+ * slot as soon
+ * as the value becomes known.
+ */
+static void
+label_mark_use(struct etna_compile *c, struct etna_compile_label *label)
+{
+   assert(c->inst_ptr < ETNA_MAX_INSTRUCTIONS);
+   c->lbl_usage[c->inst_ptr] = label;
+}
+
+/* walk the frame stack and return first frame with matching type */
+static struct etna_compile_frame *
+find_frame(struct etna_compile *c, enum etna_compile_frame_type type)
+{
+   for (unsigned sp = c->frame_sp; sp >= 0; sp--)
+      if (c->frame_stack[sp].type == type)
+         return &c->frame_stack[sp];
+
+   assert(0);
+   return NULL;
+}
+
+struct instr_translater {
+   void (*fxn)(const struct instr_translater *t, struct etna_compile *c,
+               const struct tgsi_full_instruction *inst,
+               struct etna_inst_src *src);
+   unsigned tgsi_opc;
+   uint8_t opc;
+
+   /* tgsi src -> etna src swizzle */
+   int src[3];
+
+   unsigned cond;
+};
+
+static void
+trans_instr(const struct instr_translater *t, struct etna_compile *c,
+            const struct tgsi_full_instruction *inst, struct etna_inst_src *src)
+{
+   const struct tgsi_opcode_info *info = tgsi_get_opcode_info(inst->Instruction.Opcode);
+   struct etna_inst instr = { };
+
+   instr.opcode = t->opc;
+   instr.cond = t->cond;
+   instr.sat = inst->Instruction.Saturate;
+
+   assert(info->num_dst <= 1);
+   if (info->num_dst)
+      instr.dst = convert_dst(c, &inst->Dst[0]);
+
+   assert(info->num_src <= ETNA_NUM_SRC);
+
+   for (unsigned i = 0; i < info->num_src; i++) {
+      int swizzle = t->src[i];
+
+      assert(swizzle != -1);
+      instr.src[swizzle] = src[i];
+   }
+
+   emit_inst(c, &instr);
+}
+
+static void
+trans_min_max(const struct instr_translater *t, struct etna_compile *c,
+              const struct tgsi_full_instruction *inst,
+              struct etna_inst_src *src)
+{
+   emit_inst(c, &(struct etna_inst) {
+      .opcode = INST_OPCODE_SELECT,
+       .cond = t->cond,
+       .sat = inst->Instruction.Saturate,
+       .dst = convert_dst(c, &inst->Dst[0]),
+       .src[0] = src[0],
+       .src[1] = src[1],
+       .src[2] = src[0],
+    });
+}
+
+static void
+trans_if(const struct instr_translater *t, struct etna_compile *c,
+         const struct tgsi_full_instruction *inst, struct etna_inst_src *src)
+{
+   struct etna_compile_frame *f = &c->frame_stack[c->frame_sp++];
+   struct etna_inst_src imm_0 = alloc_imm_f32(c, 0.0f);
+
+   /* push IF to stack */
+   f->type = ETNA_COMPILE_FRAME_IF;
+   /* create "else" label */
+   f->lbl_else = alloc_new_label(c);
+   f->lbl_endif = NULL;
+
+   /* We need to avoid the emit_inst() below becoming two instructions */
+   if (etna_src_uniforms_conflict(src[0], imm_0))
+      src[0] = etna_mov_src(c, src[0]);
+
+   /* mark position in instruction stream of label reference so that it can be
+    * filled in in next pass */
+   label_mark_use(c, f->lbl_else);
+
+   /* create conditional branch to label if src0 EQ 0 */
+   emit_inst(c, &(struct etna_inst){
+      .opcode = INST_OPCODE_BRANCH,
+      .cond = INST_CONDITION_EQ,
+      .src[0] = src[0],
+      .src[1] = imm_0,
+    /* imm is filled in later */
+   });
+}
+
+static void
+trans_else(const struct instr_translater *t, struct etna_compile *c,
+           const struct tgsi_full_instruction *inst, struct etna_inst_src *src)
+{
+   assert(c->frame_sp > 0);
+   struct etna_compile_frame *f = &c->frame_stack[c->frame_sp - 1];
+   assert(f->type == ETNA_COMPILE_FRAME_IF);
+
+   /* create "endif" label, and branch to endif label */
+   f->lbl_endif = alloc_new_label(c);
+   label_mark_use(c, f->lbl_endif);
+   emit_inst(c, &(struct etna_inst) {
+      .opcode = INST_OPCODE_BRANCH,
+      .cond = INST_CONDITION_TRUE,
+      /* imm is filled in later */
+   });
+
+   /* mark "else" label at this position in instruction stream */
+   label_place(c, f->lbl_else);
+}
+
+static void
+trans_endif(const struct instr_translater *t, struct etna_compile *c,
+            const struct tgsi_full_instruction *inst, struct etna_inst_src *src)
+{
+   assert(c->frame_sp > 0);
+   struct etna_compile_frame *f = &c->frame_stack[--c->frame_sp];
+   assert(f->type == ETNA_COMPILE_FRAME_IF);
+
+   /* assign "endif" or "else" (if no ELSE) label to current position in
+    * instruction stream, pop IF */
+   if (f->lbl_endif != NULL)
+      label_place(c, f->lbl_endif);
+   else
+      label_place(c, f->lbl_else);
+}
+
+static void
+trans_loop_bgn(const struct instr_translater *t, struct etna_compile *c,
+               const struct tgsi_full_instruction *inst,
+               struct etna_inst_src *src)
+{
+   struct etna_compile_frame *f = &c->frame_stack[c->frame_sp++];
+
+   /* push LOOP to stack */
+   f->type = ETNA_COMPILE_FRAME_LOOP;
+   f->lbl_loop_bgn = alloc_new_label(c);
+   f->lbl_loop_end = alloc_new_label(c);
+
+   label_place(c, f->lbl_loop_bgn);
+}
+
+static void
+trans_loop_end(const struct instr_translater *t, struct etna_compile *c,
+               const struct tgsi_full_instruction *inst,
+               struct etna_inst_src *src)
+{
+   assert(c->frame_sp > 0);
+   struct etna_compile_frame *f = &c->frame_stack[--c->frame_sp];
+   assert(f->type == ETNA_COMPILE_FRAME_LOOP);
+
+   /* mark position in instruction stream of label reference so that it can be
+    * filled in in next pass */
+   label_mark_use(c, f->lbl_loop_bgn);
+
+   /* create branch to loop_bgn label */
+   emit_inst(c, &(struct etna_inst) {
+      .opcode = INST_OPCODE_BRANCH,
+      .cond = INST_CONDITION_TRUE,
+      .src[0] = src[0],
+      /* imm is filled in later */
+   });
+
+   label_place(c, f->lbl_loop_end);
+}
+
+static void
+trans_brk(const struct instr_translater *t, struct etna_compile *c,
+          const struct tgsi_full_instruction *inst, struct etna_inst_src *src)
+{
+   assert(c->frame_sp > 0);
+   struct etna_compile_frame *f = find_frame(c, ETNA_COMPILE_FRAME_LOOP);
+
+   /* mark position in instruction stream of label reference so that it can be
+    * filled in in next pass */
+   label_mark_use(c, f->lbl_loop_end);
+
+   /* create branch to loop_end label */
+   emit_inst(c, &(struct etna_inst) {
+      .opcode = INST_OPCODE_BRANCH,
+      .cond = INST_CONDITION_TRUE,
+      .src[0] = src[0],
+      /* imm is filled in later */
+   });
+}
+
+static void
+trans_cont(const struct instr_translater *t, struct etna_compile *c,
+           const struct tgsi_full_instruction *inst, struct etna_inst_src *src)
+{
+   assert(c->frame_sp > 0);
+   struct etna_compile_frame *f = find_frame(c, ETNA_COMPILE_FRAME_LOOP);
+
+   /* mark position in instruction stream of label reference so that it can be
+    * filled in in next pass */
+   label_mark_use(c, f->lbl_loop_bgn);
+
+   /* create branch to loop_end label */
+   emit_inst(c, &(struct etna_inst) {
+      .opcode = INST_OPCODE_BRANCH,
+      .cond = INST_CONDITION_TRUE,
+      .src[0] = src[0],
+      /* imm is filled in later */
+   });
+}
+
+static void
+trans_deriv(const struct instr_translater *t, struct etna_compile *c,
+            const struct tgsi_full_instruction *inst, struct etna_inst_src *src)
+{
+   emit_inst(c, &(struct etna_inst) {
+      .opcode = t->opc,
+      .sat = inst->Instruction.Saturate,
+      .dst = convert_dst(c, &inst->Dst[0]),
+      .src[0] = src[0],
+      .src[2] = src[0],
+   });
+}
+
+static void
+trans_arl(const struct instr_translater *t, struct etna_compile *c,
+          const struct tgsi_full_instruction *inst, struct etna_inst_src *src)
+{
+   struct etna_native_reg temp = etna_compile_get_inner_temp(c);
+   struct etna_inst arl = { };
+   struct etna_inst_dst dst;
+
+   dst = etna_native_to_dst(temp, INST_COMPS_X | INST_COMPS_Y | INST_COMPS_Z |
+                                  INST_COMPS_W);
+
+   if (c->specs->has_sign_floor_ceil) {
+      struct etna_inst floor = { };
+
+      floor.opcode = INST_OPCODE_FLOOR;
+      floor.src[2] = src[0];
+      floor.dst = dst;
+
+      emit_inst(c, &floor);
+   } else {
+      struct etna_inst floor[2] = { };
+
+      floor[0].opcode = INST_OPCODE_FRC;
+      floor[0].sat = inst->Instruction.Saturate;
+      floor[0].dst = dst;
+      floor[0].src[2] = src[0];
+
+      floor[1].opcode = INST_OPCODE_ADD;
+      floor[1].sat = inst->Instruction.Saturate;
+      floor[1].dst = dst;
+      floor[1].src[0] = src[0];
+      floor[1].src[2].use = 1;
+      floor[1].src[2].swiz = INST_SWIZ_IDENTITY;
+      floor[1].src[2].neg = 1;
+      floor[1].src[2].rgroup = temp.rgroup;
+      floor[1].src[2].reg = temp.id;
+
+      emit_inst(c, &floor[0]);
+      emit_inst(c, &floor[1]);
+   }
+
+   arl.opcode = INST_OPCODE_MOVAR;
+   arl.sat = inst->Instruction.Saturate;
+   arl.dst = convert_dst(c, &inst->Dst[0]);
+   arl.src[2] = etna_native_to_src(temp, INST_SWIZ_IDENTITY);
+
+   emit_inst(c, &arl);
+}
+
+static void
+trans_lrp(const struct instr_translater *t, struct etna_compile *c,
+          const struct tgsi_full_instruction *inst, struct etna_inst_src *src)
+{
+   /* dst = src0 * src1 + (1 - src0) * src2
+    *     => src0 * src1 - (src0 - 1) * src2
+    *     => src0 * src1 - (src0 * src2 - src2)
+    * MAD tTEMP.xyzw, tSRC0.xyzw, tSRC2.xyzw, -tSRC2.xyzw
+    * MAD tDST.xyzw, tSRC0.xyzw, tSRC1.xyzw, -tTEMP.xyzw
+    */
+   struct etna_native_reg temp = etna_compile_get_inner_temp(c);
+   if (etna_src_uniforms_conflict(src[0], src[1]) ||
+       etna_src_uniforms_conflict(src[0], src[2])) {
+      src[0] = etna_mov_src(c, src[0]);
+   }
+
+   struct etna_inst mad[2] = { };
+   mad[0].opcode = INST_OPCODE_MAD;
+   mad[0].sat = 0;
+   mad[0].dst = etna_native_to_dst(temp, INST_COMPS_X | INST_COMPS_Y |
+                                         INST_COMPS_Z | INST_COMPS_W);
+   mad[0].src[0] = src[0];
+   mad[0].src[1] = src[2];
+   mad[0].src[2] = negate(src[2]);
+   mad[1].opcode = INST_OPCODE_MAD;
+   mad[1].sat = inst->Instruction.Saturate;
+   mad[1].dst = convert_dst(c, &inst->Dst[0]), mad[1].src[0] = src[0];
+   mad[1].src[1] = src[1];
+   mad[1].src[2] = negate(etna_native_to_src(temp, INST_SWIZ_IDENTITY));
+
+   emit_inst(c, &mad[0]);
+   emit_inst(c, &mad[1]);
+}
+
+static void
+trans_sub(const struct instr_translater *t, struct etna_compile *c,
+          const struct tgsi_full_instruction *inst, struct etna_inst_src *src)
+{
+   struct etna_inst inst_out = {
+      .opcode = INST_OPCODE_ADD,
+      .sat = inst->Instruction.Saturate,
+      .dst = convert_dst(c, &inst->Dst[0]),
+      .src[0] = src[0],
+      .src[2] = src[1],
+   };
+
+   inst_out.src[2].neg = !inst_out.src[2].neg;
+   emit_inst(c, &inst_out);
+}
+
+static void
+trans_abs(const struct instr_translater *t, struct etna_compile *c,
+          const struct tgsi_full_instruction *inst, struct etna_inst_src *src)
+{
+   /* XXX can be propagated into uses of destination operand */
+   src[0].abs = 1;
+   emit_inst(c, &(struct etna_inst) {
+      .opcode = INST_OPCODE_MOV,
+      .sat = inst->Instruction.Saturate,
+      .dst = convert_dst(c, &inst->Dst[0]),
+      .src[2] = src[0],
+   });
+}
+
+static void
+trans_lit(const struct instr_translater *t, struct etna_compile *c,
+          const struct tgsi_full_instruction *inst, struct etna_inst_src *src)
+{
+   /* SELECT.LT tmp._y__, 0, src.yyyy, 0
+    *  - can be eliminated if src.y is a uniform and >= 0
+    * SELECT.GT tmp.___w, 128, src.wwww, 128
+    * SELECT.LT tmp.___w, -128, tmp.wwww, -128
+    *  - can be eliminated if src.w is a uniform and fits clamp
+    * LOG tmp.x, void, void, tmp.yyyy
+    * MUL tmp.x, tmp.xxxx, tmp.wwww, void
+    * LITP dst, undef, src.xxxx, tmp.xxxx
+    */
+   struct etna_native_reg inner_temp = etna_compile_get_inner_temp(c);
+   struct etna_inst_src src_y = { };
+
+   if (!etna_rgroup_is_uniform(src[0].rgroup)) {
+      src_y = etna_native_to_src(inner_temp, SWIZZLE(Y, Y, Y, Y));
+
+      struct etna_inst ins = { };
+      ins.opcode = INST_OPCODE_SELECT;
+      ins.cond = INST_CONDITION_LT;
+      ins.dst = etna_native_to_dst(inner_temp, INST_COMPS_Y);
+      ins.src[0] = ins.src[2] = alloc_imm_f32(c, 0.0);
+      ins.src[1] = swizzle(src[0], SWIZZLE(Y, Y, Y, Y));
+      emit_inst(c, &ins);
+   } else if (uif(get_imm_u32(c, &src[0], 1)) < 0)
+      src_y = alloc_imm_f32(c, 0.0);
+   else
+      src_y = swizzle(src[0], SWIZZLE(Y, Y, Y, Y));
+
+   struct etna_inst_src src_w = { };
+
+   if (!etna_rgroup_is_uniform(src[0].rgroup)) {
+      src_w = etna_native_to_src(inner_temp, SWIZZLE(W, W, W, W));
+
+      struct etna_inst ins = { };
+      ins.opcode = INST_OPCODE_SELECT;
+      ins.cond = INST_CONDITION_GT;
+      ins.dst = etna_native_to_dst(inner_temp, INST_COMPS_W);
+      ins.src[0] = ins.src[2] = alloc_imm_f32(c, 128.);
+      ins.src[1] = swizzle(src[0], SWIZZLE(W, W, W, W));
+      emit_inst(c, &ins);
+      ins.cond = INST_CONDITION_LT;
+      ins.src[0].neg = !ins.src[0].neg;
+      ins.src[2].neg = !ins.src[2].neg;
+      ins.src[1] = src_w;
+      emit_inst(c, &ins);
+   } else if (uif(get_imm_u32(c, &src[0], 3)) < -128.)
+      src_w = alloc_imm_f32(c, -128.);
+   else if (uif(get_imm_u32(c, &src[0], 3)) > 128.)
+      src_w = alloc_imm_f32(c, 128.);
+   else
+      src_w = swizzle(src[0], SWIZZLE(W, W, W, W));
+
+   struct etna_inst ins[3] = { };
+   ins[0].opcode = INST_OPCODE_LOG;
+   ins[0].dst = etna_native_to_dst(inner_temp, INST_COMPS_X);
+   ins[0].src[2] = src_y;
+
+   emit_inst(c, &ins[0]);
+   emit_inst(c, &(struct etna_inst) {
+      .opcode = INST_OPCODE_MUL,
+      .sat = 0,
+      .dst = etna_native_to_dst(inner_temp, INST_COMPS_X),
+      .src[0] = etna_native_to_src(inner_temp, SWIZZLE(X, X, X, X)),
+      .src[1] = src_w,
+   });
+   emit_inst(c, &(struct etna_inst) {
+      .opcode = INST_OPCODE_LITP,
+      .sat = 0,
+      .dst = convert_dst(c, &inst->Dst[0]),
+      .src[0] = swizzle(src[0], SWIZZLE(X, X, X, X)),
+      .src[1] = swizzle(src[0], SWIZZLE(X, X, X, X)),
+      .src[2] = etna_native_to_src(inner_temp, SWIZZLE(X, X, X, X)),
+   });
+}
+
+static void
+trans_ssg(const struct instr_translater *t, struct etna_compile *c,
+          const struct tgsi_full_instruction *inst, struct etna_inst_src *src)
+{
+   if (c->specs->has_sign_floor_ceil) {
+      emit_inst(c, &(struct etna_inst){
+         .opcode = INST_OPCODE_SIGN,
+         .sat = inst->Instruction.Saturate,
+         .dst = convert_dst(c, &inst->Dst[0]),
+         .src[2] = src[0],
+      });
+   } else {
+      struct etna_native_reg temp = etna_compile_get_inner_temp(c);
+      struct etna_inst ins[2] = { };
+
+      ins[0].opcode = INST_OPCODE_SET;
+      ins[0].cond = INST_CONDITION_NZ;
+      ins[0].dst = etna_native_to_dst(temp, INST_COMPS_X | INST_COMPS_Y |
+                                            INST_COMPS_Z | INST_COMPS_W);
+      ins[0].src[0] = src[0];
+
+      ins[1].opcode = INST_OPCODE_SELECT;
+      ins[1].cond = INST_CONDITION_LZ;
+      ins[1].sat = inst->Instruction.Saturate;
+      ins[1].dst = convert_dst(c, &inst->Dst[0]);
+      ins[1].src[0] = src[0];
+      ins[1].src[2] = etna_native_to_src(temp, INST_SWIZ_IDENTITY);
+      ins[1].src[1] = negate(ins[1].src[2]);
+
+      emit_inst(c, &ins[0]);
+      emit_inst(c, &ins[1]);
+   }
+}
+
+static void
+trans_trig(const struct instr_translater *t, struct etna_compile *c,
+           const struct tgsi_full_instruction *inst, struct etna_inst_src *src)
+{
+   if (c->specs->has_sin_cos_sqrt) {
+      /* TGSI lowering should deal with SCS */
+      assert(inst->Instruction.Opcode != TGSI_OPCODE_SCS);
+
+      struct etna_native_reg temp = etna_compile_get_inner_temp(c);
+      /* add divide by PI/2, using a temp register. GC2000
+       * fails with src==dst for the trig instruction. */
+      emit_inst(c, &(struct etna_inst) {
+         .opcode = INST_OPCODE_MUL,
+         .sat = 0,
+         .dst = etna_native_to_dst(temp, INST_COMPS_X | INST_COMPS_Y |
+                                         INST_COMPS_Z | INST_COMPS_W),
+         .src[0] = src[0], /* any swizzling happens here */
+         .src[1] = alloc_imm_f32(c, 2.0f / M_PI),
+      });
+      emit_inst(c, &(struct etna_inst) {
+         .opcode = inst->Instruction.Opcode == TGSI_OPCODE_COS
+                    ? INST_OPCODE_COS
+                    : INST_OPCODE_SIN,
+         .sat = inst->Instruction.Saturate,
+         .dst = convert_dst(c, &inst->Dst[0]),
+         .src[2] = etna_native_to_src(temp, INST_SWIZ_IDENTITY),
+      });
+   } else {
+      /* Implement Nick's fast sine/cosine. Taken from:
+       * http://forum.devmaster.net/t/fast-and-accurate-sine-cosine/9648
+       * A=(1/2*PI 0 1/2*PI 0) B=(0.75 0 0.5 0) C=(-4 4 X X)
+       *  MAD t.x_zw, src.xxxx, A, B
+       *  FRC t.x_z_, void, void, t.xwzw
+       *  MAD t.x_z_, t.xwzw, 2, -1
+       *  MUL t._y__, t.wzww, |t.wzww|, void  (for sin/scs)
+       *  DP3 t.x_z_, t.zyww, C, void         (for sin)
+       *  DP3 t.__z_, t.zyww, C, void         (for scs)
+       *  MUL t._y__, t.wxww, |t.wxww|, void  (for cos/scs)
+       *  DP3 t.x_z_, t.xyww, C, void         (for cos)
+       *  DP3 t.x___, t.xyww, C, void         (for scs)
+       *  MAD t._y_w, t,xxzz, |t.xxzz|, -t.xxzz
+       *  MAD dst, t.ywyw, .2225, t.xzxz
+       *
+       * TODO: we don't set dst.zw correctly for SCS.
+       */
+      struct etna_inst *p, ins[9] = { };
+      struct etna_native_reg t0 = etna_compile_get_inner_temp(c);
+      struct etna_inst_src t0s = etna_native_to_src(t0, INST_SWIZ_IDENTITY);
+      struct etna_inst_src sincos[3], in = src[0];
+      sincos[0] = etna_imm_vec4f(c, sincos_const[0]);
+      sincos[1] = etna_imm_vec4f(c, sincos_const[1]);
+
+      /* A uniform source will cause the inner temp limit to
+       * be exceeded.  Explicitly deal with that scenario.
+       */
+      if (etna_rgroup_is_uniform(src[0].rgroup)) {
+         struct etna_inst ins = { };
+         ins.opcode = INST_OPCODE_MOV;
+         ins.dst = etna_native_to_dst(t0, INST_COMPS_X);
+         ins.src[2] = in;
+         emit_inst(c, &ins);
+         in = t0s;
+      }
+
+      ins[0].opcode = INST_OPCODE_MAD;
+      ins[0].dst = etna_native_to_dst(t0, INST_COMPS_X | INST_COMPS_Z | INST_COMPS_W);
+      ins[0].src[0] = swizzle(in, SWIZZLE(X, X, X, X));
+      ins[0].src[1] = swizzle(sincos[1], SWIZZLE(X, W, X, W)); /* 1/2*PI */
+      ins[0].src[2] = swizzle(sincos[1], SWIZZLE(Y, W, Z, W)); /* 0.75, 0, 0.5, 0 */
+
+      ins[1].opcode = INST_OPCODE_FRC;
+      ins[1].dst = etna_native_to_dst(t0, INST_COMPS_X | INST_COMPS_Z);
+      ins[1].src[2] = swizzle(t0s, SWIZZLE(X, W, Z, W));
+
+      ins[2].opcode = INST_OPCODE_MAD;
+      ins[2].dst = etna_native_to_dst(t0, INST_COMPS_X | INST_COMPS_Z);
+      ins[2].src[0] = swizzle(t0s, SWIZZLE(X, W, Z, W));
+      ins[2].src[1] = swizzle(sincos[0], SWIZZLE(X, X, X, X)); /* 2 */
+      ins[2].src[2] = swizzle(sincos[0], SWIZZLE(Y, Y, Y, Y)); /* -1 */
+
+      unsigned mul_swiz, dp3_swiz;
+      if (inst->Instruction.Opcode == TGSI_OPCODE_SIN) {
+         mul_swiz = SWIZZLE(W, Z, W, W);
+         dp3_swiz = SWIZZLE(Z, Y, W, W);
+      } else {
+         mul_swiz = SWIZZLE(W, X, W, W);
+         dp3_swiz = SWIZZLE(X, Y, W, W);
+      }
+
+      ins[3].opcode = INST_OPCODE_MUL;
+      ins[3].dst = etna_native_to_dst(t0, INST_COMPS_Y);
+      ins[3].src[0] = swizzle(t0s, mul_swiz);
+      ins[3].src[1] = absolute(ins[3].src[0]);
+
+      ins[4].opcode = INST_OPCODE_DP3;
+      ins[4].dst = etna_native_to_dst(t0, INST_COMPS_X | INST_COMPS_Z);
+      ins[4].src[0] = swizzle(t0s, dp3_swiz);
+      ins[4].src[1] = swizzle(sincos[0], SWIZZLE(Z, W, W, W));
+
+      if (inst->Instruction.Opcode == TGSI_OPCODE_SCS) {
+         ins[5] = ins[3];
+         ins[6] = ins[4];
+         ins[4].dst.comps = INST_COMPS_X;
+         ins[6].dst.comps = INST_COMPS_Z;
+         ins[5].src[0] = swizzle(t0s, SWIZZLE(W, Z, W, W));
+         ins[6].src[0] = swizzle(t0s, SWIZZLE(Z, Y, W, W));
+         ins[5].src[1] = absolute(ins[5].src[0]);
+         p = &ins[7];
+      } else {
+         p = &ins[5];
+      }
+
+      p->opcode = INST_OPCODE_MAD;
+      p->dst = etna_native_to_dst(t0, INST_COMPS_Y | INST_COMPS_W);
+      p->src[0] = swizzle(t0s, SWIZZLE(X, X, Z, Z));
+      p->src[1] = absolute(p->src[0]);
+      p->src[2] = negate(p->src[0]);
+
+      p++;
+      p->opcode = INST_OPCODE_MAD;
+      p->sat = inst->Instruction.Saturate;
+      p->dst = convert_dst(c, &inst->Dst[0]),
+      p->src[0] = swizzle(t0s, SWIZZLE(Y, W, Y, W));
+      p->src[1] = alloc_imm_f32(c, 0.2225);
+      p->src[2] = swizzle(t0s, SWIZZLE(X, Z, X, Z));
+
+      for (int i = 0; &ins[i] <= p; i++)
+         emit_inst(c, &ins[i]);
+   }
+}
+
+static void
+trans_dph(const struct instr_translater *t, struct etna_compile *c,
+          const struct tgsi_full_instruction *inst, struct etna_inst_src *src)
+{
+   /*
+   DP3 tmp.xyzw, src0.xyzw, src1,xyzw, void
+   ADD dst.xyzw, tmp.xyzw, void, src1.wwww
+   */
+   struct etna_native_reg temp = etna_compile_get_inner_temp(c);
+   struct etna_inst ins[2] = { };
+
+   ins[0].opcode = INST_OPCODE_DP3;
+   ins[0].dst = etna_native_to_dst(temp, INST_COMPS_X | INST_COMPS_Y |
+                                         INST_COMPS_Z | INST_COMPS_W);
+   ins[0].src[0] = src[0];
+   ins[0].src[1] = src[1];
+
+   ins[1].opcode = INST_OPCODE_ADD;
+   ins[1].sat = inst->Instruction.Saturate;
+   ins[1].dst = convert_dst(c, &inst->Dst[0]);
+   ins[1].src[0] = etna_native_to_src(temp, INST_SWIZ_IDENTITY);
+   ins[1].src[2] = swizzle(src[1], SWIZZLE(W, W, W, W));
+
+   emit_inst(c, &ins[0]);
+   emit_inst(c, &ins[1]);
+}
+
+static void
+trans_sampler(const struct instr_translater *t, struct etna_compile *c,
+              const struct tgsi_full_instruction *inst,
+              struct etna_inst_src *src)
+{
+   /* There is no native support for GL texture rectangle coordinates, so
+    * we have to rescale from ([0, width], [0, height]) to ([0, 1], [0, 1]). */
+   if (inst->Texture.Texture == TGSI_TEXTURE_RECT) {
+      uint32_t unit = inst->Src[1].Register.Index;
+      struct etna_inst ins[2] = { };
+      struct etna_native_reg temp = etna_compile_get_inner_temp(c);
+
+      ins[0].opcode = INST_OPCODE_MUL;
+      ins[0].dst = etna_native_to_dst(temp, INST_COMPS_X);
+      ins[0].src[0] = src[0];
+      ins[0].src[1] = alloc_imm(c, ETNA_IMMEDIATE_TEXRECT_SCALE_X, unit);
+
+      ins[1].opcode = INST_OPCODE_MUL;
+      ins[1].dst = etna_native_to_dst(temp, INST_COMPS_Y);
+      ins[1].src[0] = src[0];
+      ins[1].src[1] = alloc_imm(c, ETNA_IMMEDIATE_TEXRECT_SCALE_Y, unit);
+
+      emit_inst(c, &ins[0]);
+      emit_inst(c, &ins[1]);
+
+      src[0] = etna_native_to_src(temp, INST_SWIZ_IDENTITY); /* temp.xyzw */
+   }
+
+   switch (inst->Instruction.Opcode) {
+   case TGSI_OPCODE_TEX:
+      emit_inst(c, &(struct etna_inst) {
+         .opcode = INST_OPCODE_TEXLD,
+         .sat = 0,
+         .dst = convert_dst(c, &inst->Dst[0]),
+         .tex = convert_tex(c, &inst->Src[1], &inst->Texture),
+         .src[0] = src[0],
+      });
+      break;
+
+   case TGSI_OPCODE_TXB:
+      emit_inst(c, &(struct etna_inst) {
+         .opcode = INST_OPCODE_TEXLDB,
+         .sat = 0,
+         .dst = convert_dst(c, &inst->Dst[0]),
+         .tex = convert_tex(c, &inst->Src[1], &inst->Texture),
+         .src[0] = src[0],
+      });
+      break;
+
+   case TGSI_OPCODE_TXL:
+      emit_inst(c, &(struct etna_inst) {
+         .opcode = INST_OPCODE_TEXLDL,
+         .sat = 0,
+         .dst = convert_dst(c, &inst->Dst[0]),
+         .tex = convert_tex(c, &inst->Src[1], &inst->Texture),
+         .src[0] = src[0],
+      });
+      break;
+
+   case TGSI_OPCODE_TXP: { /* divide src.xyz by src.w */
+      struct etna_native_reg temp = etna_compile_get_inner_temp(c);
+
+      emit_inst(c, &(struct etna_inst) {
+         .opcode = INST_OPCODE_RCP,
+         .sat = 0,
+         .dst = etna_native_to_dst(temp, INST_COMPS_W), /* tmp.w */
+         .src[2] = swizzle(src[0], SWIZZLE(W, W, W, W)),
+      });
+      emit_inst(c, &(struct etna_inst) {
+         .opcode = INST_OPCODE_MUL,
+         .sat = 0,
+         .dst = etna_native_to_dst(temp, INST_COMPS_X | INST_COMPS_Y |
+                                         INST_COMPS_Z), /* tmp.xyz */
+         .src[0] = etna_native_to_src(temp, SWIZZLE(W, W, W, W)),
+         .src[1] = src[0], /* src.xyzw */
+      });
+      emit_inst(c, &(struct etna_inst) {
+         .opcode = INST_OPCODE_TEXLD,
+         .sat = 0,
+         .dst = convert_dst(c, &inst->Dst[0]),
+         .tex = convert_tex(c, &inst->Src[1], &inst->Texture),
+         .src[0] = etna_native_to_src(temp, INST_SWIZ_IDENTITY), /* tmp.xyzw */
+      });
+   } break;
+
+   default:
+      BUG("Unhandled instruction %s",
+          tgsi_get_opcode_name(inst->Instruction.Opcode));
+      assert(0);
+      break;
+   }
+}
+
+static void
+trans_dummy(const struct instr_translater *t, struct etna_compile *c,
+            const struct tgsi_full_instruction *inst, struct etna_inst_src *src)
+{
+   /* nothing to do */
+}
+
+static const struct instr_translater translaters[TGSI_OPCODE_LAST] = {
+#define INSTR(n, f, ...) \
+   [TGSI_OPCODE_##n] = {.fxn = (f), .tgsi_opc = TGSI_OPCODE_##n, ##__VA_ARGS__}
+
+   INSTR(MOV, trans_instr, .opc = INST_OPCODE_MOV, .src = {2, -1, -1}),
+   INSTR(RCP, trans_instr, .opc = INST_OPCODE_RCP, .src = {2, -1, -1}),
+   INSTR(RSQ, trans_instr, .opc = INST_OPCODE_RSQ, .src = {2, -1, -1}),
+   INSTR(MUL, trans_instr, .opc = INST_OPCODE_MUL, .src = {0, 1, -1}),
+   INSTR(ADD, trans_instr, .opc = INST_OPCODE_ADD, .src = {0, 2, -1}),
+   INSTR(DP3, trans_instr, .opc = INST_OPCODE_DP3, .src = {0, 1, -1}),
+   INSTR(DP4, trans_instr, .opc = INST_OPCODE_DP4, .src = {0, 1, -1}),
+   INSTR(DST, trans_instr, .opc = INST_OPCODE_DST, .src = {0, 1, -1}),
+   INSTR(MAD, trans_instr, .opc = INST_OPCODE_MAD, .src = {0, 1, 2}),
+   INSTR(EX2, trans_instr, .opc = INST_OPCODE_EXP, .src = {2, -1, -1}),
+   INSTR(LG2, trans_instr, .opc = INST_OPCODE_LOG, .src = {2, -1, -1}),
+   INSTR(SQRT, trans_instr, .opc = INST_OPCODE_SQRT, .src = {2, -1, -1}),
+   INSTR(FRC, trans_instr, .opc = INST_OPCODE_FRC, .src = {2, -1, -1}),
+   INSTR(CEIL, trans_instr, .opc = INST_OPCODE_CEIL, .src = {2, -1, -1}),
+   INSTR(FLR, trans_instr, .opc = INST_OPCODE_FLOOR, .src = {2, -1, -1}),
+   INSTR(CMP, trans_instr, .opc = INST_OPCODE_SELECT, .src = {0, 1, 2}, .cond = INST_CONDITION_LZ),
+
+   INSTR(KILL, trans_instr, .opc = INST_OPCODE_TEXKILL),
+   INSTR(KILL_IF, trans_instr, .opc = INST_OPCODE_TEXKILL, .src = {0, -1, -1}, .cond = INST_CONDITION_LZ),
+
+   INSTR(DDX, trans_deriv, .opc = INST_OPCODE_DSX),
+   INSTR(DDY, trans_deriv, .opc = INST_OPCODE_DSY),
+
+   INSTR(IF, trans_if),
+   INSTR(ELSE, trans_else),
+   INSTR(ENDIF, trans_endif),
+
+   INSTR(BGNLOOP, trans_loop_bgn),
+   INSTR(ENDLOOP, trans_loop_end),
+   INSTR(BRK, trans_brk),
+   INSTR(CONT, trans_cont),
+
+   INSTR(MIN, trans_min_max, .opc = INST_OPCODE_SELECT, .cond = INST_CONDITION_GT),
+   INSTR(MAX, trans_min_max, .opc = INST_OPCODE_SELECT, .cond = INST_CONDITION_LT),
+
+   INSTR(ARL, trans_arl),
+   INSTR(LRP, trans_lrp),
+   INSTR(LIT, trans_lit),
+   INSTR(SSG, trans_ssg),
+   INSTR(DPH, trans_dph),
+   INSTR(SUB, trans_sub),
+   INSTR(ABS, trans_abs),
+
+   INSTR(SIN, trans_trig),
+   INSTR(COS, trans_trig),
+   INSTR(SCS, trans_trig),
+
+   INSTR(SLT, trans_instr, .opc = INST_OPCODE_SET, .src = {0, 1, -1}, .cond = INST_CONDITION_LT),
+   INSTR(SGE, trans_instr, .opc = INST_OPCODE_SET, .src = {0, 1, -1}, .cond = INST_CONDITION_GE),
+   INSTR(SEQ, trans_instr, .opc = INST_OPCODE_SET, .src = {0, 1, -1}, .cond = INST_CONDITION_EQ),
+   INSTR(SGT, trans_instr, .opc = INST_OPCODE_SET, .src = {0, 1, -1}, .cond = INST_CONDITION_GT),
+   INSTR(SLE, trans_instr, .opc = INST_OPCODE_SET, .src = {0, 1, -1}, .cond = INST_CONDITION_LE),
+   INSTR(SNE, trans_instr, .opc = INST_OPCODE_SET, .src = {0, 1, -1}, .cond = INST_CONDITION_NE),
+
+   INSTR(TEX, trans_sampler),
+   INSTR(TXB, trans_sampler),
+   INSTR(TXL, trans_sampler),
+   INSTR(TXP, trans_sampler),
+
+   INSTR(NOP, trans_dummy),
+   INSTR(END, trans_dummy),
+};
+
+/* Pass -- compile instructions */
+static void
+etna_compile_pass_generate_code(struct etna_compile *c)
+{
+   struct tgsi_parse_context ctx = { };
+   unsigned status = tgsi_parse_init(&ctx, c->tokens);
+   assert(status == TGSI_PARSE_OK);
+
+   int inst_idx = 0;
+   while (!tgsi_parse_end_of_tokens(&ctx)) {
+      const struct tgsi_full_instruction *inst = 0;
+
+      /* No inner temps used yet for this instruction, clear counter */
+      c->inner_temps = 0;
+
+      tgsi_parse_token(&ctx);
+
+      switch (ctx.FullToken.Token.Type) {
+      case TGSI_TOKEN_TYPE_INSTRUCTION:
+         /* iterate over operands */
+         inst = &ctx.FullToken.FullInstruction;
+         if (c->dead_inst[inst_idx]) { /* skip dead instructions */
+            inst_idx++;
+            continue;
+         }
+
+         /* Lookup the TGSI information and generate the source arguments */
+         struct etna_inst_src src[ETNA_NUM_SRC];
+         memset(src, 0, sizeof(src));
+
+         const struct tgsi_opcode_info *tgsi = tgsi_get_opcode_info(inst->Instruction.Opcode);
+
+         for (int i = 0; i < tgsi->num_src && i < ETNA_NUM_SRC; i++) {
+            const struct tgsi_full_src_register *reg = &inst->Src[i];
+            const struct etna_native_reg *n = &etna_get_src_reg(c, reg->Register)->native;
+
+            if (!n->valid || n->is_tex)
+               continue;
+
+            src[i] = etna_create_src(reg, n);
+         }
+
+         const unsigned opc = inst->Instruction.Opcode;
+         const struct instr_translater *t = &translaters[opc];
+
+         if (t->fxn) {
+            t->fxn(t, c, inst, src);
+
+            inst_idx += 1;
+         } else {
+            BUG("Unhandled instruction %s", tgsi_get_opcode_name(opc));
+            assert(0);
+         }
+         break;
+      }
+   }
+   tgsi_parse_free(&ctx);
+}
+
+/* Look up register by semantic */
+static struct etna_reg_desc *
+find_decl_by_semantic(struct etna_compile *c, uint file, uint name, uint index)
+{
+   for (int idx = 0; idx < c->file[file].reg_size; ++idx) {
+      struct etna_reg_desc *reg = &c->file[file].reg[idx];
+
+      if (reg->semantic.Name == name && reg->semantic.Index == index)
+         return reg;
+   }
+
+   return NULL; /* not found */
+}
+
+/** Add ADD and MUL instruction to bring Z/W to 0..1 if -1..1 if needed:
+ * - this is a vertex shader
+ * - and this is an older GPU
+ */
+static void
+etna_compile_add_z_div_if_needed(struct etna_compile *c)
+{
+   if (c->info.processor == PIPE_SHADER_VERTEX && c->specs->vs_need_z_div) {
+      /* find position out */
+      struct etna_reg_desc *pos_reg =
+         find_decl_by_semantic(c, TGSI_FILE_OUTPUT, TGSI_SEMANTIC_POSITION, 0);
+
+      if (pos_reg != NULL) {
+         /*
+          * ADD tX.__z_, tX.zzzz, void, tX.wwww
+          * MUL tX.__z_, tX.zzzz, 0.5, void
+         */
+         emit_inst(c, &(struct etna_inst) {
+            .opcode = INST_OPCODE_ADD,
+            .dst = etna_native_to_dst(pos_reg->native, INST_COMPS_Z),
+            .src[0] = etna_native_to_src(pos_reg->native, SWIZZLE(Z, Z, Z, Z)),
+            .src[2] = etna_native_to_src(pos_reg->native, SWIZZLE(W, W, W, W)),
+         });
+         emit_inst(c, &(struct etna_inst) {
+            .opcode = INST_OPCODE_MUL,
+            .dst = etna_native_to_dst(pos_reg->native, INST_COMPS_Z),
+            .src[0] = etna_native_to_src(pos_reg->native, SWIZZLE(Z, Z, Z, Z)),
+            .src[1] = alloc_imm_f32(c, 0.5f),
+         });
+      }
+   }
+}
+
+/** add a NOP to the shader if
+ * a) the shader is empty
+ * or
+ * b) there is a label at the end of the shader
+ */
+static void
+etna_compile_add_nop_if_needed(struct etna_compile *c)
+{
+   bool label_at_last_inst = false;
+
+   for (int idx = 0; idx < c->labels_count; ++idx) {
+      if (c->labels[idx].inst_idx == c->inst_ptr)
+         label_at_last_inst = true;
+
+   }
+
+   if (c->inst_ptr == 0 || label_at_last_inst)
+      emit_inst(c, &(struct etna_inst){.opcode = INST_OPCODE_NOP});
+}
+
+static void
+assign_uniforms(struct etna_compile_file *file, unsigned base)
+{
+   for (int idx = 0; idx < file->reg_size; ++idx) {
+      file->reg[idx].native.valid = 1;
+      file->reg[idx].native.rgroup = INST_RGROUP_UNIFORM_0;
+      file->reg[idx].native.id = base + idx;
+   }
+}
+
+/* Allocate CONST and IMM to native ETNA_RGROUP_UNIFORM(x).
+ * CONST must be consecutive as const buffers are supposed to be consecutive,
+ * and before IMM, as this is
+ * more convenient because is possible for the compilation process itself to
+ * generate extra
+ * immediates for constants such as pi, one, zero.
+ */
+static void
+assign_constants_and_immediates(struct etna_compile *c)
+{
+   assign_uniforms(&c->file[TGSI_FILE_CONSTANT], 0);
+   /* immediates start after the constants */
+   c->imm_base = c->file[TGSI_FILE_CONSTANT].reg_size * 4;
+   assign_uniforms(&c->file[TGSI_FILE_IMMEDIATE], c->imm_base / 4);
+   DBG_F(ETNA_DBG_COMPILER_MSGS, "imm base: %i size: %i", c->imm_base,
+         c->imm_size);
+}
+
+/* Assign declared samplers to native texture units */
+static void
+assign_texture_units(struct etna_compile *c)
+{
+   uint tex_base = 0;
+
+   if (c->info.processor == PIPE_SHADER_VERTEX)
+      tex_base = c->specs->vertex_sampler_offset;
+
+   for (int idx = 0; idx < c->file[TGSI_FILE_SAMPLER].reg_size; ++idx) {
+      c->file[TGSI_FILE_SAMPLER].reg[idx].native.valid = 1;
+      c->file[TGSI_FILE_SAMPLER].reg[idx].native.is_tex = 1; // overrides rgroup
+      c->file[TGSI_FILE_SAMPLER].reg[idx].native.id = tex_base + idx;
+   }
+}
+
+/* Additional pass to fill in branch targets. This pass should be last
+ * as no instruction reordering or removing/addition can be done anymore
+ * once the branch targets are computed.
+ */
+static void
+etna_compile_fill_in_labels(struct etna_compile *c)
+{
+   for (int idx = 0; idx < c->inst_ptr; ++idx) {
+      if (c->lbl_usage[idx])
+         etna_assemble_set_imm(&c->code[idx * 4], c->lbl_usage[idx]->inst_idx);
+   }
+}
+
+/* compare two etna_native_reg structures, return true if equal */
+static bool
+cmp_etna_native_reg(const struct etna_native_reg to,
+                    const struct etna_native_reg from)
+{
+   return to.valid == from.valid && to.is_tex == from.is_tex &&
+          to.rgroup == from.rgroup && to.id == from.id;
+}
+
+/* go through all declarations and swap native registers *to* and *from* */
+static void
+swap_native_registers(struct etna_compile *c, const struct etna_native_reg to,
+                      const struct etna_native_reg from)
+{
+   if (cmp_etna_native_reg(from, to))
+      return; /* Nothing to do */
+
+   for (int idx = 0; idx < c->total_decls; ++idx) {
+      if (cmp_etna_native_reg(c->decl[idx].native, from)) {
+         c->decl[idx].native = to;
+      } else if (cmp_etna_native_reg(c->decl[idx].native, to)) {
+         c->decl[idx].native = from;
+      }
+   }
+}
+
+/* For PS we need to permute so that inputs are always in temporary 0..N-1.
+ * Semantic POS is always t0. If that semantic is not used, avoid t0.
+ */
+static void
+permute_ps_inputs(struct etna_compile *c)
+{
+   /* Special inputs:
+    * gl_FragCoord  VARYING_SLOT_POS   TGSI_SEMANTIC_POSITION
+    * gl_PointCoord VARYING_SLOT_PNTC  TGSI_SEMANTIC_PCOORD
+    */
+   uint native_idx = 1;
+
+   for (int idx = 0; idx < c->file[TGSI_FILE_INPUT].reg_size; ++idx) {
+      struct etna_reg_desc *reg = &c->file[TGSI_FILE_INPUT].reg[idx];
+      uint input_id;
+      assert(reg->has_semantic);
+
+      if (!reg->active || reg->semantic.Name == TGSI_SEMANTIC_POSITION)
+         continue;
+
+      input_id = native_idx++;
+      swap_native_registers(c, etna_native_temp(input_id),
+                            c->file[TGSI_FILE_INPUT].reg[idx].native);
+   }
+
+   c->num_varyings = native_idx - 1;
+
+   if (native_idx > c->next_free_native)
+      c->next_free_native = native_idx;
+}
+
+/* fill in ps inputs into shader object */
+static void
+fill_in_ps_inputs(struct etna_shader *sobj, struct etna_compile *c)
+{
+   struct etna_shader_io_file *sf = &sobj->infile;
+
+   sf->num_reg = 0;
+
+   for (int idx = 0; idx < c->file[TGSI_FILE_INPUT].reg_size; ++idx) {
+      struct etna_reg_desc *reg = &c->file[TGSI_FILE_INPUT].reg[idx];
+
+      if (reg->native.id > 0) {
+         assert(sf->num_reg < ETNA_NUM_INPUTS);
+         sf->reg[sf->num_reg].reg = reg->native.id;
+         sf->reg[sf->num_reg].semantic = reg->semantic;
+         /* convert usage mask to number of components (*=wildcard)
+          *   .r    (0..1)  -> 1 component
+          *   .*g   (2..3)  -> 2 component
+          *   .**b  (4..7)  -> 3 components
+          *   .***a (8..15) -> 4 components
+          */
+         sf->reg[sf->num_reg].num_components = util_last_bit(reg->usage_mask);
+         sf->num_reg++;
+      }
+   }
+
+   assert(sf->num_reg == c->num_varyings);
+   sobj->input_count_unk8 = 31; /* XXX what is this */
+}
+
+/* fill in output mapping for ps into shader object */
+static void
+fill_in_ps_outputs(struct etna_shader *sobj, struct etna_compile *c)
+{
+   sobj->outfile.num_reg = 0;
+
+   for (int idx = 0; idx < c->file[TGSI_FILE_OUTPUT].reg_size; ++idx) {
+      struct etna_reg_desc *reg = &c->file[TGSI_FILE_OUTPUT].reg[idx];
+
+      switch (reg->semantic.Name) {
+      case TGSI_SEMANTIC_COLOR: /* FRAG_RESULT_COLOR */
+         sobj->ps_color_out_reg = reg->native.id;
+         break;
+      case TGSI_SEMANTIC_POSITION: /* FRAG_RESULT_DEPTH */
+         sobj->ps_depth_out_reg = reg->native.id; /* =always native reg 0, only z component should be assigned */
+         break;
+      default:
+         assert(0); /* only outputs supported are COLOR and POSITION at the moment */
+      }
+   }
+}
+
+/* fill in inputs for vs into shader object */
+static void
+fill_in_vs_inputs(struct etna_shader *sobj, struct etna_compile *c)
+{
+   struct etna_shader_io_file *sf = &sobj->infile;
+
+   sf->num_reg = 0;
+   for (int idx = 0; idx < c->file[TGSI_FILE_INPUT].reg_size; ++idx) {
+      struct etna_reg_desc *reg = &c->file[TGSI_FILE_INPUT].reg[idx];
+      assert(sf->num_reg < ETNA_NUM_INPUTS);
+      /* XXX exclude inputs with special semantics such as gl_frontFacing */
+      sf->reg[sf->num_reg].reg = reg->native.id;
+      sf->reg[sf->num_reg].semantic = reg->semantic;
+      sf->reg[sf->num_reg].num_components = util_last_bit(reg->usage_mask);
+      sf->num_reg++;
+   }
+
+   sobj->input_count_unk8 = (sf->num_reg + 19) / 16; /* XXX what is this */
+}
+
+/* build two-level output index [Semantic][Index] for fast linking */
+static void
+build_output_index(struct etna_shader *sobj)
+{
+   int total = 0;
+   int offset = 0;
+
+   for (int name = 0; name < TGSI_SEMANTIC_COUNT; ++name)
+      total += sobj->output_count_per_semantic[name];
+
+   sobj->output_per_semantic_list = CALLOC(total, sizeof(struct etna_shader_inout *));
+
+   for (int name = 0; name < TGSI_SEMANTIC_COUNT; ++name) {
+      sobj->output_per_semantic[name] = &sobj->output_per_semantic_list[offset];
+      offset += sobj->output_count_per_semantic[name];
+   }
+
+   for (int idx = 0; idx < sobj->outfile.num_reg; ++idx) {
+      sobj->output_per_semantic[sobj->outfile.reg[idx].semantic.Name]
+                               [sobj->outfile.reg[idx].semantic.Index] =
+         &sobj->outfile.reg[idx];
+   }
+}
+
+/* fill in outputs for vs into shader object */
+static void
+fill_in_vs_outputs(struct etna_shader *sobj, struct etna_compile *c)
+{
+   struct etna_shader_io_file *sf = &sobj->outfile;
+
+   sf->num_reg = 0;
+   for (int idx = 0; idx < c->file[TGSI_FILE_OUTPUT].reg_size; ++idx) {
+      struct etna_reg_desc *reg = &c->file[TGSI_FILE_OUTPUT].reg[idx];
+      assert(sf->num_reg < ETNA_NUM_INPUTS);
+
+      switch (reg->semantic.Name) {
+      case TGSI_SEMANTIC_POSITION:
+         sobj->vs_pos_out_reg = reg->native.id;
+         break;
+      case TGSI_SEMANTIC_PSIZE:
+         sobj->vs_pointsize_out_reg = reg->native.id;
+         break;
+      default:
+         sf->reg[sf->num_reg].reg = reg->native.id;
+         sf->reg[sf->num_reg].semantic = reg->semantic;
+         sf->reg[sf->num_reg].num_components = 4; // XXX reg->num_components;
+         sf->num_reg++;
+         sobj->output_count_per_semantic[reg->semantic.Name] =
+            MAX2(reg->semantic.Index + 1,
+                 sobj->output_count_per_semantic[reg->semantic.Name]);
+      }
+   }
+
+   /* build two-level index for linking */
+   build_output_index(sobj);
+
+   /* fill in "mystery meat" load balancing value. This value determines how
+    * work is scheduled between VS and PS
+    * in the unified shader architecture. More precisely, it is determined from
+    * the number of VS outputs, as well as chip-specific
+    * vertex output buffer size, vertex cache size, and the number of shader
+    * cores.
+    *
+    * XXX this is a conservative estimate, the "optimal" value is only known for
+    * sure at link time because some
+    * outputs may be unused and thus unmapped. Then again, in the general use
+    * case with GLSL the vertex and fragment
+    * shaders are linked already before submitting to Gallium, thus all outputs
+    * are used.
+    */
+   int half_out = (c->file[TGSI_FILE_OUTPUT].reg_size + 1) / 2;
+   assert(half_out);
+
+   uint32_t b = ((20480 / (c->specs->vertex_output_buffer_size -
+                           2 * half_out * c->specs->vertex_cache_size)) +
+                 9) /
+                10;
+   uint32_t a = (b + 256 / (c->specs->shader_core_count * half_out)) / 2;
+   sobj->vs_load_balancing = VIVS_VS_LOAD_BALANCING_A(MIN2(a, 255)) |
+                             VIVS_VS_LOAD_BALANCING_B(MIN2(b, 255)) |
+                             VIVS_VS_LOAD_BALANCING_C(0x3f) |
+                             VIVS_VS_LOAD_BALANCING_D(0x0f);
+}
+
+static bool
+etna_compile_check_limits(struct etna_compile *c)
+{
+   int max_uniforms = (c->info.processor == PIPE_SHADER_VERTEX)
+                         ? c->specs->max_vs_uniforms
+                         : c->specs->max_ps_uniforms;
+   /* round up number of uniforms, including immediates, in units of four */
+   int num_uniforms = c->imm_base / 4 + (c->imm_size + 3) / 4;
+
+   if (c->inst_ptr > c->specs->max_instructions) {
+      DBG("Number of instructions (%d) exceeds maximum %d", c->inst_ptr,
+          c->specs->max_instructions);
+      return false;
+   }
+
+   if (c->next_free_native > c->specs->max_registers) {
+      DBG("Number of registers (%d) exceeds maximum %d", c->next_free_native,
+          c->specs->max_registers);
+      return false;
+   }
+
+   if (num_uniforms > max_uniforms) {
+      DBG("Number of uniforms (%d) exceeds maximum %d", num_uniforms,
+          max_uniforms);
+      return false;
+   }
+
+   if (c->num_varyings > c->specs->max_varyings) {
+      DBG("Number of varyings (%d) exceeds maximum %d", c->num_varyings,
+          c->specs->max_varyings);
+      return false;
+   }
+
+   if (c->imm_base > c->specs->num_constants) {
+      DBG("Number of constants (%d) exceeds maximum %d", c->imm_base,
+          c->specs->num_constants);
+   }
+
+   return true;
+}
+
+static void
+copy_uniform_state_to_shader(struct etna_compile *c, struct etna_shader *sobj)
+{
+   uint32_t count = c->imm_size;
+   struct etna_shader_uniform_info *uinfo = &sobj->uniforms;
+
+   uinfo->const_count = c->imm_base;
+   uinfo->imm_count = count;
+   uinfo->imm_data = mem_dup(c->imm_data, count * sizeof(*c->imm_data));
+   uinfo->imm_contents = mem_dup(c->imm_contents, count * sizeof(*c->imm_contents));
+
+   etna_set_shader_uniforms_dirty_flags(sobj);
+}
+
+struct etna_shader *
+etna_compile_shader(const struct etna_specs *specs,
+                    const struct tgsi_token *tokens)
+{
+   /* Create scratch space that may be too large to fit on stack
+    */
+   bool ret;
+   struct etna_compile *c;
+   struct etna_shader *shader;
+
+   struct tgsi_lowering_config lconfig = {
+      .lower_SCS = specs->has_sin_cos_sqrt,
+      .lower_FLR = !specs->has_sign_floor_ceil,
+      .lower_CEIL = !specs->has_sign_floor_ceil,
+      .lower_POW = true,
+      .lower_EXP = true,
+      .lower_LOG = true,
+      .lower_DP2 = true,
+      .lower_DP2A = true,
+      .lower_TRUNC = true,
+      .lower_XPD = true
+   };
+
+   c = CALLOC_STRUCT(etna_compile);
+   if (!c)
+      return NULL;
+
+   shader = CALLOC_STRUCT(etna_shader);
+   if (!shader)
+      goto out;
+
+   c->specs = specs;
+   c->tokens = tgsi_transform_lowering(&lconfig, tokens, &c->info);
+   c->free_tokens = !!c->tokens;
+   if (!c->tokens) {
+      /* no lowering */
+      c->tokens = tokens;
+   }
+
+   /* Build a map from gallium register to native registers for files
+    * CONST, SAMP, IMM, OUT, IN, TEMP.
+    * SAMP will map as-is for fragment shaders, there will be a +8 offset for
+    * vertex shaders.
+    */
+   /* Pass one -- check register file declarations and immediates */
+   etna_compile_parse_declarations(c);
+
+   etna_allocate_decls(c);
+
+   /* Pass two -- check usage of temporaries, inputs, outputs */
+   etna_compile_pass_check_usage(c);
+
+   assign_special_inputs(c);
+
+   /* Assign native temp register to TEMPs */
+   assign_temporaries_to_native(c, &c->file[TGSI_FILE_TEMPORARY]);
+
+   /* optimize outputs */
+   etna_compile_pass_optimize_outputs(c);
+
+   /* XXX assign special inputs: gl_FrontFacing (VARYING_SLOT_FACE)
+    *     this is part of RGROUP_INTERNAL
+    */
+
+   /* assign inputs: last usage of input should be <= first usage of temp */
+   /*   potential optimization case:
+    *     if single MOV TEMP[y], IN[x] before which temp y is not used, and
+    * after which IN[x]
+    *     is not read, temp[y] can be used as input register as-is
+    */
+   /*   sort temporaries by first use
+    *   sort inputs by last usage
+    *   iterate over inputs, temporaries
+    *     if last usage of input <= first usage of temp:
+    *       assign input to temp
+    *       advance input, temporary pointer
+    *     else
+    *       advance temporary pointer
+    *
+    *   potential problem: instruction with multiple inputs of which one is the
+    * temp and the other is the input;
+    *      however, as the temp is not used before this, how would this make
+    * sense? uninitialized temporaries have an undefined
+    *      value, so this would be ok
+    */
+   assign_inouts_to_temporaries(c, TGSI_FILE_INPUT);
+
+   /* assign outputs: first usage of output should be >= last usage of temp */
+   /*   potential optimization case:
+    *      if single MOV OUT[x], TEMP[y] (with full write mask, or at least
+    * writing all components that are used in
+    *        the shader) after which temp y is no longer used temp[y] can be
+    * used as output register as-is
+    *
+    *   potential problem: instruction with multiple outputs of which one is the
+    * temp and the other is the output;
+    *      however, as the temp is not used after this, how would this make
+    * sense? could just discard the output value
+    */
+   /*   sort temporaries by last use
+    *   sort outputs by first usage
+    *   iterate over outputs, temporaries
+    *     if first usage of output >= last usage of temp:
+    *       assign output to temp
+    *       advance output, temporary pointer
+    *     else
+    *       advance temporary pointer
+    */
+   assign_inouts_to_temporaries(c, TGSI_FILE_OUTPUT);
+
+   assign_constants_and_immediates(c);
+   assign_texture_units(c);
+
+   /* list declarations */
+   for (int x = 0; x < c->total_decls; ++x) {
+      DBG_F(ETNA_DBG_COMPILER_MSGS, "%i: %s,%d active=%i first_use=%i "
+                                    "last_use=%i native=%i usage_mask=%x "
+                                    "has_semantic=%i",
+            x, tgsi_file_name(c->decl[x].file), c->decl[x].idx,
+            c->decl[x].active, c->decl[x].first_use, c->decl[x].last_use,
+            c->decl[x].native.valid ? c->decl[x].native.id : -1,
+            c->decl[x].usage_mask, c->decl[x].has_semantic);
+      if (c->decl[x].has_semantic)
+         DBG_F(ETNA_DBG_COMPILER_MSGS, " semantic_name=%s semantic_idx=%i",
+               tgsi_semantic_names[c->decl[x].semantic.Name],
+               c->decl[x].semantic.Index);
+   }
+   /* XXX for PS we need to permute so that inputs are always in temporary
+    * 0..N-1.
+    * There is no "switchboard" for varyings (AFAIK!). The output color,
+    * however, can be routed
+    * from an arbitrary temporary.
+    */
+   if (c->info.processor == PIPE_SHADER_FRAGMENT)
+      permute_ps_inputs(c);
+
+
+   /* list declarations */
+   for (int x = 0; x < c->total_decls; ++x) {
+      DBG_F(ETNA_DBG_COMPILER_MSGS, "%i: %s,%d active=%i first_use=%i "
+                                    "last_use=%i native=%i usage_mask=%x "
+                                    "has_semantic=%i",
+            x, tgsi_file_name(c->decl[x].file), c->decl[x].idx,
+            c->decl[x].active, c->decl[x].first_use, c->decl[x].last_use,
+            c->decl[x].native.valid ? c->decl[x].native.id : -1,
+            c->decl[x].usage_mask, c->decl[x].has_semantic);
+      if (c->decl[x].has_semantic)
+         DBG_F(ETNA_DBG_COMPILER_MSGS, " semantic_name=%s semantic_idx=%i",
+               tgsi_semantic_names[c->decl[x].semantic.Name],
+               c->decl[x].semantic.Index);
+   }
+
+   /* pass 3: generate instructions */
+   etna_compile_pass_generate_code(c);
+   etna_compile_add_z_div_if_needed(c);
+   etna_compile_add_nop_if_needed(c);
+   etna_compile_fill_in_labels(c);
+
+   ret = etna_compile_check_limits(c);
+   if (!ret) {
+      FREE(shader);
+      shader = NULL;
+      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_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);
+
+   if (c->info.processor == PIPE_SHADER_VERTEX) {
+      fill_in_vs_inputs(shader, c);
+      fill_in_vs_outputs(shader, c);
+   } else if (c->info.processor == PIPE_SHADER_FRAGMENT) {
+      fill_in_ps_inputs(shader, c);
+      fill_in_ps_outputs(shader, c);
+   }
+
+out:
+   if (c->free_tokens)
+      FREE((void *)c->tokens);
+
+   FREE(c->labels);
+   FREE(c);
+
+   return shader;
+}
+
+extern const char *tgsi_swizzle_names[];
+void
+etna_dump_shader(const struct etna_shader *shader)
+{
+   if (shader->processor == PIPE_SHADER_VERTEX)
+      printf("VERT\n");
+   else
+      printf("FRAG\n");
+
+
+   etna_disasm(shader->code, shader->code_size, PRINT_RAW);
+
+   printf("num temps: %i\n", shader->num_temps);
+   printf("num const: %i\n", shader->uniforms.const_count);
+   printf("immediates:\n");
+   for (int idx = 0; idx < shader->uniforms.imm_count; ++idx) {
+      printf(" [%i].%s = %f (0x%08x)\n",
+             (idx + shader->uniforms.const_count) / 4,
+             tgsi_swizzle_names[idx % 4],
+             *((float *)&shader->uniforms.imm_data[idx]),
+             shader->uniforms.imm_data[idx]);
+   }
+   printf("inputs:\n");
+   for (int idx = 0; idx < shader->infile.num_reg; ++idx) {
+      printf(" [%i] name=%s index=%i comps=%i\n", shader->infile.reg[idx].reg,
+             tgsi_semantic_names[shader->infile.reg[idx].semantic.Name],
+             shader->infile.reg[idx].semantic.Index,
+             shader->infile.reg[idx].num_components);
+   }
+   printf("outputs:\n");
+   for (int idx = 0; idx < shader->outfile.num_reg; ++idx) {
+      printf(" [%i] name=%s index=%i comps=%i\n", shader->outfile.reg[idx].reg,
+             tgsi_semantic_names[shader->outfile.reg[idx].semantic.Name],
+             shader->outfile.reg[idx].semantic.Index,
+             shader->outfile.reg[idx].num_components);
+   }
+   printf("special:\n");
+   if (shader->processor == PIPE_SHADER_VERTEX) {
+      printf("  vs_pos_out_reg=%i\n", shader->vs_pos_out_reg);
+      printf("  vs_pointsize_out_reg=%i\n", shader->vs_pointsize_out_reg);
+      printf("  vs_load_balancing=0x%08x\n", shader->vs_load_balancing);
+   } else {
+      printf("  ps_color_out_reg=%i\n", shader->ps_color_out_reg);
+      printf("  ps_depth_out_reg=%i\n", shader->ps_depth_out_reg);
+   }
+   printf("  input_count_unk8=0x%08x\n", shader->input_count_unk8);
+}
+
+void
+etna_destroy_shader(struct etna_shader *shader)
+{
+   assert(shader);
+
+   FREE(shader->code);
+   FREE(shader->uniforms.imm_data);
+   FREE(shader->uniforms.imm_contents);
+   FREE(shader->output_per_semantic_list);
+   FREE(shader);
+}
+
+static const struct etna_shader_inout *
+etna_shader_vs_lookup(const struct etna_shader *sobj,
+                      const struct etna_shader_inout *in)
+{
+   if (in->semantic.Index < sobj->output_count_per_semantic[in->semantic.Name])
+      return sobj->output_per_semantic[in->semantic.Name][in->semantic.Index];
+
+   return NULL;
+}
+
+bool
+etna_link_shader(struct etna_shader_link_info *info,
+                 const struct etna_shader *vs, const struct etna_shader *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
+    * binary search could be used because the vs outputs are sorted by their
+    * semantic index and grouped by semantic type by fill_in_vs_outputs.
+    */
+   assert(fs->infile.num_reg < ETNA_NUM_INPUTS);
+
+   for (int idx = 0; idx < fs->infile.num_reg; ++idx) {
+      const struct etna_shader_inout *fsio = &fs->infile.reg[idx];
+      const struct etna_shader_inout *vsio = etna_shader_vs_lookup(vs, fsio);
+      struct etna_varying *varying;
+
+      assert(fsio->reg > 0 && fsio->reg <= ARRAY_SIZE(info->varyings));
+
+      if (fsio->reg > info->num_varyings)
+         info->num_varyings = fsio->reg;
+
+      varying = &info->varyings[fsio->reg - 1];
+      varying->num_components = fsio->num_components;
+
+      if (fsio->semantic.Name == TGSI_SEMANTIC_COLOR) /* colors affected by flat shading */
+         varying->pa_attributes = 0x200;
+      else /* texture coord or other bypasses flat shading */
+         varying->pa_attributes = 0x2f1;
+
+      if (fsio->semantic.Name == TGSI_SEMANTIC_PCOORD) {
+         varying->use[0] = VARYING_COMPONENT_USE_POINTCOORD_X;
+         varying->use[1] = VARYING_COMPONENT_USE_POINTCOORD_Y;
+         varying->use[2] = VARYING_COMPONENT_USE_USED;
+         varying->use[3] = VARYING_COMPONENT_USE_USED;
+         varying->reg = 0; /* replaced by point coord -- doesn't matter */
+         continue;
+      }
+
+      if (vsio == NULL)
+         return true; /* not found -- link error */
+
+      varying->use[0] = VARYING_COMPONENT_USE_USED;
+      varying->use[1] = VARYING_COMPONENT_USE_USED;
+      varying->use[2] = VARYING_COMPONENT_USE_USED;
+      varying->use[3] = VARYING_COMPONENT_USE_USED;
+      varying->reg = vsio->reg;
+   }
+
+   assert(info->num_varyings == fs->infile.num_reg);
+
+   return false;
+}
diff --git a/src/gallium/drivers/etnaviv/etnaviv_compiler.h b/src/gallium/drivers/etnaviv/etnaviv_compiler.h
new file mode 100644
index 0000000..d310109
--- /dev/null
+++ b/src/gallium/drivers/etnaviv/etnaviv_compiler.h
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2012-2015 Etnaviv Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Wladimir J. van der Laan <laanwj at gmail.com>
+ */
+
+#ifndef H_ETNAVIV_COMPILER
+#define H_ETNAVIV_COMPILER
+
+#include "etnaviv_context.h"
+#include "etnaviv_internal.h"
+#include "pipe/p_compiler.h"
+#include "pipe/p_shader_tokens.h"
+
+/* XXX some of these are pretty arbitrary limits, may be better to switch
+ * to dynamic allocation at some point.
+ */
+#define ETNA_MAX_TEMPS (64) /* max temp register count of all Vivante hw */
+#define ETNA_MAX_TOKENS (2048)
+#define ETNA_MAX_IMM (1024) /* max const+imm in 32-bit words */
+#define ETNA_MAX_DECL (2048) /* max declarations */
+#define ETNA_MAX_DEPTH (32)
+#define ETNA_MAX_INSTRUCTIONS (2048)
+
+/* compiler output per input/output */
+struct etna_shader_inout {
+   int reg; /* native register */
+   struct tgsi_declaration_semantic semantic; /* tgsi semantic name and index */
+   int num_components;
+};
+
+struct etna_shader_io_file {
+   size_t num_reg;
+   struct etna_shader_inout reg[ETNA_NUM_INPUTS];
+};
+
+/* shader object, for linking */
+struct etna_shader {
+   uint processor; /* TGSI_PROCESSOR_... */
+   uint32_t code_size; /* code size in uint32 words */
+   uint32_t *code;
+   unsigned num_temps;
+
+   struct etna_shader_uniform_info uniforms;
+
+   /* ETNA_DIRTY_* flags that, when set in context dirty, mean that the
+    * uniforms have to get (partial) reloaded. */
+   uint32_t uniforms_dirty_bits;
+
+   /* inputs (for linking) for fs, the inputs must be in register 1..N */
+   struct etna_shader_io_file infile;
+
+   /* outputs (for linking) */
+   struct etna_shader_io_file outfile;
+
+   /* index into outputs (for linking) */
+   int output_count_per_semantic[TGSI_SEMANTIC_COUNT];
+   struct etna_shader_inout * *output_per_semantic_list; /* list of pointers to outputs */
+   struct etna_shader_inout **output_per_semantic[TGSI_SEMANTIC_COUNT];
+
+   /* special outputs (vs only) */
+   int vs_pos_out_reg; /* VS position output */
+   int vs_pointsize_out_reg; /* VS point size output */
+   uint32_t vs_load_balancing;
+
+   /* special outputs (ps only) */
+   int ps_color_out_reg; /* color output register */
+   int ps_depth_out_reg; /* depth output register */
+
+   /* unknown input property (XX_INPUT_COUNT, field UNK8) */
+   uint32_t input_count_unk8;
+};
+
+struct etna_varying {
+   uint32_t pa_attributes;
+   uint8_t num_components;
+   uint8_t use[4];
+   uint8_t reg;
+};
+
+struct etna_shader_link_info {
+   /* each PS input is annotated with the VS output reg */
+   unsigned num_varyings;
+   struct etna_varying varyings[ETNA_NUM_INPUTS];
+};
+
+struct etna_shader *
+etna_compile_shader(const struct etna_specs *specs, const struct tgsi_token *tokens);
+
+void
+etna_dump_shader(const struct etna_shader *shader);
+
+bool
+etna_link_shader(struct etna_shader_link_info *info,
+                 const struct etna_shader *vs, const struct etna_shader *fs);
+
+void
+etna_destroy_shader(struct etna_shader *shader);
+
+#endif
diff --git a/src/gallium/drivers/etnaviv/etnaviv_compiler_cmdline.c b/src/gallium/drivers/etnaviv/etnaviv_compiler_cmdline.c
new file mode 100644
index 0000000..6f241d1
--- /dev/null
+++ b/src/gallium/drivers/etnaviv/etnaviv_compiler_cmdline.c
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 2015 Etnaviv Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Rob Clark <robclark at freedesktop.org>
+ *    Christian Gmeiner <christian.gmeiner at gmail.com>
+ */
+
+#include <err.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "tgsi/tgsi_dump.h"
+#include "tgsi/tgsi_parse.h"
+#include "tgsi/tgsi_text.h"
+
+#include "etnaviv_compiler.h"
+#include "etnaviv_debug.h"
+#include "etnaviv_internal.h"
+
+static const struct etna_specs specs_gc2000 = {
+   .vs_need_z_div = 0,
+   .has_sin_cos_sqrt = 1,
+   .has_sign_floor_ceil = 1,
+   .vertex_sampler_offset = 8,
+   .vertex_output_buffer_size = 512,
+   .vertex_cache_size = 16,
+   .shader_core_count = 4,
+   .max_instructions = 512,
+   .max_varyings = 12,
+   .max_registers = 64,
+   .max_vs_uniforms = 168,
+   .max_ps_uniforms = 128,
+   .num_constants = 168,
+};
+
+static int
+read_file(const char *filename, void **ptr, size_t *size)
+{
+   int fd, ret;
+   struct stat st;
+
+   *ptr = MAP_FAILED;
+
+   fd = open(filename, O_RDONLY);
+   if (fd == -1) {
+      warnx("couldn't open `%s'", filename);
+      return 1;
+   }
+
+   ret = fstat(fd, &st);
+   if (ret)
+      errx(1, "couldn't stat `%s'", filename);
+
+   *size = st.st_size;
+   *ptr = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
+   if (*ptr == MAP_FAILED)
+      errx(1, "couldn't map `%s'", filename);
+
+   close(fd);
+
+   return 0;
+}
+
+static void
+print_usage(void)
+{
+   printf("Usage: etnaviv_compiler [OPTIONS]... FILE\n");
+   printf("    --verbose         - verbose compiler/debug messages\n");
+   printf("    --help            - show this message\n");
+}
+
+int
+main(int argc, char **argv)
+{
+   int ret = 0, n = 1;
+   const char *filename;
+   struct tgsi_token toks[65536];
+   struct tgsi_parse_context parse;
+   struct etna_shader *shader_obj;
+   void *ptr;
+   size_t size;
+
+   etna_mesa_debug = ETNA_DBG_MSGS;
+
+   while (n < argc) {
+      if (!strcmp(argv[n], "--verbose")) {
+         etna_mesa_debug |= ETNA_DBG_COMPILER_MSGS;
+         n++;
+         continue;
+      }
+
+      if (!strcmp(argv[n], "--help")) {
+         print_usage();
+         return 0;
+      }
+
+      break;
+   }
+
+   filename = argv[n];
+
+   ret = read_file(filename, &ptr, &size);
+   if (ret) {
+      print_usage();
+      return ret;
+   }
+
+   debug_printf("%s\n", (char *)ptr);
+
+   if (!tgsi_text_translate(ptr, toks, ARRAY_SIZE(toks)))
+      errx(1, "could not parse `%s'", filename);
+
+   tgsi_parse_init(&parse, toks);
+
+   shader_obj = etna_compile_shader(&specs_gc2000, toks);
+
+   if (shader_obj == NULL) {
+      fprintf(stderr, "compiler failed!\n");
+      return 1;
+   }
+
+   etna_dump_shader(shader_obj);
+   etna_destroy_shader(shader_obj);
+}
diff --git a/src/gallium/drivers/etnaviv/etnaviv_context.c b/src/gallium/drivers/etnaviv/etnaviv_context.c
new file mode 100644
index 0000000..d767cd1
--- /dev/null
+++ b/src/gallium/drivers/etnaviv/etnaviv_context.c
@@ -0,0 +1,323 @@
+/*
+ * Copyright (c) 2012-2015 Etnaviv Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Wladimir J. van der Laan <laanwj at gmail.com>
+ *    Christian Gmeiner <christian.gmeiner at gmail.com>
+ */
+
+#include "etnaviv_context.h"
+
+#include "etnaviv_blend.h"
+#include "etnaviv_clear_blit.h"
+#include "etnaviv_compiler.h"
+#include "etnaviv_debug.h"
+#include "etnaviv_emit.h"
+#include "etnaviv_fence.h"
+#include "etnaviv_query.h"
+#include "etnaviv_rasterizer.h"
+#include "etnaviv_screen.h"
+#include "etnaviv_shader.h"
+#include "etnaviv_state.h"
+#include "etnaviv_surface.h"
+#include "etnaviv_texture.h"
+#include "etnaviv_transfer.h"
+#include "etnaviv_translate.h"
+#include "etnaviv_zsa.h"
+
+#include "pipe/p_context.h"
+#include "pipe/p_state.h"
+#include "util/u_blitter.h"
+#include "util/u_memory.h"
+#include "util/u_prim.h"
+
+#include "hw/common.xml.h"
+
+static void
+etna_context_destroy(struct pipe_context *pctx)
+{
+   struct etna_context *ctx = etna_context(pctx);
+
+   if (ctx->primconvert)
+      util_primconvert_destroy(ctx->primconvert);
+
+   if (ctx->blitter)
+      util_blitter_destroy(ctx->blitter);
+
+   if (ctx->stream)
+      etna_cmd_stream_del(ctx->stream);
+
+   slab_destroy_child(&ctx->transfer_pool);
+
+   FREE(pctx);
+}
+
+/* Update render state where needed based on draw operation */
+static void
+etna_update_state_for_draw(struct etna_context *ctx, const struct pipe_draw_info *info)
+{
+   /* Handle primitive restart:
+    * - If not an indexed draw, we don't care about the state of the primitive restart bit.
+    * - Otherwise, set the bit in INDEX_STREAM_CONTROL in the index buffer state
+    *   accordingly
+    * - If the value of the INDEX_STREAM_CONTROL register changed due to this, or
+    *   primitive restart is enabled and the restart index changed, mark the index
+    *   buffer state as dirty
+    */
+
+   if (info->indexed) {
+      uint32_t new_control = ctx->index_buffer.FE_INDEX_STREAM_CONTROL;
+
+      if (info->primitive_restart)
+         new_control |= VIVS_FE_INDEX_STREAM_CONTROL_PRIMITIVE_RESTART;
+      else
+         new_control &= ~VIVS_FE_INDEX_STREAM_CONTROL_PRIMITIVE_RESTART;
+
+      if (ctx->index_buffer.FE_INDEX_STREAM_CONTROL != new_control ||
+          (info->primitive_restart && ctx->index_buffer.FE_PRIMITIVE_RESTART_INDEX != info->restart_index)) {
+         ctx->index_buffer.FE_INDEX_STREAM_CONTROL = new_control;
+         ctx->index_buffer.FE_PRIMITIVE_RESTART_INDEX = info->restart_index;
+         ctx->dirty |= ETNA_DIRTY_INDEX_BUFFER;
+      }
+   }
+}
+
+
+static void
+etna_draw_vbo(struct pipe_context *pctx, const struct pipe_draw_info *info)
+{
+   struct etna_context *ctx = etna_context(pctx);
+   struct pipe_framebuffer_state *pfb = &ctx->framebuffer_s;
+   uint32_t draw_mode;
+   unsigned i;
+
+   if (ctx->vertex_elements == NULL || ctx->vertex_elements->num_elements == 0)
+      return; /* Nothing to do */
+
+   if (!(ctx->prim_hwsupport & (1 << info->mode))) {
+      struct primconvert_context *primconvert = ctx->primconvert;
+      util_primconvert_save_index_buffer(primconvert, &ctx->index_buffer.ib);
+      util_primconvert_save_rasterizer_state(primconvert, ctx->rasterizer);
+      util_primconvert_draw_vbo(primconvert, info);
+      return;
+   }
+
+   int prims = u_decomposed_prims_for_vertices(info->mode, info->count);
+   if (unlikely(prims <= 0)) {
+      DBG("Invalid draw primitive mode=%i or no primitives to be drawn", info->mode);
+      return;
+   }
+
+   draw_mode = translate_draw_mode(info->mode);
+   if (draw_mode == ETNA_NO_MATCH) {
+      BUG("Unsupported draw mode");
+      return;
+   }
+
+   if (info->indexed && !ctx->index_buffer.FE_INDEX_STREAM_BASE_ADDR.bo) {
+      BUG("Unsupported or no index buffer");
+      return;
+   }
+
+   /* Update any derived state */
+   if (!etna_state_update(ctx))
+      return;
+
+   /*
+    * Figure out the buffers/features we need:
+    */
+   if (etna_depth_enabled(ctx))
+      resource_written(ctx, pfb->zsbuf->texture);
+
+   if (etna_stencil_enabled(ctx))
+      resource_written(ctx, pfb->zsbuf->texture);
+
+   for (i = 0; i < pfb->nr_cbufs; i++) {
+      struct pipe_resource *surf;
+
+      if (!pfb->cbufs[i])
+         continue;
+
+      surf = pfb->cbufs[i]->texture;
+      resource_written(ctx, surf);
+   }
+
+   /* Mark constant buffers as being read */
+   resource_read(ctx, ctx->constant_buffer[PIPE_SHADER_VERTEX].buffer);
+   resource_read(ctx, ctx->constant_buffer[PIPE_SHADER_FRAGMENT].buffer);
+
+   /* Mark VBOs as being read */
+   for (i = 0; i < ctx->vertex_buffer.count; i++) {
+      assert(!ctx->vertex_buffer.vb[i].user_buffer);
+      resource_read(ctx, ctx->vertex_buffer.vb[i].buffer);
+   }
+
+   /* Mark index buffer as being read */
+   resource_read(ctx, ctx->index_buffer.ib.buffer);
+
+   /* Mark textures as being read */
+   for (i = 0; i < PIPE_MAX_SAMPLERS; i++)
+      if (ctx->sampler_view[i])
+         resource_read(ctx, ctx->sampler_view[i]->texture);
+
+   ctx->stats.prims_emitted += u_reduced_prims_for_vertices(info->mode, info->count);
+   ctx->stats.draw_calls++;
+
+   /* Update state for this draw operation */
+   etna_update_state_for_draw(ctx, info);
+
+   /* First, sync state, then emit DRAW_PRIMITIVES or DRAW_INDEXED_PRIMITIVES */
+   etna_emit_state(ctx);
+
+   if (info->indexed)
+      etna_draw_indexed_primitives(ctx->stream, draw_mode, info->start, prims, info->index_bias);
+   else
+      etna_draw_primitives(ctx->stream, draw_mode, info->start, prims);
+
+   if (DBG_ENABLED(ETNA_DBG_DRAW_STALL)) {
+      /* Stall the FE after every draw operation.  This allows better
+       * debug of GPU hang conditions, as the FE will indicate which
+       * draw op has caused the hang. */
+      etna_stall(ctx->stream, SYNC_RECIPIENT_FE, SYNC_RECIPIENT_PE);
+   }
+
+   if (DBG_ENABLED(ETNA_DBG_FLUSH_ALL))
+      pctx->flush(pctx, NULL, 0);
+
+   if (ctx->framebuffer.cbuf)
+      etna_resource(ctx->framebuffer.cbuf->texture)->seqno++;
+   if (ctx->framebuffer.zsbuf)
+      etna_resource(ctx->framebuffer.zsbuf->texture)->seqno++;
+}
+
+static void
+etna_flush(struct pipe_context *pctx, struct pipe_fence_handle **fence,
+           enum pipe_flush_flags flags)
+{
+   struct etna_context *ctx = etna_context(pctx);
+
+   etna_cmd_stream_flush(ctx->stream);
+
+   if (fence)
+      *fence = etna_fence_create(pctx);
+}
+
+static void
+etna_cmd_stream_reset_notify(struct etna_cmd_stream *stream, void *priv)
+{
+   struct etna_context *ctx = priv;
+   struct etna_resource *rsc, *rsc_tmp;
+
+   etna_set_state(stream, VIVS_GL_API_MODE, VIVS_GL_API_MODE_OPENGL);
+   etna_set_state(stream, VIVS_GL_VERTEX_ELEMENT_CONFIG, 0x00000001);
+   etna_set_state(stream, VIVS_RA_EARLY_DEPTH, 0x00000031);
+   etna_set_state(stream, VIVS_PA_W_CLIP_LIMIT, 0x34000001);
+
+   ctx->dirty = ~0L;
+
+   /* go through all the used resources and clear their status flag */
+   LIST_FOR_EACH_ENTRY_SAFE(rsc, rsc_tmp, &ctx->used_resources, list)
+   {
+      debug_assert(rsc->status != 0);
+      rsc->status = 0;
+      rsc->pending_ctx = NULL;
+      list_delinit(&rsc->list);
+   }
+
+   assert(LIST_IS_EMPTY(&ctx->used_resources));
+}
+
+struct pipe_context *
+etna_context_create(struct pipe_screen *pscreen, void *priv, unsigned flags)
+{
+   struct etna_context *ctx = CALLOC_STRUCT(etna_context);
+   struct etna_screen *screen;
+   struct pipe_context *pctx = NULL;
+
+   if (ctx == NULL)
+      return NULL;
+
+   screen = etna_screen(pscreen);
+   ctx->stream = etna_cmd_stream_new(screen->pipe, 0x2000, &etna_cmd_stream_reset_notify, ctx);
+   if (ctx->stream == NULL)
+      goto fail;
+
+   pctx = &ctx->base;
+   pctx->priv = ctx;
+   pctx->screen = pscreen;
+
+   /* context ctxate setup */
+   ctx->specs = screen->specs;
+   ctx->screen = screen;
+   /* need some sane default in case state tracker doesn't set some state: */
+   ctx->sample_mask = 0xffff;
+
+   list_inithead(&ctx->used_resources);
+
+   /*  Set sensible defaults for state */
+   etna_cmd_stream_reset_notify(ctx->stream, ctx);
+
+   pctx->destroy = etna_context_destroy;
+   pctx->draw_vbo = etna_draw_vbo;
+   pctx->flush = etna_flush;
+
+   /* creation of compile states */
+   pctx->create_blend_state = etna_blend_state_create;
+   pctx->create_rasterizer_state = etna_rasterizer_state_create;
+   pctx->create_depth_stencil_alpha_state = etna_zsa_state_create;
+
+   etna_clear_blit_init(pctx);
+   etna_query_context_init(pctx);
+   etna_state_init(pctx);
+   etna_surface_init(pctx);
+   etna_shader_init(pctx);
+   etna_texture_init(pctx);
+   etna_transfer_init(pctx);
+
+   ctx->blitter = util_blitter_create(pctx);
+   if (!ctx->blitter)
+      goto fail;
+
+   /* Generate the bitmask of supported draw primitives. */
+   ctx->prim_hwsupport = 1 << PIPE_PRIM_POINTS |
+                         1 << PIPE_PRIM_LINES |
+                         1 << PIPE_PRIM_LINE_STRIP |
+                         1 << PIPE_PRIM_TRIANGLES |
+                         1 << PIPE_PRIM_TRIANGLE_STRIP |
+                         1 << PIPE_PRIM_TRIANGLE_FAN;
+
+   if (VIV_FEATURE(ctx->screen, chipMinorFeatures2, LINE_LOOP))
+      ctx->prim_hwsupport |= 1 << PIPE_PRIM_LINE_LOOP;
+
+   ctx->primconvert = util_primconvert_create(pctx, ctx->prim_hwsupport);
+   if (!ctx->primconvert)
+      goto fail;
+
+   slab_create_child(&ctx->transfer_pool, &screen->transfer_pool);
+
+   return pctx;
+
+fail:
+   pctx->destroy(pctx);
+
+   return NULL;
+}
diff --git a/src/gallium/drivers/etnaviv/etnaviv_context.h b/src/gallium/drivers/etnaviv/etnaviv_context.h
new file mode 100644
index 0000000..74e93e1
--- /dev/null
+++ b/src/gallium/drivers/etnaviv/etnaviv_context.h
@@ -0,0 +1,194 @@
+/*
+ * Copyright (c) 2012-2015 Etnaviv Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Wladimir J. van der Laan <laanwj at gmail.com>
+ *    Christian Gmeiner <christian.gmeiner at gmail.com>
+ */
+
+#ifndef H_ETNAVIV_CONTEXT
+#define H_ETNAVIV_CONTEXT
+
+#include <stdint.h>
+
+#include "etnaviv_resource.h"
+#include "etnaviv_tiling.h"
+#include "indices/u_primconvert.h"
+#include "pipe/p_context.h"
+#include "pipe/p_defines.h"
+#include "pipe/p_format.h"
+#include "pipe/p_shader_tokens.h"
+#include "pipe/p_state.h"
+#include "util/slab.h"
+
+struct pipe_screen;
+struct etna_shader;
+
+struct etna_index_buffer {
+   struct pipe_index_buffer ib;
+   struct etna_reloc FE_INDEX_STREAM_BASE_ADDR;
+   uint32_t FE_INDEX_STREAM_CONTROL;
+   uint32_t FE_PRIMITIVE_RESTART_INDEX;
+};
+
+struct etna_shader_input {
+   int vs_reg; /* VS input register */
+};
+
+enum etna_varying_special {
+   ETNA_VARYING_VSOUT = 0, /* from VS */
+   ETNA_VARYING_POINTCOORD, /* point texture coord */
+};
+
+struct etna_shader_varying {
+   int num_components;
+   enum etna_varying_special special;
+   int pa_attributes;
+   int vs_reg; /* VS output register */
+};
+
+struct etna_transfer {
+   struct pipe_transfer base;
+   struct pipe_resource *rsc;
+   void *staging;
+};
+
+struct etna_vertexbuf_state {
+   struct pipe_vertex_buffer vb[PIPE_MAX_ATTRIBS];
+   struct compiled_set_vertex_buffer cvb[PIPE_MAX_ATTRIBS];
+   unsigned count;
+   uint32_t enabled_mask;
+};
+
+enum etna_immediate_contents {
+   ETNA_IMMEDIATE_UNUSED = 0,
+   ETNA_IMMEDIATE_CONSTANT,
+   ETNA_IMMEDIATE_TEXRECT_SCALE_X,
+   ETNA_IMMEDIATE_TEXRECT_SCALE_Y,
+};
+
+struct etna_shader_uniform_info {
+   enum etna_immediate_contents *imm_contents;
+   uint32_t *imm_data;
+   uint32_t imm_count;
+   uint32_t const_count;
+};
+
+struct etna_context {
+   struct pipe_context base;
+
+   struct etna_specs specs;
+   struct etna_screen *screen;
+   struct etna_cmd_stream *stream;
+
+   /* which state objects need to be re-emit'd: */
+   enum {
+      ETNA_DIRTY_BLEND           = (1 << 0),
+      ETNA_DIRTY_SAMPLERS        = (1 << 1),
+      ETNA_DIRTY_RASTERIZER      = (1 << 2),
+      ETNA_DIRTY_ZSA             = (1 << 3),
+      ETNA_DIRTY_VERTEX_ELEMENTS = (1 << 4),
+      ETNA_DIRTY_BLEND_COLOR     = (1 << 6),
+      ETNA_DIRTY_STENCIL_REF     = (1 << 7),
+      ETNA_DIRTY_SAMPLE_MASK     = (1 << 8),
+      ETNA_DIRTY_VIEWPORT        = (1 << 9),
+      ETNA_DIRTY_FRAMEBUFFER     = (1 << 10),
+      ETNA_DIRTY_SCISSOR         = (1 << 11),
+      ETNA_DIRTY_SAMPLER_VIEWS   = (1 << 12),
+      ETNA_DIRTY_CONSTBUF        = (1 << 13),
+      ETNA_DIRTY_VERTEX_BUFFERS  = (1 << 14),
+      ETNA_DIRTY_INDEX_BUFFER    = (1 << 15),
+      ETNA_DIRTY_SHADER          = (1 << 16),
+      ETNA_DIRTY_TS              = (1 << 17),
+      ETNA_DIRTY_TEXTURE_CACHES  = (1 << 18),
+   } dirty;
+
+   uint32_t prim_hwsupport;
+   struct primconvert_context *primconvert;
+
+   /* list of resources used by currently-unsubmitted renders */
+   struct list_head used_resources;
+
+   struct slab_child_pool transfer_pool;
+   struct blitter_context *blitter;
+
+   /* compiled bindable state */
+   unsigned sample_mask;
+   struct pipe_blend_state *blend;
+   unsigned num_fragment_samplers;
+   uint32_t active_samplers;
+   struct pipe_sampler_state *sampler[PIPE_MAX_SAMPLERS];
+   struct pipe_rasterizer_state *rasterizer;
+   struct pipe_depth_stencil_alpha_state *zsa;
+   struct compiled_vertex_elements_state *vertex_elements;
+   struct compiled_shader_state shader_state;
+
+   /* to simplify the emit process we store pre compiled state objects,
+    * which got 'compiled' during state change. */
+   struct compiled_blend_color blend_color;
+   struct compiled_stencil_ref stencil_ref;
+   struct compiled_framebuffer_state framebuffer;
+   struct compiled_scissor_state scissor;
+   struct compiled_viewport_state viewport;
+   unsigned num_fragment_sampler_views;
+   uint32_t active_sampler_views;
+   struct pipe_sampler_view *sampler_view[PIPE_MAX_SAMPLERS];
+   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 *vs;
+   struct etna_shader *fs;
+
+   /* saved parameter-like state. these are mainly kept around for the blitter */
+   struct pipe_framebuffer_state framebuffer_s;
+   struct pipe_stencil_ref stencil_ref_s;
+   struct pipe_viewport_state viewport_s;
+   struct pipe_scissor_state scissor_s;
+
+   /* cached state of entire GPU */
+   struct etna_3d_state gpu3d;
+
+   /* stats/counters */
+   struct {
+      uint64_t prims_emitted;
+      uint64_t draw_calls;
+   } stats;
+};
+
+static inline struct etna_context *
+etna_context(struct pipe_context *pctx)
+{
+   return (struct etna_context *)pctx;
+}
+
+static inline struct etna_transfer *
+etna_transfer(struct pipe_transfer *p)
+{
+   return (struct etna_transfer *)p;
+}
+
+struct pipe_context *
+etna_context_create(struct pipe_screen *pscreen, void *priv, unsigned flags);
+
+#endif
diff --git a/src/gallium/drivers/etnaviv/etnaviv_debug.h b/src/gallium/drivers/etnaviv/etnaviv_debug.h
new file mode 100644
index 0000000..cfda52b
--- /dev/null
+++ b/src/gallium/drivers/etnaviv/etnaviv_debug.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2012-2013 Etnaviv Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+/* Common debug stuffl */
+#ifndef H_ETNA_DEBUG
+#define H_ETNA_DEBUG
+
+#include "util/u_debug.h"
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+/* Logging */
+#define ETNA_DBG_MSGS            0x1 /* Warnings and non-fatal errors */
+#define ETNA_DBG_FRAME_MSGS      0x2
+#define ETNA_DBG_RESOURCE_MSGS   0x4
+#define ETNA_DBG_COMPILER_MSGS   0x8
+#define ETNA_DBG_LINKER_MSGS     0x10
+#define ETNA_DBG_DUMP_SHADERS    0x20
+
+/* Bypasses */
+#define ETNA_DBG_NO_TS           0x1000   /* Disable TS */
+#define ETNA_DBG_NO_AUTODISABLE  0x2000   /* Disable autodisable */
+#define ETNA_DBG_NO_SUPERTILE    0x4000   /* Disable supertile */
+#define ETNA_DBG_NO_EARLY_Z      0x8000   /* Disable early z */
+#define ETNA_DBG_CFLUSH_ALL      0x10000  /* Flush before every state update + draw call */
+#define ETNA_DBG_MSAA_2X         0x20000  /* Force 2X MSAA for screen */
+#define ETNA_DBG_MSAA_4X         0x40000  /* Force 4X MSAA for screen */
+#define ETNA_DBG_FINISH_ALL      0x80000  /* Finish on every flush */
+#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 */
+
+extern int etna_mesa_debug; /* set in etna_screen.c from ETNA_DEBUG */
+
+#define DBG_ENABLED(flag) unlikely(etna_mesa_debug & (flag))
+
+#define DBG_F(flag, fmt, ...)                                     \
+   do {                                                           \
+      if (etna_mesa_debug & (flag))                               \
+         debug_printf("%s:%d: " fmt "\n", __FUNCTION__, __LINE__, \
+                      ##__VA_ARGS__);                             \
+   } while (0)
+
+#define DBG(fmt, ...)                                             \
+   do {                                                           \
+      if (etna_mesa_debug & ETNA_DBG_MSGS)                        \
+         debug_printf("%s:%d: " fmt "\n", __FUNCTION__, __LINE__, \
+                      ##__VA_ARGS__);                             \
+   } while (0)
+
+/* A serious bug, show this even in non-debug mode */
+#define BUG(fmt, ...)                                                    \
+   do {                                                                  \
+      printf("%s:%d: " fmt "\n", __FUNCTION__, __LINE__, ##__VA_ARGS__); \
+   } while (0)
+
+#endif
diff --git a/src/gallium/drivers/etnaviv/etnaviv_disasm.c b/src/gallium/drivers/etnaviv/etnaviv_disasm.c
new file mode 100644
index 0000000..918d24e
--- /dev/null
+++ b/src/gallium/drivers/etnaviv/etnaviv_disasm.c
@@ -0,0 +1,612 @@
+/*
+ * Copyright (c) 2016 Etnaviv Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Christian Gmeiner <christian.gmeiner at gmail.com>
+ */
+
+#include "etnaviv_disasm.h"
+
+#include <assert.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "hw/isa.xml.h"
+
+struct instr {
+   /* dword0: */
+   uint32_t opc         : 6;
+   uint32_t cond        : 5;
+   uint32_t sat         : 1;
+   uint32_t dst_use     : 1;
+   uint32_t dst_amode   : 3;
+   uint32_t dst_reg     : 7;
+   uint32_t dst_comps   : 4;
+   uint32_t tex_id      : 5;
+
+   /* dword1: */
+   uint32_t tex_amode   : 3;
+   uint32_t tex_swiz    : 8;
+   uint32_t src0_use    : 1;
+   uint32_t src0_reg    : 9;
+   uint32_t type_bit2   : 1;
+   uint32_t src0_swiz   : 8;
+   uint32_t src0_neg    : 1;
+   uint32_t src0_abs    : 1;
+
+   /* dword2: */
+   uint32_t src0_amode  : 3;
+   uint32_t src0_rgroup : 3;
+   uint32_t src1_use    : 1;
+   uint32_t src1_reg    : 9;
+   uint32_t opcode_bit6 : 1;
+   uint32_t src1_swiz   : 8;
+   uint32_t src1_neg    : 1;
+   uint32_t src1_abs    : 1;
+   uint32_t src1_amode  : 3;
+   uint32_t type_bit01  : 2;
+
+   /* dword3: */
+   union {
+      struct {
+         uint32_t src1_rgroup : 3;
+         uint32_t src2_use    : 1;
+         uint32_t src2_reg    : 9;
+         uint32_t unk3_13     : 1;
+         uint32_t src2_swiz   : 8;
+         uint32_t src2_neg    : 1;
+         uint32_t src2_abs    : 1;
+         uint32_t unk3_24     : 1;
+         uint32_t src2_amode  : 3;
+         uint32_t src2_rgroup : 3;
+         uint32_t unk3_31     : 1;
+      };
+      uint32_t dword3;
+   };
+};
+
+struct dst_operand {
+   bool use;
+   uint8_t amode;
+   uint16_t reg;
+   uint8_t comps;
+};
+
+struct src_operand {
+   bool use;
+   bool neg;
+   bool abs;
+   uint8_t rgroup;
+   uint16_t reg;
+   uint8_t swiz;
+   uint8_t amode;
+};
+
+struct tex_operand {
+   uint8_t id;
+   uint8_t amode;
+   uint8_t swiz;
+};
+
+struct opc_operands {
+   struct dst_operand *dst;
+   struct tex_operand *tex;
+   struct src_operand *src0;
+   struct src_operand *src1;
+   struct src_operand *src2;
+
+   int imm;
+};
+
+static void
+printf_type(uint8_t type)
+{
+   switch(type) {
+   case INST_TYPE_F32:
+      /* as f32 is the default print nothing */
+      break;
+
+   case INST_TYPE_S32:
+      printf(".s32");
+      break;
+
+   case INST_TYPE_S8:
+      printf(".s8");
+      break;
+
+   case INST_TYPE_U16:
+      printf(".u16");
+      break;
+
+   case INST_TYPE_F16:
+      printf(".f16");
+      break;
+
+   case INST_TYPE_S16:
+      printf(".s16");
+      break;
+
+   case INST_TYPE_U32:
+      printf(".u32");
+      break;
+
+   case INST_TYPE_U8:
+      printf(".u8");
+      break;
+
+   default:
+      abort();
+      break;
+   }
+}
+
+static void
+print_condition(uint8_t condition)
+{
+   switch (condition) {
+   case INST_CONDITION_TRUE:
+      break;
+
+   case INST_CONDITION_GT:
+      printf(".GT");
+      break;
+
+   case INST_CONDITION_LT:
+      printf(".LT");
+      break;
+
+   case INST_CONDITION_GE:
+      printf(".GE");
+      break;
+
+   case INST_CONDITION_LE:
+      printf(".LE");
+      break;
+
+   case INST_CONDITION_EQ:
+      printf(".EQ");
+      break;
+
+   case INST_CONDITION_NE:
+      printf(".NE");
+      break;
+
+   case INST_CONDITION_AND:
+      printf(".AND");
+      break;
+
+   case INST_CONDITION_OR:
+      printf(".OR");
+      break;
+
+   case INST_CONDITION_XOR:
+      printf(".XOR");
+      break;
+
+   case INST_CONDITION_NOT:
+      printf(".NOT");
+      break;
+
+   case INST_CONDITION_NZ:
+      printf(".NZ");
+      break;
+
+   case INST_CONDITION_GEZ:
+      printf(".GEZ");
+      break;
+
+   case INST_CONDITION_GZ:
+      printf(".GZ");
+      break;
+
+   case INST_CONDITION_LEZ:
+      printf(".LEZ");
+      break;
+
+   case INST_CONDITION_LZ:
+      printf(".LZ");
+      break;
+
+   default:
+      abort();
+      break;
+   }
+}
+
+static void
+print_rgroup(uint8_t rgoup)
+{
+   switch (rgoup) {
+   case INST_RGROUP_TEMP:
+      printf("t");
+      break;
+
+   case INST_RGROUP_INTERNAL:
+      printf("i");
+      break;
+
+   case INST_RGROUP_UNIFORM_0:
+   case INST_RGROUP_UNIFORM_1:
+      printf("u");
+      break;
+   }
+}
+
+static void
+print_components(uint8_t components)
+{
+   if (components == 15)
+      return;
+
+   printf(".");
+   if (components & INST_COMPS_X)
+      printf("x");
+   else
+      printf("_");
+
+   if (components & INST_COMPS_Y)
+      printf("y");
+   else
+      printf("_");
+
+   if (components & INST_COMPS_Z)
+      printf("z");
+   else
+      printf("_");
+
+   if (components & INST_COMPS_W)
+      printf("w");
+   else
+      printf("_");
+}
+
+static inline void
+print_swiz_comp(uint8_t swiz_comp)
+{
+   switch (swiz_comp) {
+   case INST_SWIZ_COMP_X:
+      printf("x");
+      break;
+
+   case INST_SWIZ_COMP_Y:
+      printf("y");
+      break;
+
+   case INST_SWIZ_COMP_Z:
+      printf("z");
+      break;
+
+   case INST_SWIZ_COMP_W:
+      printf("w");
+      break;
+
+   default:
+      abort();
+      break;
+   }
+}
+
+static void
+print_swiz(uint8_t swiz)
+{
+   // if a null swizzle
+   if (swiz == 0xe4)
+      return;
+
+   const unsigned x = swiz & 0x3;
+   const unsigned y = (swiz & 0x0C) >> 2;
+   const unsigned z = (swiz & 0x30) >> 4;
+   const unsigned w = (swiz & 0xc0) >> 6;
+
+   printf(".");
+   print_swiz_comp(x);
+   print_swiz_comp(y);
+   print_swiz_comp(z);
+   print_swiz_comp(w);
+}
+
+static void
+print_amode(uint8_t amode)
+{
+   switch (amode) {
+   case INST_AMODE_DIRECT:
+      /* nothing to output */
+      break;
+
+   case INST_AMODE_ADD_A_X:
+      printf("[a.x]");
+      break;
+
+   case INST_AMODE_ADD_A_Y:
+      printf("[a.y]");
+      break;
+
+   case INST_AMODE_ADD_A_Z:
+      printf("[a.z]");
+      break;
+
+   case INST_AMODE_ADD_A_W:
+      printf("[a.w]");
+      break;
+
+   default:
+      abort();
+      break;
+   }
+}
+
+static void
+print_dst(struct dst_operand *dst, bool sep)
+{
+   if (dst->use) {
+      printf("t%u", dst->reg);
+      print_amode(dst->amode);
+      print_components(dst->comps);
+   } else {
+      printf("void");
+   }
+
+   if (sep)
+      printf(", ");
+}
+
+static void
+print_tex(struct tex_operand *tex, bool sep)
+{
+   printf("tex%u", tex->id);
+   print_amode(tex->amode);
+   print_swiz(tex->swiz);
+
+   if (sep)
+      printf(", ");
+}
+
+static void
+print_src(struct src_operand *src, bool sep)
+{
+   if (src->use) {
+      if (src->neg)
+         printf("-");
+
+      if (src->abs)
+         printf("|");
+
+      if (src->rgroup == INST_RGROUP_UNIFORM_1)
+         src->reg += 128;
+
+      print_rgroup(src->rgroup);
+      printf("%u", src->reg);
+      print_amode(src->amode);
+      print_swiz(src->swiz);
+
+      if (src->abs)
+         printf("|");
+   } else {
+      printf("void");
+   }
+
+   if (sep)
+      printf(", ");
+}
+
+static void
+print_opc_default(struct opc_operands *operands)
+{
+   print_dst(operands->dst, true);
+   print_src(operands->src0, true);
+   print_src(operands->src1, true);
+   print_src(operands->src2, false);
+}
+
+static void
+print_opc_mov(struct opc_operands *operands)
+{
+   // dst (areg)
+   printf("a%u", operands->dst->reg);
+   print_components(operands->dst->comps);
+   printf(", ");
+
+   print_src(operands->src0, true);
+   print_src(operands->src1, true);
+   print_src(operands->src2, false);
+}
+
+static void
+print_opc_tex(struct opc_operands *operands)
+{
+   print_dst(operands->dst, true);
+   print_tex(operands->tex, true);
+   print_src(operands->src0, true);
+   print_src(operands->src1, true);
+   print_src(operands->src2, false);
+}
+
+static void
+print_opc_imm(struct opc_operands *operands)
+{
+   print_dst(operands->dst, true);
+   print_src(operands->src0, true);
+   print_src(operands->src1, true);
+   printf("label_%04d", operands->imm);
+}
+
+#define OPC_BITS 7
+
+static const struct opc_info {
+   const char *name;
+   void (*print)(struct opc_operands *operands);
+} opcs[1 << OPC_BITS] = {
+#define OPC(opc) [INST_OPCODE_##opc] = {#opc, print_opc_default}
+#define OPC_MOV(opc) [INST_OPCODE_##opc] = {#opc, print_opc_mov}
+#define OPC_TEX(opc) [INST_OPCODE_##opc] = {#opc, print_opc_tex}
+#define OPC_IMM(opc) [INST_OPCODE_##opc] = {#opc, print_opc_imm}
+   OPC(NOP),
+   OPC(ADD),
+   OPC(MAD),
+   OPC(MUL),
+   OPC(DST),
+   OPC(DP3),
+   OPC(DP4),
+   OPC(DSX),
+   OPC(DSY),
+   OPC(MOV),
+   OPC_MOV(MOVAR),
+   OPC_MOV(MOVAF),
+   OPC(RCP),
+   OPC(RSQ),
+   OPC(LITP),
+   OPC(SELECT),
+   OPC(SET),
+   OPC(EXP),
+   OPC(LOG),
+   OPC(FRC),
+   OPC_IMM(CALL),
+   OPC(RET),
+   OPC_IMM(BRANCH),
+   OPC_TEX(TEXKILL),
+   OPC_TEX(TEXLD),
+   OPC_TEX(TEXLDB),
+   OPC_TEX(TEXLDD),
+   OPC_TEX(TEXLDL),
+   OPC_TEX(TEXLDPCF),
+   OPC(REP),
+   OPC(ENDREP),
+   OPC(LOOP),
+   OPC(ENDLOOP),
+   OPC(SQRT),
+   OPC(SIN),
+   OPC(COS),
+   OPC(FLOOR),
+   OPC(CEIL),
+   OPC(SIGN),
+   OPC(I2F),
+   OPC(CMP),
+   OPC(LOAD),
+   OPC(STORE),
+   OPC(IMULLO0),
+   OPC(IMULHI0),
+   OPC(LEADZERO),
+   OPC(LSHIFT),
+   OPC(RSHIFT),
+   OPC(ROTATE),
+   OPC(OR),
+   OPC(AND),
+   OPC(XOR),
+   OPC(NOT),
+};
+
+static void
+print_instr(uint32_t *dwords, int n, enum debug_t debug)
+{
+   struct instr *instr = (struct instr *)dwords;
+   const unsigned opc = instr->opc | (instr->opcode_bit6 << 6);
+   const char *name = opcs[opc].name;
+
+   printf("%04d: ", n);
+   if (debug & PRINT_RAW)
+      printf("%08x %08x %08x %08x  ", dwords[0], dwords[1], dwords[2],
+             dwords[3]);
+
+   if (name) {
+
+      struct dst_operand dst = {
+         .use = instr->dst_use,
+         .amode = instr->dst_amode,
+         .reg = instr->dst_reg,
+         .comps = instr->dst_comps
+      };
+
+      struct tex_operand tex = {
+         .id = instr->tex_id,
+         .amode = instr->tex_amode,
+         .swiz = instr->tex_swiz,
+      };
+
+      struct src_operand src0 = {
+         .use = instr->src0_use,
+         .neg = instr->src0_neg,
+         .abs = instr->src0_abs,
+         .rgroup = instr->src0_rgroup,
+         .reg = instr->src0_reg,
+         .swiz = instr->src0_swiz,
+         .amode = instr->src0_amode,
+      };
+
+      struct src_operand src1 = {
+         .use = instr->src1_use,
+         .neg = instr->src1_neg,
+         .abs = instr->src1_abs,
+         .rgroup = instr->src1_rgroup,
+         .reg = instr->src1_reg,
+         .swiz = instr->src1_swiz,
+         .amode = instr->src1_amode,
+      };
+
+      struct src_operand src2 = {
+         .use = instr->src2_use,
+         .neg = instr->src2_neg,
+         .abs = instr->src2_abs,
+         .rgroup = instr->src2_rgroup,
+         .reg = instr->src2_reg,
+         .swiz = instr->src2_swiz,
+         .amode = instr->src2_amode,
+      };
+
+      int imm = (instr->dword3 & VIV_ISA_WORD_3_SRC2_IMM__MASK)
+                >> VIV_ISA_WORD_3_SRC2_IMM__SHIFT;
+
+      struct opc_operands operands = {
+         .dst = &dst,
+         .tex = &tex,
+         .src0 = &src0,
+         .src1 = &src1,
+         .src2 = &src2,
+         .imm = imm,
+      };
+
+      uint8_t type = instr->type_bit01 | (instr->type_bit2 << 2);
+
+      printf("%s", name);
+      printf_type(type);
+      if (instr->sat)
+         printf(".SAT");
+      print_condition(instr->cond);
+      printf(" ");
+      opcs[opc].print(&operands);
+   } else {
+      printf("unknown (%d)", instr->opc);
+   }
+
+   printf("\n");
+}
+
+void
+etna_disasm(uint32_t *dwords, int sizedwords, enum debug_t debug)
+{
+   unsigned i;
+
+   assert((sizedwords % 2) == 0);
+
+   for (i = 0; i < sizedwords; i += 4)
+      print_instr(&dwords[i], i / 4, debug);
+}
diff --git a/src/gallium/drivers/etnaviv/etnaviv_disasm.h b/src/gallium/drivers/etnaviv/etnaviv_disasm.h
new file mode 100644
index 0000000..15df612
--- /dev/null
+++ b/src/gallium/drivers/etnaviv/etnaviv_disasm.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2016 Etnaviv Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Christian Gmeiner <christian.gmeiner at gmail.com>
+ */
+
+#ifndef H_ETNAVIV_DISASM
+#define H_ETNAVIV_DISASM
+
+#include <stdint.h>
+
+/* bitmask of print flags */
+enum debug_t {
+   PRINT_RAW = 0x1, /* dump raw hexdump */
+};
+
+void
+etna_disasm(uint32_t *dwords, int sizedwords, enum debug_t debug);
+
+#endif
diff --git a/src/gallium/drivers/etnaviv/etnaviv_emit.c b/src/gallium/drivers/etnaviv/etnaviv_emit.c
new file mode 100644
index 0000000..7eeeda5
--- /dev/null
+++ b/src/gallium/drivers/etnaviv/etnaviv_emit.c
@@ -0,0 +1,770 @@
+/*
+ * Copyright (c) 2014-2015 Etnaviv Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Wladimir J. van der Laan <laanwj at gmail.com>
+ */
+
+#include "etnaviv_emit.h"
+
+#include "etnaviv_blend.h"
+#include "etnaviv_compiler.h"
+#include "etnaviv_context.h"
+#include "etnaviv_rasterizer.h"
+#include "etnaviv_resource.h"
+#include "etnaviv_rs.h"
+#include "etnaviv_screen.h"
+#include "etnaviv_shader.h"
+#include "etnaviv_texture.h"
+#include "etnaviv_translate.h"
+#include "etnaviv_uniforms.h"
+#include "etnaviv_util.h"
+#include "etnaviv_zsa.h"
+#include "hw/common.xml.h"
+#include "hw/state.xml.h"
+#include "util/u_math.h"
+
+struct etna_coalesce {
+   uint32_t start;
+   uint32_t last_reg;
+   uint32_t last_fixp;
+};
+
+/* Queue a STALL command (queues 2 words) */
+static inline void
+CMD_STALL(struct etna_cmd_stream *stream, uint32_t from, uint32_t to)
+{
+   etna_cmd_stream_emit(stream, VIV_FE_STALL_HEADER_OP_STALL);
+   etna_cmd_stream_emit(stream, VIV_FE_STALL_TOKEN_FROM(from) | VIV_FE_STALL_TOKEN_TO(to));
+}
+
+void
+etna_stall(struct etna_cmd_stream *stream, uint32_t from, uint32_t to)
+{
+   etna_cmd_stream_reserve(stream, 4);
+
+   etna_emit_load_state(stream, VIVS_GL_SEMAPHORE_TOKEN >> 2, 1, 0);
+   etna_cmd_stream_emit(stream, VIVS_GL_SEMAPHORE_TOKEN_FROM(from) | VIVS_GL_SEMAPHORE_TOKEN_TO(to));
+
+   if (from == SYNC_RECIPIENT_FE) {
+      /* if the frontend is to be stalled, queue a STALL frontend command */
+      CMD_STALL(stream, from, to);
+   } else {
+      /* otherwise, load the STALL token state */
+      etna_emit_load_state(stream, VIVS_GL_STALL_TOKEN >> 2, 1, 0);
+      etna_cmd_stream_emit(stream, VIVS_GL_STALL_TOKEN_FROM(from) | VIVS_GL_STALL_TOKEN_TO(to));
+   }
+}
+
+static void
+etna_coalesce_start(struct etna_cmd_stream *stream,
+                    struct etna_coalesce *coalesce)
+{
+   coalesce->start = etna_cmd_stream_offset(stream);
+   coalesce->last_reg = 0;
+   coalesce->last_fixp = 0;
+}
+
+static void
+etna_coalesce_end(struct etna_cmd_stream *stream,
+                  struct etna_coalesce *coalesce)
+{
+   uint32_t end = etna_cmd_stream_offset(stream);
+   uint32_t size = end - coalesce->start;
+
+   if (size) {
+      uint32_t offset = coalesce->start - 1;
+      uint32_t value = etna_cmd_stream_get(stream, offset);
+
+      value |= VIV_FE_LOAD_STATE_HEADER_COUNT(size);
+      etna_cmd_stream_set(stream, offset, value);
+   }
+
+   /* append needed padding */
+   if (end % 2 == 1)
+      etna_cmd_stream_emit(stream, 0xdeadbeef);
+}
+
+static void
+check_coalsence(struct etna_cmd_stream *stream, struct etna_coalesce *coalesce,
+                uint32_t reg, uint32_t fixp)
+{
+   if (coalesce->last_reg != 0) {
+      if (((coalesce->last_reg + 4) != reg) || (coalesce->last_fixp != fixp)) {
+         etna_coalesce_end(stream, coalesce);
+         etna_emit_load_state(stream, reg >> 2, 0, fixp);
+         coalesce->start = etna_cmd_stream_offset(stream);
+      }
+   } else {
+      etna_emit_load_state(stream, reg >> 2, 0, fixp);
+      coalesce->start = etna_cmd_stream_offset(stream);
+   }
+
+   coalesce->last_reg = reg;
+   coalesce->last_fixp = fixp;
+}
+
+static inline void
+etna_coalsence_emit(struct etna_cmd_stream *stream,
+                    struct etna_coalesce *coalesce, uint32_t reg,
+                    uint32_t value)
+{
+   check_coalsence(stream, coalesce, reg, 0);
+   etna_cmd_stream_emit(stream, value);
+}
+
+static inline void
+etna_coalsence_emit_fixp(struct etna_cmd_stream *stream,
+                         struct etna_coalesce *coalesce, uint32_t reg,
+                         uint32_t value)
+{
+   check_coalsence(stream, coalesce, reg, 1);
+   etna_cmd_stream_emit(stream, value);
+}
+
+static inline void
+etna_coalsence_emit_reloc(struct etna_cmd_stream *stream,
+                          struct etna_coalesce *coalesce, uint32_t reg,
+                          const struct etna_reloc *r)
+{
+   if (r->bo) {
+      check_coalsence(stream, coalesce, reg, 0);
+      etna_cmd_stream_reloc(stream, r);
+   }
+}
+
+#define EMIT_STATE(state_name, src_value) \
+   etna_coalsence_emit(stream, &coalesce, VIVS_##state_name, src_value)
+
+#define EMIT_STATE_FIXP(state_name, src_value) \
+   etna_coalsence_emit_fixp(stream, &coalesce, VIVS_##state_name, src_value)
+
+#define EMIT_STATE_RELOC(state_name, src_value) \
+   etna_coalsence_emit_reloc(stream, &coalesce, VIVS_##state_name, src_value)
+
+/* submit RS state, without any processing and no dependence on context
+ * except TS if this is a source-to-destination blit. */
+void
+etna_submit_rs_state(struct etna_context *ctx,
+                     const struct compiled_rs_state *cs)
+{
+   struct etna_screen *screen = etna_screen(ctx->base.screen);
+   struct etna_cmd_stream *stream = ctx->stream;
+   struct etna_coalesce coalesce;
+
+   if (screen->specs.pixel_pipes == 1) {
+      etna_cmd_stream_reserve(stream, 22);
+      etna_coalesce_start(stream, &coalesce);
+      /* 0/1 */ EMIT_STATE(RS_CONFIG, cs->RS_CONFIG);
+      /* 2   */ EMIT_STATE_RELOC(RS_SOURCE_ADDR, &cs->source[0]);
+      /* 3   */ EMIT_STATE(RS_SOURCE_STRIDE, cs->RS_SOURCE_STRIDE);
+      /* 4   */ EMIT_STATE_RELOC(RS_DEST_ADDR, &cs->dest[0]);
+      /* 5   */ EMIT_STATE(RS_DEST_STRIDE, cs->RS_DEST_STRIDE);
+      /* 6/7 */ EMIT_STATE(RS_WINDOW_SIZE, cs->RS_WINDOW_SIZE);
+      /* 8/9 */ EMIT_STATE(RS_DITHER(0), cs->RS_DITHER[0]);
+      /*10   */ EMIT_STATE(RS_DITHER(1), cs->RS_DITHER[1]);
+      /*11 - pad */
+      /*12/13*/ EMIT_STATE(RS_CLEAR_CONTROL, cs->RS_CLEAR_CONTROL);
+      /*14   */ EMIT_STATE(RS_FILL_VALUE(0), cs->RS_FILL_VALUE[0]);
+      /*15   */ EMIT_STATE(RS_FILL_VALUE(1), cs->RS_FILL_VALUE[1]);
+      /*16   */ EMIT_STATE(RS_FILL_VALUE(2), cs->RS_FILL_VALUE[2]);
+      /*17   */ EMIT_STATE(RS_FILL_VALUE(3), cs->RS_FILL_VALUE[3]);
+      /*18/19*/ EMIT_STATE(RS_EXTRA_CONFIG, cs->RS_EXTRA_CONFIG);
+      /*20/21*/ EMIT_STATE(RS_KICKER, 0xbeebbeeb);
+      etna_coalesce_end(stream, &coalesce);
+   } else if (screen->specs.pixel_pipes == 2) {
+      etna_cmd_stream_reserve(stream, 34); /* worst case - both pipes multi=1 */
+      etna_coalesce_start(stream, &coalesce);
+      /* 0/1 */ EMIT_STATE(RS_CONFIG, cs->RS_CONFIG);
+      /* 2/3 */ EMIT_STATE(RS_SOURCE_STRIDE, cs->RS_SOURCE_STRIDE);
+      /* 4/5 */ EMIT_STATE(RS_DEST_STRIDE, cs->RS_DEST_STRIDE);
+      /* 6/7 */ EMIT_STATE_RELOC(RS_PIPE_SOURCE_ADDR(0), &cs->source[0]);
+      if (cs->RS_SOURCE_STRIDE & VIVS_RS_SOURCE_STRIDE_MULTI) {
+         /*8 */ EMIT_STATE_RELOC(RS_PIPE_SOURCE_ADDR(1), &cs->source[1]);
+         /*9 - pad */
+      }
+      /*10/11*/ EMIT_STATE_RELOC(RS_PIPE_DEST_ADDR(0), &cs->dest[0]);
+      if (cs->RS_DEST_STRIDE & VIVS_RS_DEST_STRIDE_MULTI) {
+         /*12*/ EMIT_STATE_RELOC(RS_PIPE_DEST_ADDR(1), &cs->dest[1]);
+         /*13 - pad */
+      }
+      /*14/15*/ EMIT_STATE(RS_PIPE_OFFSET(0), cs->RS_PIPE_OFFSET[0]);
+      /*16   */ EMIT_STATE(RS_PIPE_OFFSET(1), cs->RS_PIPE_OFFSET[1]);
+      /*17 - pad */
+      /*18/19*/ EMIT_STATE(RS_WINDOW_SIZE, cs->RS_WINDOW_SIZE);
+      /*20/21*/ EMIT_STATE(RS_DITHER(0), cs->RS_DITHER[0]);
+      /*22   */ EMIT_STATE(RS_DITHER(1), cs->RS_DITHER[1]);
+      /*23 - pad */
+      /*24/25*/ EMIT_STATE(RS_CLEAR_CONTROL, cs->RS_CLEAR_CONTROL);
+      /*26   */ EMIT_STATE(RS_FILL_VALUE(0), cs->RS_FILL_VALUE[0]);
+      /*27   */ EMIT_STATE(RS_FILL_VALUE(1), cs->RS_FILL_VALUE[1]);
+      /*28   */ EMIT_STATE(RS_FILL_VALUE(2), cs->RS_FILL_VALUE[2]);
+      /*29   */ EMIT_STATE(RS_FILL_VALUE(3), cs->RS_FILL_VALUE[3]);
+      /*30/31*/ EMIT_STATE(RS_EXTRA_CONFIG, cs->RS_EXTRA_CONFIG);
+      /*32/33*/ EMIT_STATE(RS_KICKER, 0xbeebbeeb);
+      etna_coalesce_end(stream, &coalesce);
+   } else {
+      abort();
+   }
+}
+
+/* Create bit field that specifies which samplers are active and thus need to be
+ * programmed
+ * 32 bits is enough for 32 samplers. As far as I know this is the upper bound
+ * supported on any Vivante hw
+ * up to GC4000.
+ */
+static uint32_t
+active_samplers_bits(struct etna_context *ctx)
+{
+   return ctx->active_sampler_views & ctx->active_samplers;
+}
+
+#define ETNA_3D_CONTEXT_SIZE  (400) /* keep this number above "Total state updates (fixed)" from gen_weave_state tool */
+
+static unsigned
+required_stream_size(struct etna_context *ctx)
+{
+   unsigned size = ETNA_3D_CONTEXT_SIZE;
+
+   /* stall + flush */
+   size += 2 + 4;
+
+   /* vertex elements */
+   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;
+
+   /* shader */
+   size += ctx->shader_state.vs_inst_mem_size + 1;
+   size += ctx->shader_state.ps_inst_mem_size + 1;
+
+   /* DRAW_INDEXED_PRIMITIVES command */
+   size += 6;
+
+   /* reserve for alignment etc. */
+   size += 64;
+
+   return size;
+}
+
+/* Weave state before draw operation. This function merges all the compiled
+ * state blocks under the context into one device register state. Parts of
+ * this state that are changed since last call (dirty) will be uploaded as
+ * state changes in the command buffer. */
+void
+etna_emit_state(struct etna_context *ctx)
+{
+   struct etna_cmd_stream *stream = ctx->stream;
+   uint32_t active_samplers = active_samplers_bits(ctx);
+
+   /* Pre-reserve the command buffer space which we are likely to need.
+    * This must cover all the state emitted below, and the following
+    * draw command. */
+   etna_cmd_stream_reserve(stream, required_stream_size(ctx));
+
+   uint32_t dirty = ctx->dirty;
+
+   /* Pre-processing: see what caches we need to flush before making state changes. */
+   uint32_t to_flush = 0;
+   if (unlikely(dirty & (ETNA_DIRTY_BLEND))) {
+      /* Need flush COLOR when changing PE.COLOR_FORMAT.OVERWRITE. */
+#if 0
+        /* TODO*/
+        if ((ctx->gpu3d.PE_COLOR_FORMAT & VIVS_PE_COLOR_FORMAT_OVERWRITE) !=
+           (etna_blend_state(ctx->blend)->PE_COLOR_FORMAT & VIVS_PE_COLOR_FORMAT_OVERWRITE))
+#endif
+      to_flush |= VIVS_GL_FLUSH_CACHE_COLOR;
+   }
+   if (unlikely(dirty & (ETNA_DIRTY_TEXTURE_CACHES)))
+      to_flush |= VIVS_GL_FLUSH_CACHE_TEXTURE;
+   if (unlikely(dirty & (ETNA_DIRTY_FRAMEBUFFER))) /* Framebuffer config changed? */
+      to_flush |= VIVS_GL_FLUSH_CACHE_COLOR | VIVS_GL_FLUSH_CACHE_DEPTH;
+   if (DBG_ENABLED(ETNA_DBG_CFLUSH_ALL))
+      to_flush |= VIVS_GL_FLUSH_CACHE_TEXTURE | VIVS_GL_FLUSH_CACHE_COLOR | VIVS_GL_FLUSH_CACHE_DEPTH;
+
+   if (to_flush) {
+      etna_set_state(stream, VIVS_GL_FLUSH_CACHE, to_flush);
+      etna_stall(stream, SYNC_RECIPIENT_RA, SYNC_RECIPIENT_PE);
+   }
+
+   /* If MULTI_SAMPLE_CONFIG.MSAA_SAMPLES changed, clobber affected shader
+    * state to make sure it is always rewritten. */
+   if (unlikely(dirty & (ETNA_DIRTY_FRAMEBUFFER))) {
+      if ((ctx->gpu3d.GL_MULTI_SAMPLE_CONFIG & VIVS_GL_MULTI_SAMPLE_CONFIG_MSAA_SAMPLES__MASK) !=
+          (ctx->framebuffer.GL_MULTI_SAMPLE_CONFIG & VIVS_GL_MULTI_SAMPLE_CONFIG_MSAA_SAMPLES__MASK)) {
+         /* XXX what does the GPU set these states to on MSAA samples change?
+          * Does it do the right thing?
+          * (increase/decrease as necessary) or something else? Just set some
+          * invalid value until we know for
+          * sure. */
+         ctx->gpu3d.PS_INPUT_COUNT = 0xffffffff;
+         ctx->gpu3d.PS_TEMP_REGISTER_CONTROL = 0xffffffff;
+      }
+   }
+
+   /* Update vertex elements. This is different from any of the other states, in that
+    * a) the number of vertex elements written matters: so write only active ones
+    * b) the vertex element states must all be written: do not skip entries that stay the same */
+   if (dirty & (ETNA_DIRTY_VERTEX_ELEMENTS)) {
+      /* Special case: vertex elements must always be sent in full if changed */
+      /*00600*/ etna_set_state_multi(stream, VIVS_FE_VERTEX_ELEMENT_CONFIG(0),
+         ctx->vertex_elements->num_elements,
+         ctx->vertex_elements->FE_VERTEX_ELEMENT_CONFIG);
+   }
+
+   /* The following code is originally generated by gen_merge_state.py, to
+    * emit state in increasing order of address (this makes it possible to merge
+    * consecutive register updates into one SET_STATE command)
+    *
+    * There have been some manual changes, where the weaving operation is not
+    * simply bitwise or:
+    * - scissor fixp
+    * - num vertex elements
+    * - scissor handling
+    * - num samplers
+    * - texture lod
+    * - ETNA_DIRTY_TS
+    * - removed ETNA_DIRTY_BASE_SETUP statements -- these are guaranteed to not
+    * change anyway
+    * - PS / framebuffer interaction for MSAA
+    * - move update of GL_MULTI_SAMPLE_CONFIG first
+    * - add unlikely()/likely()
+    */
+   struct etna_coalesce coalesce;
+
+   etna_coalesce_start(stream, &coalesce);
+
+   /* begin only EMIT_STATE -- make sure no new etna_reserve calls are done here
+    * directly
+    *    or indirectly */
+   /* multi sample config is set first, and outside of the normal sorting
+    * order, as changing the multisample state clobbers PS.INPUT_COUNT (and
+    * possibly PS.TEMP_REGISTER_CONTROL).
+    */
+   if (unlikely(dirty & (ETNA_DIRTY_FRAMEBUFFER | ETNA_DIRTY_SAMPLE_MASK))) {
+      uint32_t val = VIVS_GL_MULTI_SAMPLE_CONFIG_MSAA_ENABLES(ctx->sample_mask);
+      val |= ctx->framebuffer.GL_MULTI_SAMPLE_CONFIG;
+
+      /*03818*/ EMIT_STATE(GL_MULTI_SAMPLE_CONFIG, val);
+   }
+   if (likely(dirty & (ETNA_DIRTY_INDEX_BUFFER)) &&
+       ctx->index_buffer.ib.buffer) {
+      /*00644*/ EMIT_STATE_RELOC(FE_INDEX_STREAM_BASE_ADDR, &ctx->index_buffer.FE_INDEX_STREAM_BASE_ADDR);
+      /*00648*/ EMIT_STATE(FE_INDEX_STREAM_CONTROL, ctx->index_buffer.FE_INDEX_STREAM_CONTROL);
+   }
+   if (likely(dirty & (ETNA_DIRTY_VERTEX_BUFFERS))) {
+      /*0064C*/ EMIT_STATE_RELOC(FE_VERTEX_STREAM_BASE_ADDR, &ctx->vertex_buffer.cvb[0].FE_VERTEX_STREAM_BASE_ADDR);
+      /*00650*/ EMIT_STATE(FE_VERTEX_STREAM_CONTROL, ctx->vertex_buffer.cvb[0].FE_VERTEX_STREAM_CONTROL);
+   }
+   if (likely(dirty & (ETNA_DIRTY_INDEX_BUFFER))) {
+      /*00674*/ EMIT_STATE(FE_PRIMITIVE_RESTART_INDEX, ctx->index_buffer.FE_PRIMITIVE_RESTART_INDEX);
+   }
+   if (likely(dirty & (ETNA_DIRTY_VERTEX_BUFFERS))) {
+      for (int x = 1; x < ctx->vertex_buffer.count; ++x) {
+         /*00680*/ EMIT_STATE_RELOC(FE_VERTEX_STREAMS_BASE_ADDR(x), &ctx->vertex_buffer.cvb[x].FE_VERTEX_STREAM_BASE_ADDR);
+      }
+      for (int x = 1; x < ctx->vertex_buffer.count; ++x) {
+         if (ctx->vertex_buffer.cvb[x].FE_VERTEX_STREAM_BASE_ADDR.bo) {
+            /*006A0*/ EMIT_STATE(FE_VERTEX_STREAMS_CONTROL(x), ctx->vertex_buffer.cvb[x].FE_VERTEX_STREAM_CONTROL);
+         }
+      }
+   }
+   if (unlikely(dirty & (ETNA_DIRTY_SHADER))) {
+      /*00800*/ EMIT_STATE(VS_END_PC, ctx->shader_state.VS_END_PC);
+   }
+   if (unlikely(dirty & (ETNA_DIRTY_SHADER | ETNA_DIRTY_RASTERIZER))) {
+      bool point_size_per_vertex =
+         etna_rasterizer_state(ctx->rasterizer)->point_size_per_vertex;
+
+      /*00804*/ EMIT_STATE(VS_OUTPUT_COUNT,
+                           point_size_per_vertex
+                              ? ctx->shader_state.VS_OUTPUT_COUNT_PSIZE
+                              : ctx->shader_state.VS_OUTPUT_COUNT);
+   }
+   if (unlikely(dirty & (ETNA_DIRTY_VERTEX_ELEMENTS | ETNA_DIRTY_SHADER))) {
+      /*00808*/ EMIT_STATE(VS_INPUT_COUNT, ctx->shader_state.VS_INPUT_COUNT);
+      /*0080C*/ EMIT_STATE(VS_TEMP_REGISTER_CONTROL, ctx->shader_state.VS_TEMP_REGISTER_CONTROL);
+   }
+   if (unlikely(dirty & (ETNA_DIRTY_SHADER))) {
+      for (int x = 0; x < 4; ++x) {
+         /*00810*/ EMIT_STATE(VS_OUTPUT(x), ctx->shader_state.VS_OUTPUT[x]);
+      }
+   }
+   if (unlikely(dirty & (ETNA_DIRTY_VERTEX_ELEMENTS | ETNA_DIRTY_SHADER))) {
+      for (int x = 0; x < 4; ++x) {
+         /*00820*/ EMIT_STATE(VS_INPUT(x), ctx->shader_state.VS_INPUT[x]);
+      }
+   }
+   if (unlikely(dirty & (ETNA_DIRTY_SHADER))) {
+      /*00830*/ EMIT_STATE(VS_LOAD_BALANCING, ctx->shader_state.VS_LOAD_BALANCING);
+      /*00838*/ EMIT_STATE(VS_START_PC, ctx->shader_state.VS_START_PC);
+      if (ctx->specs.has_shader_range_registers) {
+         /*0085C*/ EMIT_STATE(VS_RANGE, (ctx->shader_state.vs_inst_mem_size / 4 - 1) << 16);
+      }
+   }
+   if (unlikely(dirty & (ETNA_DIRTY_VIEWPORT))) {
+      /*00A00*/ EMIT_STATE_FIXP(PA_VIEWPORT_SCALE_X, ctx->viewport.PA_VIEWPORT_SCALE_X);
+      /*00A04*/ EMIT_STATE_FIXP(PA_VIEWPORT_SCALE_Y, ctx->viewport.PA_VIEWPORT_SCALE_Y);
+      /*00A08*/ EMIT_STATE(PA_VIEWPORT_SCALE_Z, ctx->viewport.PA_VIEWPORT_SCALE_Z);
+      /*00A0C*/ EMIT_STATE_FIXP(PA_VIEWPORT_OFFSET_X, ctx->viewport.PA_VIEWPORT_OFFSET_X);
+      /*00A10*/ EMIT_STATE_FIXP(PA_VIEWPORT_OFFSET_Y, ctx->viewport.PA_VIEWPORT_OFFSET_Y);
+      /*00A14*/ EMIT_STATE(PA_VIEWPORT_OFFSET_Z, ctx->viewport.PA_VIEWPORT_OFFSET_Z);
+   }
+   if (unlikely(dirty & (ETNA_DIRTY_RASTERIZER))) {
+      struct etna_rasterizer_state *rasterizer = etna_rasterizer_state(ctx->rasterizer);
+
+      /*00A18*/ EMIT_STATE(PA_LINE_WIDTH, rasterizer->PA_LINE_WIDTH);
+      /*00A1C*/ EMIT_STATE(PA_POINT_SIZE, rasterizer->PA_POINT_SIZE);
+      /*00A28*/ EMIT_STATE(PA_SYSTEM_MODE, rasterizer->PA_SYSTEM_MODE);
+   }
+   if (unlikely(dirty & (ETNA_DIRTY_SHADER))) {
+      /*00A30*/ EMIT_STATE(PA_ATTRIBUTE_ELEMENT_COUNT, ctx->shader_state.PA_ATTRIBUTE_ELEMENT_COUNT);
+   }
+   if (unlikely(dirty & (ETNA_DIRTY_RASTERIZER | ETNA_DIRTY_SHADER))) {
+      uint32_t val = etna_rasterizer_state(ctx->rasterizer)->PA_CONFIG;
+      /*00A34*/ EMIT_STATE(PA_CONFIG, val & ctx->shader_state.PA_CONFIG);
+   }
+   if (unlikely(dirty & (ETNA_DIRTY_RASTERIZER))) {
+      struct etna_rasterizer_state *rasterizer = etna_rasterizer_state(ctx->rasterizer);
+      /*00A38*/ EMIT_STATE(PA_WIDE_LINE_WIDTH0, rasterizer->PA_LINE_WIDTH);
+      /*00A3C*/ EMIT_STATE(PA_WIDE_LINE_WIDTH1, rasterizer->PA_LINE_WIDTH);
+   }
+   if (unlikely(dirty & (ETNA_DIRTY_SHADER))) {
+      for (int x = 0; x < 10; ++x) {
+         /*00A40*/ EMIT_STATE(PA_SHADER_ATTRIBUTES(x), ctx->shader_state.PA_SHADER_ATTRIBUTES[x]);
+      }
+   }
+   if (unlikely(dirty & (ETNA_DIRTY_SCISSOR | ETNA_DIRTY_FRAMEBUFFER |
+                         ETNA_DIRTY_RASTERIZER | ETNA_DIRTY_VIEWPORT))) {
+      /* this is a bit of a mess: rasterizer.scissor determines whether to use
+       * only the framebuffer scissor, or specific scissor state, and the
+       * viewport clips too so the logic spans four CSOs */
+      struct etna_rasterizer_state *rasterizer = etna_rasterizer_state(ctx->rasterizer);
+
+      uint32_t scissor_left =
+         MAX2(ctx->framebuffer.SE_SCISSOR_LEFT, ctx->viewport.SE_SCISSOR_LEFT);
+      uint32_t scissor_top =
+         MAX2(ctx->framebuffer.SE_SCISSOR_TOP, ctx->viewport.SE_SCISSOR_TOP);
+      uint32_t scissor_right =
+         MIN2(ctx->framebuffer.SE_SCISSOR_RIGHT, ctx->viewport.SE_SCISSOR_RIGHT);
+      uint32_t scissor_bottom =
+         MIN2(ctx->framebuffer.SE_SCISSOR_BOTTOM, ctx->viewport.SE_SCISSOR_BOTTOM);
+
+      if (rasterizer->scissor) {
+         scissor_left = MAX2(ctx->scissor.SE_SCISSOR_LEFT, scissor_left);
+         scissor_top = MAX2(ctx->scissor.SE_SCISSOR_TOP, scissor_top);
+         scissor_right = MIN2(ctx->scissor.SE_SCISSOR_RIGHT, scissor_right);
+         scissor_bottom = MIN2(ctx->scissor.SE_SCISSOR_BOTTOM, scissor_bottom);
+      }
+
+      /*00C00*/ EMIT_STATE_FIXP(SE_SCISSOR_LEFT, scissor_left);
+      /*00C04*/ EMIT_STATE_FIXP(SE_SCISSOR_TOP, scissor_top);
+      /*00C08*/ EMIT_STATE_FIXP(SE_SCISSOR_RIGHT, scissor_right);
+      /*00C0C*/ EMIT_STATE_FIXP(SE_SCISSOR_BOTTOM, scissor_bottom);
+   }
+   if (unlikely(dirty & (ETNA_DIRTY_RASTERIZER))) {
+      struct etna_rasterizer_state *rasterizer = etna_rasterizer_state(ctx->rasterizer);
+
+      /*00C10*/ EMIT_STATE(SE_DEPTH_SCALE, rasterizer->SE_DEPTH_SCALE);
+      /*00C14*/ EMIT_STATE(SE_DEPTH_BIAS, rasterizer->SE_DEPTH_BIAS);
+      /*00C18*/ EMIT_STATE(SE_CONFIG, rasterizer->SE_CONFIG);
+   }
+   if (unlikely(dirty & (ETNA_DIRTY_SHADER))) {
+      /*00E00*/ EMIT_STATE(RA_CONTROL, ctx->shader_state.RA_CONTROL);
+   }
+   if (unlikely(dirty & (ETNA_DIRTY_FRAMEBUFFER))) {
+      /*00E04*/ EMIT_STATE(RA_MULTISAMPLE_UNK00E04, ctx->framebuffer.RA_MULTISAMPLE_UNK00E04);
+      for (int x = 0; x < 4; ++x) {
+         /*00E10*/ EMIT_STATE(RA_MULTISAMPLE_UNK00E10(x), ctx->framebuffer.RA_MULTISAMPLE_UNK00E10[x]);
+      }
+      for (int x = 0; x < 16; ++x) {
+         /*00E40*/ EMIT_STATE(RA_CENTROID_TABLE(x), ctx->framebuffer.RA_CENTROID_TABLE[x]);
+      }
+   }
+   if (unlikely(dirty & (ETNA_DIRTY_SHADER | ETNA_DIRTY_FRAMEBUFFER))) {
+      /*01000*/ EMIT_STATE(PS_END_PC, ctx->shader_state.PS_END_PC);
+      /*01004*/ EMIT_STATE(PS_OUTPUT_REG, ctx->shader_state.PS_OUTPUT_REG);
+      /*01008*/ EMIT_STATE(PS_INPUT_COUNT,
+                           ctx->framebuffer.msaa_mode
+                              ? ctx->shader_state.PS_INPUT_COUNT_MSAA
+                              : ctx->shader_state.PS_INPUT_COUNT);
+      /*0100C*/ EMIT_STATE(PS_TEMP_REGISTER_CONTROL,
+                           ctx->framebuffer.msaa_mode
+                              ? ctx->shader_state.PS_TEMP_REGISTER_CONTROL_MSAA
+                              : ctx->shader_state.PS_TEMP_REGISTER_CONTROL);
+      /*01010*/ EMIT_STATE(PS_CONTROL, ctx->shader_state.PS_CONTROL);
+      /*01018*/ EMIT_STATE(PS_START_PC, ctx->shader_state.PS_START_PC);
+      if (ctx->specs.has_shader_range_registers) {
+         /*0101C*/ EMIT_STATE(PS_RANGE, ((ctx->shader_state.ps_inst_mem_size / 4 - 1 + 0x100) << 16) |
+                                        0x100);
+      }
+   }
+   if (unlikely(dirty & (ETNA_DIRTY_ZSA | ETNA_DIRTY_FRAMEBUFFER))) {
+      uint32_t val = etna_zsa_state(ctx->zsa)->PE_DEPTH_CONFIG;
+      /*01400*/ EMIT_STATE(PE_DEPTH_CONFIG, val | ctx->framebuffer.PE_DEPTH_CONFIG);
+   }
+   if (unlikely(dirty & (ETNA_DIRTY_VIEWPORT))) {
+      /*01404*/ EMIT_STATE(PE_DEPTH_NEAR, ctx->viewport.PE_DEPTH_NEAR);
+      /*01408*/ EMIT_STATE(PE_DEPTH_FAR, ctx->viewport.PE_DEPTH_FAR);
+   }
+   if (unlikely(dirty & (ETNA_DIRTY_FRAMEBUFFER))) {
+      /*0140C*/ EMIT_STATE(PE_DEPTH_NORMALIZE, ctx->framebuffer.PE_DEPTH_NORMALIZE);
+
+      if (ctx->specs.pixel_pipes == 1) {
+         /*01410*/ EMIT_STATE_RELOC(PE_DEPTH_ADDR, &ctx->framebuffer.PE_DEPTH_ADDR);
+      }
+
+      /*01414*/ EMIT_STATE(PE_DEPTH_STRIDE, ctx->framebuffer.PE_DEPTH_STRIDE);
+   }
+   if (unlikely(dirty & (ETNA_DIRTY_ZSA))) {
+      uint32_t val = etna_zsa_state(ctx->zsa)->PE_STENCIL_OP;
+      /*01418*/ EMIT_STATE(PE_STENCIL_OP, val);
+   }
+   if (unlikely(dirty & (ETNA_DIRTY_ZSA | ETNA_DIRTY_STENCIL_REF))) {
+      uint32_t val = etna_zsa_state(ctx->zsa)->PE_STENCIL_CONFIG;
+      /*0141C*/ EMIT_STATE(PE_STENCIL_CONFIG, val | ctx->stencil_ref.PE_STENCIL_CONFIG);
+   }
+   if (unlikely(dirty & (ETNA_DIRTY_ZSA))) {
+      uint32_t val = etna_zsa_state(ctx->zsa)->PE_ALPHA_OP;
+      /*01420*/ EMIT_STATE(PE_ALPHA_OP, val);
+   }
+   if (unlikely(dirty & (ETNA_DIRTY_BLEND_COLOR))) {
+      /*01424*/ EMIT_STATE(PE_ALPHA_BLEND_COLOR, ctx->blend_color.PE_ALPHA_BLEND_COLOR);
+   }
+   if (unlikely(dirty & (ETNA_DIRTY_BLEND))) {
+      uint32_t val = etna_blend_state(ctx->blend)->PE_ALPHA_CONFIG;
+      /*01428*/ EMIT_STATE(PE_ALPHA_CONFIG, val);
+   }
+   if (unlikely(dirty & (ETNA_DIRTY_BLEND | ETNA_DIRTY_FRAMEBUFFER))) {
+      uint32_t val;
+      /* Use the components and overwrite bits in framebuffer.PE_COLOR_FORMAT
+       * as a mask to enable the bits from blend PE_COLOR_FORMAT */
+      val = ~(VIVS_PE_COLOR_FORMAT_COMPONENTS__MASK |
+              VIVS_PE_COLOR_FORMAT_OVERWRITE);
+      val |= etna_blend_state(ctx->blend)->PE_COLOR_FORMAT;
+      val &= ctx->framebuffer.PE_COLOR_FORMAT;
+      /*0142C*/ EMIT_STATE(PE_COLOR_FORMAT, val);
+   }
+   if (unlikely(dirty & (ETNA_DIRTY_FRAMEBUFFER))) {
+      if (ctx->specs.pixel_pipes == 1) {
+         /*01430*/ EMIT_STATE_RELOC(PE_COLOR_ADDR, &ctx->framebuffer.PE_COLOR_ADDR);
+         /*01434*/ EMIT_STATE(PE_COLOR_STRIDE, ctx->framebuffer.PE_COLOR_STRIDE);
+         /*01454*/ EMIT_STATE(PE_HDEPTH_CONTROL, ctx->framebuffer.PE_HDEPTH_CONTROL);
+      } else if (ctx->specs.pixel_pipes == 2) {
+         /*01434*/ EMIT_STATE(PE_COLOR_STRIDE, ctx->framebuffer.PE_COLOR_STRIDE);
+         /*01454*/ EMIT_STATE(PE_HDEPTH_CONTROL, ctx->framebuffer.PE_HDEPTH_CONTROL);
+         /*01460*/ EMIT_STATE_RELOC(PE_PIPE_COLOR_ADDR(0), &ctx->framebuffer.PE_PIPE_COLOR_ADDR[0]);
+         /*01464*/ EMIT_STATE_RELOC(PE_PIPE_COLOR_ADDR(1), &ctx->framebuffer.PE_PIPE_COLOR_ADDR[1]);
+         /*01480*/ EMIT_STATE_RELOC(PE_PIPE_DEPTH_ADDR(0), &ctx->framebuffer.PE_PIPE_DEPTH_ADDR[0]);
+         /*01484*/ EMIT_STATE_RELOC(PE_PIPE_DEPTH_ADDR(1), &ctx->framebuffer.PE_PIPE_DEPTH_ADDR[1]);
+      } else {
+         abort();
+      }
+   }
+   if (unlikely(dirty & (ETNA_DIRTY_STENCIL_REF))) {
+      /*014A0*/ EMIT_STATE(PE_STENCIL_CONFIG_EXT, ctx->stencil_ref.PE_STENCIL_CONFIG_EXT);
+   }
+   if (unlikely(dirty & (ETNA_DIRTY_BLEND))) {
+      struct etna_blend_state *blend = etna_blend_state(ctx->blend);
+
+      /*014A4*/ EMIT_STATE(PE_LOGIC_OP, blend->PE_LOGIC_OP);
+      for (int x = 0; x < 2; ++x) {
+         /*014A8*/ EMIT_STATE(PE_DITHER(x), blend->PE_DITHER[x]);
+      }
+   }
+   if (unlikely(dirty & (ETNA_DIRTY_FRAMEBUFFER | ETNA_DIRTY_TS))) {
+      /*01654*/ EMIT_STATE(TS_MEM_CONFIG, ctx->framebuffer.TS_MEM_CONFIG);
+      /*01658*/ EMIT_STATE_RELOC(TS_COLOR_STATUS_BASE, &ctx->framebuffer.TS_COLOR_STATUS_BASE);
+      /*0165C*/ EMIT_STATE_RELOC(TS_COLOR_SURFACE_BASE, &ctx->framebuffer.TS_COLOR_SURFACE_BASE);
+      /*01660*/ EMIT_STATE(TS_COLOR_CLEAR_VALUE, ctx->framebuffer.TS_COLOR_CLEAR_VALUE);
+      /*01664*/ EMIT_STATE_RELOC(TS_DEPTH_STATUS_BASE, &ctx->framebuffer.TS_DEPTH_STATUS_BASE);
+      /*01668*/ EMIT_STATE_RELOC(TS_DEPTH_SURFACE_BASE, &ctx->framebuffer.TS_DEPTH_SURFACE_BASE);
+      /*0166C*/ EMIT_STATE(TS_DEPTH_CLEAR_VALUE, ctx->framebuffer.TS_DEPTH_CLEAR_VALUE);
+   }
+   if (unlikely(dirty & (ETNA_DIRTY_SAMPLER_VIEWS | ETNA_DIRTY_SAMPLERS))) {
+      for (int x = 0; x < VIVS_TE_SAMPLER__LEN; ++x) {
+         uint32_t val = 0; /* 0 == sampler inactive */
+
+         /* set active samplers to their configuration value (determined by both
+          * the sampler state and sampler view) */
+         if ((1 << x) & active_samplers) {
+            struct etna_sampler_state *ss = etna_sampler_state(ctx->sampler[x]);
+            struct etna_sampler_view *sv = etna_sampler_view(ctx->sampler_view[x]);
+
+            val = (ss->TE_SAMPLER_CONFIG0 & sv->TE_SAMPLER_CONFIG0_MASK) |
+                  sv->TE_SAMPLER_CONFIG0;
+         }
+
+         /*02000*/ EMIT_STATE(TE_SAMPLER_CONFIG0(x), val);
+      }
+   }
+   if (unlikely(dirty & (ETNA_DIRTY_SAMPLER_VIEWS))) {
+      struct etna_sampler_view *sv;
+
+      for (int x = 0; x < VIVS_TE_SAMPLER__LEN; ++x) {
+         if ((1 << x) & active_samplers) {
+            sv = etna_sampler_view(ctx->sampler_view[x]);
+            /*02040*/ EMIT_STATE(TE_SAMPLER_SIZE(x), sv->TE_SAMPLER_SIZE);
+         }
+      }
+      for (int x = 0; x < VIVS_TE_SAMPLER__LEN; ++x) {
+         if ((1 << x) & active_samplers) {
+            sv = etna_sampler_view(ctx->sampler_view[x]);
+            /*02080*/ EMIT_STATE(TE_SAMPLER_LOG_SIZE(x), sv->TE_SAMPLER_LOG_SIZE);
+         }
+      }
+   }
+   if (unlikely(dirty & (ETNA_DIRTY_SAMPLER_VIEWS | ETNA_DIRTY_SAMPLERS))) {
+      struct etna_sampler_state *ss;
+      struct etna_sampler_view *sv;
+
+      for (int x = 0; x < VIVS_TE_SAMPLER__LEN; ++x) {
+         if ((1 << x) & active_samplers) {
+            ss = etna_sampler_state(ctx->sampler[x]);
+            sv = etna_sampler_view(ctx->sampler_view[x]);
+
+            /* min and max lod is determined both by the sampler and the view */
+            /*020C0*/ EMIT_STATE(TE_SAMPLER_LOD_CONFIG(x),
+                                 ss->TE_SAMPLER_LOD_CONFIG |
+                                 VIVS_TE_SAMPLER_LOD_CONFIG_MAX(MIN2(ss->max_lod, sv->max_lod)) |
+                                 VIVS_TE_SAMPLER_LOD_CONFIG_MIN(MAX2(ss->min_lod, sv->min_lod)));
+         }
+      }
+      for (int x = 0; x < VIVS_TE_SAMPLER__LEN; ++x) {
+         if ((1 << x) & active_samplers) {
+            ss = etna_sampler_state(ctx->sampler[x]);
+            sv = etna_sampler_view(ctx->sampler_view[x]);
+
+            /*021C0*/ EMIT_STATE(TE_SAMPLER_CONFIG1(x), ss->TE_SAMPLER_CONFIG1 |
+                                                        sv->TE_SAMPLER_CONFIG1);
+         }
+      }
+   }
+   if (unlikely(dirty & (ETNA_DIRTY_SAMPLER_VIEWS))) {
+      for (int y = 0; y < VIVS_TE_SAMPLER_LOD_ADDR__LEN; ++y) {
+         for (int x = 0; x < VIVS_TE_SAMPLER__LEN; ++x) {
+            if ((1 << x) & active_samplers) {
+               struct etna_sampler_view *sv = etna_sampler_view(ctx->sampler_view[x]);
+               /*02400*/ EMIT_STATE_RELOC(TE_SAMPLER_LOD_ADDR(x, y),&sv->TE_SAMPLER_LOD_ADDR[y]);
+            }
+         }
+      }
+   }
+   if (unlikely(dirty & (ETNA_DIRTY_SHADER))) {
+      /*0381C*/ EMIT_STATE(GL_VARYING_TOTAL_COMPONENTS, ctx->shader_state.GL_VARYING_TOTAL_COMPONENTS);
+      /*03820*/ EMIT_STATE(GL_VARYING_NUM_COMPONENTS, ctx->shader_state.GL_VARYING_NUM_COMPONENTS);
+      for (int x = 0; x < 2; ++x) {
+         /*03828*/ EMIT_STATE(GL_VARYING_COMPONENT_USE(x), ctx->shader_state.GL_VARYING_COMPONENT_USE[x]);
+      }
+   }
+   etna_coalesce_end(stream, &coalesce);
+   /* end only EMIT_STATE */
+
+   /* Insert a FE/PE stall as changing the shader instructions (and maybe
+    * the uniforms) can corrupt the previous in-progress draw operation.
+    * Observed with amoeba on GC2000 during the right-to-left rendering
+    * of PI, and can cause GPU hangs immediately after.
+    * I summise that this is because the "new" locations at 0xc000 are not
+    * properly protected against updates as other states seem to be. Hence,
+    * we detect the "new" vertex shader instruction offset to apply this. */
+   if (ctx->dirty & (ETNA_DIRTY_SHADER | ETNA_DIRTY_CONSTBUF) && ctx->specs.vs_offset > 0x4000)
+      etna_stall(ctx->stream, SYNC_RECIPIENT_FE, SYNC_RECIPIENT_PE);
+
+   /* We need to update the uniform cache only if one of the following bits are
+    * set in ctx->dirty:
+    * - ETNA_DIRTY_SHADER
+    * - ETNA_DIRTY_CONSTBUF
+    * - uniforms_dirty_bits
+    *
+    * In case of ETNA_DIRTY_SHADER we need load all uniforms from the cache. In
+    * all
+    * other cases we can load on the changed uniforms.
+    */
+   static const uint32_t uniform_dirty_bits =
+      ETNA_DIRTY_SHADER | ETNA_DIRTY_CONSTBUF;
+
+   if (dirty & (uniform_dirty_bits | ctx->fs->uniforms_dirty_bits))
+      etna_uniforms_write(
+         ctx, ctx->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))
+      etna_uniforms_write(
+         ctx, ctx->fs, &ctx->constant_buffer[PIPE_SHADER_FRAGMENT],
+         ctx->shader_state.PS_UNIFORMS, &ctx->shader_state.ps_uniforms_size);
+
+   /**** Large dynamically-sized state ****/
+   if (dirty & (ETNA_DIRTY_SHADER)) {
+      /* Special case: a new shader was loaded; simply re-load all uniforms and
+       * shader code at once */
+      /*04000 or 0C000*/
+      etna_set_state_multi(stream, ctx->specs.vs_offset,
+                           ctx->shader_state.vs_inst_mem_size,
+                           ctx->shader_state.VS_INST_MEM);
+      /*06000 or 0D000*/
+      etna_set_state_multi(stream, ctx->specs.ps_offset,
+                           ctx->shader_state.ps_inst_mem_size,
+                           ctx->shader_state.PS_INST_MEM);
+      /*05000*/ etna_set_state_multi(stream, VIVS_VS_UNIFORMS(0),
+                                     ctx->shader_state.vs_uniforms_size,
+                                     ctx->shader_state.VS_UNIFORMS);
+      /*07000*/ etna_set_state_multi(stream, VIVS_PS_UNIFORMS(0),
+                                     ctx->shader_state.ps_uniforms_size,
+                                     ctx->shader_state.PS_UNIFORMS);
+
+      /* Copy uniforms to gpu3d, so that incremental updates to uniforms are
+       * possible as long as the
+       * same shader remains bound */
+      ctx->gpu3d.vs_uniforms_size = ctx->shader_state.vs_uniforms_size;
+      ctx->gpu3d.ps_uniforms_size = ctx->shader_state.ps_uniforms_size;
+      memcpy(ctx->gpu3d.VS_UNIFORMS, ctx->shader_state.VS_UNIFORMS,
+             ctx->shader_state.vs_uniforms_size * 4);
+      memcpy(ctx->gpu3d.PS_UNIFORMS, ctx->shader_state.PS_UNIFORMS,
+             ctx->shader_state.ps_uniforms_size * 4);
+   } else {
+      etna_coalesce_start(stream, &coalesce);
+      for (int x = 0; x < ctx->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];
+         }
+      }
+      etna_coalesce_end(stream, &coalesce);
+
+      etna_coalesce_start(stream, &coalesce);
+      for (int x = 0; x < ctx->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];
+         }
+      }
+      etna_coalesce_end(stream, &coalesce);
+   }
+/**** End of state update ****/
+#undef EMIT_STATE
+#undef EMIT_STATE_FIXP
+#undef EMIT_STATE_RELOC
+   ctx->dirty = 0;
+}
diff --git a/src/gallium/drivers/etnaviv/etnaviv_emit.h b/src/gallium/drivers/etnaviv/etnaviv_emit.h
new file mode 100644
index 0000000..6a3c772
--- /dev/null
+++ b/src/gallium/drivers/etnaviv/etnaviv_emit.h
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2012-2015 Etnaviv Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Wladimir J. van der Laan <laanwj at gmail.com>
+ */
+
+#ifndef H_ETNA_EMIT
+#define H_ETNA_EMIT
+
+#include "etnaviv_screen.h"
+#include "etnaviv_util.h"
+#include "hw/cmdstream.xml.h"
+
+struct etna_context;
+struct compiled_rs_state;
+
+static inline void
+etna_emit_load_state(struct etna_cmd_stream *stream, const uint16_t offset,
+                     const uint16_t count, const int fixp)
+{
+   uint32_t v;
+
+   v = VIV_FE_LOAD_STATE_HEADER_OP_LOAD_STATE |
+       COND(fixp, VIV_FE_LOAD_STATE_HEADER_FIXP) |
+       VIV_FE_LOAD_STATE_HEADER_OFFSET(offset) |
+       (VIV_FE_LOAD_STATE_HEADER_COUNT(count) &
+        VIV_FE_LOAD_STATE_HEADER_COUNT__MASK);
+
+   etna_cmd_stream_emit(stream, v);
+}
+
+static inline void
+etna_set_state(struct etna_cmd_stream *stream, uint32_t address, uint32_t value)
+{
+   etna_cmd_stream_reserve(stream, 2);
+   etna_emit_load_state(stream, address >> 2, 1, 0);
+   etna_cmd_stream_emit(stream, value);
+}
+
+static inline void
+etna_set_state_reloc(struct etna_cmd_stream *stream, uint32_t address,
+                     struct etna_reloc *reloc)
+{
+   etna_cmd_stream_reserve(stream, 2);
+   etna_emit_load_state(stream, address >> 2, 1, 0);
+   etna_cmd_stream_reloc(stream, reloc);
+}
+
+static inline void
+etna_set_state_multi(struct etna_cmd_stream *stream, uint32_t base,
+                     uint32_t num, const uint32_t *values)
+{
+   if (num == 0)
+      return;
+
+   etna_cmd_stream_reserve(stream, 1 + num + 1); /* 1 extra for potential alignment */
+   etna_emit_load_state(stream, base >> 2, num, 0);
+
+   for (uint32_t i = 0; i < num; i++)
+      etna_cmd_stream_emit(stream, values[i]);
+
+   /* add potential padding */
+   if ((num % 2) == 0)
+      etna_cmd_stream_emit(stream, 0);
+}
+
+void
+etna_stall(struct etna_cmd_stream *stream, uint32_t from, uint32_t to);
+
+void
+etna_submit_rs_state(struct etna_context *ctx, const struct compiled_rs_state *cs);
+
+static inline void
+etna_draw_primitives(struct etna_cmd_stream *stream, uint32_t primitive_type,
+                     uint32_t start, uint32_t count)
+{
+   etna_cmd_stream_reserve(stream, 4);
+
+   etna_cmd_stream_emit(stream, VIV_FE_DRAW_PRIMITIVES_HEADER_OP_DRAW_PRIMITIVES);
+   etna_cmd_stream_emit(stream, primitive_type);
+   etna_cmd_stream_emit(stream, start);
+   etna_cmd_stream_emit(stream, count);
+}
+
+static inline void
+etna_draw_indexed_primitives(struct etna_cmd_stream *stream,
+                             uint32_t primitive_type, uint32_t start,
+                             uint32_t count, uint32_t offset)
+{
+   etna_cmd_stream_reserve(stream, 5 + 1);
+
+   etna_cmd_stream_emit(stream, VIV_FE_DRAW_INDEXED_PRIMITIVES_HEADER_OP_DRAW_INDEXED_PRIMITIVES);
+   etna_cmd_stream_emit(stream, primitive_type);
+   etna_cmd_stream_emit(stream, start);
+   etna_cmd_stream_emit(stream, count);
+   etna_cmd_stream_emit(stream, offset);
+   etna_cmd_stream_emit(stream, 0);
+}
+
+void
+etna_emit_state(struct etna_context *ctx);
+
+#endif
diff --git a/src/gallium/drivers/etnaviv/etnaviv_fence.c b/src/gallium/drivers/etnaviv/etnaviv_fence.c
new file mode 100644
index 0000000..02f520b
--- /dev/null
+++ b/src/gallium/drivers/etnaviv/etnaviv_fence.c
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2012-2015 Etnaviv Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Wladimir J. van der Laan <laanwj at gmail.com>
+ *    Rob Clark <robclark at freedesktop.org>
+ */
+
+#include "etnaviv_fence.h"
+#include "etnaviv_context.h"
+#include "etnaviv_screen.h"
+
+#include "util/u_inlines.h"
+#include "util/u_memory.h"
+
+struct pipe_fence_handle {
+   struct pipe_reference reference;
+   struct etna_context *ctx;
+   struct etna_screen *screen;
+   uint32_t timestamp;
+};
+
+static void
+etna_screen_fence_reference(struct pipe_screen *pscreen,
+                            struct pipe_fence_handle **ptr,
+                            struct pipe_fence_handle *fence)
+{
+   if (pipe_reference(&(*ptr)->reference, &fence->reference))
+      FREE(*ptr);
+
+   *ptr = fence;
+}
+
+static boolean
+etna_screen_fence_finish(struct pipe_screen *pscreen, struct pipe_context *ctx,
+                         struct pipe_fence_handle *fence, uint64_t timeout)
+{
+   if (etna_pipe_wait_ns(fence->screen->pipe, fence->timestamp, timeout))
+      return false;
+
+   return true;
+}
+
+struct pipe_fence_handle *
+etna_fence_create(struct pipe_context *pctx)
+{
+   struct pipe_fence_handle *fence;
+   struct etna_context *ctx = etna_context(pctx);
+
+   fence = CALLOC_STRUCT(pipe_fence_handle);
+   if (!fence)
+      return NULL;
+
+   pipe_reference_init(&fence->reference, 1);
+
+   fence->ctx = ctx;
+   fence->screen = ctx->screen;
+   fence->timestamp = etna_cmd_stream_timestamp(ctx->stream);
+
+   return fence;
+}
+
+void
+etna_fence_screen_init(struct pipe_screen *pscreen)
+{
+   pscreen->fence_reference = etna_screen_fence_reference;
+   pscreen->fence_finish = etna_screen_fence_finish;
+}
diff --git a/src/gallium/drivers/etnaviv/etnaviv_fence.h b/src/gallium/drivers/etnaviv/etnaviv_fence.h
new file mode 100644
index 0000000..cd91d2e
--- /dev/null
+++ b/src/gallium/drivers/etnaviv/etnaviv_fence.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2012-2015 Etnaviv Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Wladimir J. van der Laan <laanwj at gmail.com>
+ *    Rob Clark <robclark at freedesktop.org>
+ */
+
+#ifndef ETNAVIV_FENCE_H_
+#define ETNAVIV_FENCE_H_
+
+#include "pipe/p_context.h"
+
+struct pipe_fence_handle *
+etna_fence_create(struct pipe_context *pctx);
+
+void
+etna_fence_screen_init(struct pipe_screen *pscreen);
+
+#endif
diff --git a/src/gallium/drivers/etnaviv/etnaviv_format.c b/src/gallium/drivers/etnaviv/etnaviv_format.c
new file mode 100644
index 0000000..0794603
--- /dev/null
+++ b/src/gallium/drivers/etnaviv/etnaviv_format.c
@@ -0,0 +1,268 @@
+/*
+ * Copyright (c) 2016 Etnaviv Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Christian Gmeiner <christian.gmeiner at gmail.com>
+ */
+
+#include "etnaviv_format.h"
+
+#include "hw/state.xml.h"
+#include "hw/state_3d.xml.h"
+
+#include "pipe/p_defines.h"
+
+/* Specifies the table of all the formats and their features. Also supplies
+ * the helpers that look up various data in those tables.
+ */
+
+struct etna_format {
+   unsigned vtx;
+   unsigned tex;
+   unsigned rs;
+   boolean present;
+};
+
+#define RS_FORMAT_NONE ~0
+
+#define RS_FORMAT_MASK        0xf
+#define RS_FORMAT(x)          ((x) & RS_FORMAT_MASK)
+#define RS_FORMAT_RB_SWAP     0x10
+
+#define RS_FORMAT_X8B8G8R8    (RS_FORMAT_X8R8G8B8 | RS_FORMAT_RB_SWAP)
+#define RS_FORMAT_A8B8G8R8    (RS_FORMAT_A8R8G8B8 | RS_FORMAT_RB_SWAP)
+
+/* vertex + texture */
+#define VT(pipe, vtxfmt, texfmt, rsfmt)                   \
+   [PIPE_FORMAT_##pipe] = {                               \
+      .vtx = VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE_##vtxfmt, \
+      .tex = TEXTURE_FORMAT_##texfmt,                     \
+      .rs = RS_FORMAT_##rsfmt,                            \
+      .present = 1,                                       \
+   }
+
+/* texture-only */
+#define _T(pipe, fmt, rsfmt)       \
+   [PIPE_FORMAT_##pipe] = {        \
+      .vtx = ETNA_NO_MATCH,        \
+      .tex = TEXTURE_FORMAT_##fmt, \
+      .rs = RS_FORMAT_##rsfmt,     \
+      .present = 1,                \
+   }
+
+/* vertex-only */
+#define V_(pipe, fmt, rsfmt)                           \
+   [PIPE_FORMAT_##pipe] = {                            \
+      .vtx = VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE_##fmt, \
+      .tex = ETNA_NO_MATCH,                            \
+      .rs = RS_FORMAT_##rsfmt,                         \
+      .present = 1,                                    \
+   }
+
+static struct etna_format formats[PIPE_FORMAT_COUNT] = {
+   /* 8-bit */
+   V_(R8_UNORM,   UNSIGNED_BYTE, NONE),
+   V_(R8_SNORM,   BYTE,          NONE),
+   V_(R8_UINT,    UNSIGNED_BYTE, NONE),
+   V_(R8_SINT,    BYTE,          NONE),
+   V_(R8_USCALED, UNSIGNED_BYTE, NONE),
+   V_(R8_SSCALED, BYTE,          NONE),
+
+   _T(A8_UNORM, A8, NONE),
+   _T(L8_UNORM, L8, NONE),
+   _T(I8_UNORM, I8, NONE),
+
+   /* 16-bit */
+   V_(R16_UNORM,   UNSIGNED_SHORT, NONE),
+   V_(R16_SNORM,   SHORT,          NONE),
+   V_(R16_UINT,    UNSIGNED_SHORT, NONE),
+   V_(R16_SINT,    SHORT,          NONE),
+   V_(R16_USCALED, UNSIGNED_SHORT, NONE),
+   V_(R16_SSCALED, SHORT,          NONE),
+   V_(R16_FLOAT,   HALF_FLOAT,     NONE),
+
+   _T(B4G4R4A4_UNORM, A4R4G4B4, A4R4G4B4),
+   _T(B4G4R4X4_UNORM, X4R4G4B4, X4R4G4B4),
+
+   _T(Z16_UNORM,      D16,      A4R4G4B4),
+   _T(B5G6R5_UNORM,   R5G6B5,   R5G6B5),
+   _T(B5G5R5A1_UNORM, A1R5G5B5, A1R5G5B5),
+   _T(B5G5R5X1_UNORM, X1R5G5B5, X1R5G5B5),
+
+   V_(R8G8_UNORM,   UNSIGNED_BYTE,  NONE),
+   V_(R8G8_SNORM,   BYTE,           NONE),
+   V_(R8G8_UINT,    UNSIGNED_BYTE,  NONE),
+   V_(R8G8_SINT,    BYTE,           NONE),
+   V_(R8G8_USCALED, UNSIGNED_BYTE,  NONE),
+   V_(R8G8_SSCALED, BYTE,           NONE),
+
+   /* 24-bit */
+   V_(R8G8B8_UNORM,   UNSIGNED_BYTE, NONE),
+   V_(R8G8B8_SNORM,   BYTE,          NONE),
+   V_(R8G8B8_UINT,    UNSIGNED_BYTE, NONE),
+   V_(R8G8B8_SINT,    BYTE,          NONE),
+   V_(R8G8B8_USCALED, UNSIGNED_BYTE, NONE),
+   V_(R8G8B8_SSCALED, BYTE,          NONE),
+
+   /* 32-bit */
+   V_(R32_UNORM,   UNSIGNED_INT, NONE),
+   V_(R32_SNORM,   INT,          NONE),
+   V_(R32_SINT,    INT,          NONE),
+   V_(R32_UINT,    UNSIGNED_INT, NONE),
+   V_(R32_USCALED, UNSIGNED_INT, NONE),
+   V_(R32_SSCALED, INT,          NONE),
+   V_(R32_FLOAT,   FLOAT,        NONE),
+   V_(R32_FIXED,   FIXED,        NONE),
+
+   V_(R16G16_UNORM,   UNSIGNED_SHORT, NONE),
+   V_(R16G16_SNORM,   SHORT,          NONE),
+   V_(R16G16_UINT,    UNSIGNED_SHORT, NONE),
+   V_(R16G16_SINT,    SHORT,          NONE),
+   V_(R16G16_USCALED, UNSIGNED_SHORT, NONE),
+   V_(R16G16_SSCALED, SHORT,          NONE),
+   V_(R16G16_FLOAT,   HALF_FLOAT,     NONE),
+
+   V_(A8B8G8R8_UNORM,   UNSIGNED_BYTE, NONE),
+
+   V_(R8G8B8A8_UNORM,   UNSIGNED_BYTE, A8B8G8R8),
+   V_(R8G8B8A8_SNORM,   BYTE,          A8B8G8R8),
+   _T(R8G8B8X8_UNORM,   X8B8G8R8,      X8B8G8R8),
+   V_(R8G8B8A8_UINT,    UNSIGNED_BYTE, A8B8G8R8),
+   V_(R8G8B8A8_SINT,    BYTE,          A8B8G8R8),
+   V_(R8G8B8A8_USCALED, UNSIGNED_BYTE, A8B8G8R8),
+   V_(R8G8B8A8_SSCALED, BYTE,          A8B8G8R8),
+
+   _T(R8G8B8A8_UNORM, A8B8G8R8, A8B8G8R8),
+   _T(R8G8B8X8_UNORM, X8B8G8R8, X8B8G8R8),
+
+   _T(B8G8R8A8_UNORM, A8R8G8B8, A8R8G8B8),
+   _T(B8G8R8X8_UNORM, X8R8G8B8, X8R8G8B8),
+
+   V_(R10G10B10A2_UNORM,   UNSIGNED_INT_10_10_10_2, NONE),
+   V_(R10G10B10A2_SNORM,   INT_10_10_10_2,          NONE),
+   V_(R10G10B10A2_USCALED, UNSIGNED_INT_10_10_10_2, NONE),
+   V_(R10G10B10A2_SSCALED, INT_10_10_10_2,          NONE),
+
+   _T(X8Z24_UNORM,       D24S8, A8R8G8B8),
+   _T(S8_UINT_Z24_UNORM, D24S8, A8R8G8B8),
+
+   /* 48-bit */
+   V_(R16G16B16_UNORM,   UNSIGNED_SHORT, NONE),
+   V_(R16G16B16_SNORM,   SHORT,          NONE),
+   V_(R16G16B16_UINT,    UNSIGNED_SHORT, NONE),
+   V_(R16G16B16_SINT,    SHORT,          NONE),
+   V_(R16G16B16_USCALED, UNSIGNED_SHORT, NONE),
+   V_(R16G16B16_SSCALED, SHORT,          NONE),
+   V_(R16G16B16_FLOAT,   HALF_FLOAT,     NONE),
+
+   /* 64-bit */
+   V_(R16G16B16A16_UNORM,   UNSIGNED_SHORT, NONE),
+   V_(R16G16B16A16_SNORM,   SHORT,          NONE),
+   V_(R16G16B16A16_UINT,    UNSIGNED_SHORT, NONE),
+   V_(R16G16B16A16_SINT,    SHORT,          NONE),
+   V_(R16G16B16A16_USCALED, UNSIGNED_SHORT, NONE),
+   V_(R16G16B16A16_SSCALED, SHORT,          NONE),
+   V_(R16G16B16A16_FLOAT,   HALF_FLOAT,     NONE),
+
+   V_(R32G32_UNORM,   UNSIGNED_INT, NONE),
+   V_(R32G32_SNORM,   INT,          NONE),
+   V_(R32G32_UINT,    UNSIGNED_INT, NONE),
+   V_(R32G32_SINT,    INT,          NONE),
+   V_(R32G32_USCALED, UNSIGNED_INT, NONE),
+   V_(R32G32_SSCALED, INT,          NONE),
+   V_(R32G32_FLOAT,   FLOAT,        NONE),
+   V_(R32G32_FIXED,   FIXED,        NONE),
+
+   /* 96-bit */
+   V_(R32G32B32_UNORM,   UNSIGNED_INT, NONE),
+   V_(R32G32B32_SNORM,   INT,          NONE),
+   V_(R32G32B32_UINT,    UNSIGNED_INT, NONE),
+   V_(R32G32B32_SINT,    INT,          NONE),
+   V_(R32G32B32_USCALED, UNSIGNED_INT, NONE),
+   V_(R32G32B32_SSCALED, INT,          NONE),
+   V_(R32G32B32_FLOAT,   FLOAT,        NONE),
+   V_(R32G32B32_FIXED,   FIXED,        NONE),
+
+   /* 128-bit */
+   V_(R32G32B32A32_UNORM,   UNSIGNED_INT, NONE),
+   V_(R32G32B32A32_SNORM,   INT,          NONE),
+   V_(R32G32B32A32_UINT,    UNSIGNED_INT, NONE),
+   V_(R32G32B32A32_SINT,    INT,          NONE),
+   V_(R32G32B32A32_USCALED, UNSIGNED_INT, NONE),
+   V_(R32G32B32A32_SSCALED, INT,          NONE),
+   V_(R32G32B32A32_FLOAT,   FLOAT,        NONE),
+   V_(R32G32B32A32_FIXED,   FIXED,        NONE),
+
+   /* compressed */
+   _T(ETC1_RGB8, ETC1, NONE),
+
+   _T(DXT1_RGB,  DXT1,      NONE),
+   _T(DXT1_RGBA, DXT1,      NONE),
+   _T(DXT3_RGBA, DXT2_DXT3, NONE),
+   _T(DXT3_RGBA, DXT2_DXT3, NONE),
+   _T(DXT5_RGBA, DXT4_DXT5, NONE),
+
+   /* YUV */
+   _T(YUYV, YUY2, YUY2),
+   _T(UYVY, UYVY, NONE),
+};
+
+uint32_t
+translate_texture_format(enum pipe_format fmt)
+{
+   /* XXX with TEXTURE_FORMAT_EXT and swizzle on newer chips we can
+    * support much more */
+   if (!formats[fmt].present)
+      return ETNA_NO_MATCH;
+
+   return formats[fmt].tex;
+}
+
+uint32_t
+translate_rs_format(enum pipe_format fmt)
+{
+   if (!formats[fmt].present)
+      return ETNA_NO_MATCH;
+
+   if (formats[fmt].rs == ETNA_NO_MATCH)
+      return ETNA_NO_MATCH;
+
+   return RS_FORMAT(formats[fmt].rs);
+}
+
+int
+translate_rs_format_rb_swap(enum pipe_format fmt)
+{
+   assert(formats[fmt].present);
+
+   return formats[fmt].rs & RS_FORMAT_RB_SWAP;
+}
+
+/* Return type flags for vertex element format */
+uint32_t
+translate_vertex_format_type(enum pipe_format fmt)
+{
+   if (!formats[fmt].present)
+      return ETNA_NO_MATCH;
+
+   return formats[fmt].vtx;
+}
diff --git a/src/gallium/drivers/etnaviv/etnaviv_format.h b/src/gallium/drivers/etnaviv/etnaviv_format.h
new file mode 100644
index 0000000..549dfda
--- /dev/null
+++ b/src/gallium/drivers/etnaviv/etnaviv_format.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2016 Etnaviv Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Christian Gmeiner <christian.gmeiner at gmail.com>
+ */
+
+#ifndef ETNAVIV_FORMAT_H_
+#define ETNAVIV_FORMAT_H_
+
+#include "util/u_format.h"
+#include <stdint.h>
+
+#define ETNA_NO_MATCH (~0)
+
+uint32_t
+translate_texture_format(enum pipe_format fmt);
+
+uint32_t
+translate_rs_format(enum pipe_format fmt);
+
+int
+translate_rs_format_rb_swap(enum pipe_format fmt);
+
+uint32_t
+translate_vertex_format_type(enum pipe_format fmt);
+
+#endif /* ETNAVIV_FORMAT_H_ */
diff --git a/src/gallium/drivers/etnaviv/etnaviv_internal.h b/src/gallium/drivers/etnaviv/etnaviv_internal.h
new file mode 100644
index 0000000..fa75c3e
--- /dev/null
+++ b/src/gallium/drivers/etnaviv/etnaviv_internal.h
@@ -0,0 +1,259 @@
+/*
+ * Copyright (c) 2012-2015 Etnaviv Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef H_ETNA_INTERNAL
+#define H_ETNA_INTERNAL
+
+#include <assert.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+#include "hw/state.xml.h"
+#include "hw/state_3d.xml.h"
+
+#include <etnaviv_drmif.h>
+
+#define ETNA_NUM_INPUTS (16)
+#define ETNA_NUM_VARYINGS 8
+#define ETNA_NUM_LOD (14)
+#define ETNA_NUM_LAYERS (6)
+#define ETNA_MAX_UNIFORMS (256)
+#define ETNA_MAX_PIXELPIPES 2
+
+/* All RS operations must have width%16 = 0 */
+#define ETNA_RS_WIDTH_MASK (16 - 1)
+/* RS tiled operations must have height%4 = 0 */
+#define ETNA_RS_HEIGHT_MASK (3)
+/* PE render targets must be aligned to 64 bytes */
+#define ETNA_PE_ALIGNMENT (64)
+
+/* GPU chip 3D specs */
+struct etna_specs {
+   /* supports SUPERTILE (64x64) tiling? */
+   unsigned can_supertile : 1;
+   /* needs z=(z+w)/2, for older GCxxx */
+   unsigned vs_need_z_div : 1;
+   /* supports trigonometric instructions */
+   unsigned has_sin_cos_sqrt : 1;
+   /* has SIGN/FLOOR/CEIL instructions */
+   unsigned has_sign_floor_ceil : 1;
+   /* can use VS_RANGE, PS_RANGE registers*/
+   unsigned has_shader_range_registers : 1;
+   /* can use any kind of wrapping mode on npot textures */
+   unsigned npot_tex_any_wrap;
+   /* number of bits per TS tile */
+   unsigned bits_per_tile;
+   /* clear value for TS (dependent on bits_per_tile) */
+   uint32_t ts_clear_value;
+   /* base of vertex texture units */
+   unsigned vertex_sampler_offset;
+   /* number of fragment sampler units */
+   unsigned fragment_sampler_count;
+   /* number of vertex sampler units */
+   unsigned vertex_sampler_count;
+   /* size of vertex shader output buffer */
+   unsigned vertex_output_buffer_size;
+   /* maximum number of vertex element configurations */
+   unsigned vertex_max_elements;
+   /* size of a cached vertex (?) */
+   unsigned vertex_cache_size;
+   /* number of shader cores */
+   unsigned shader_core_count;
+   /* number of vertex streams */
+   unsigned stream_count;
+   /* vertex shader memory address*/
+   uint32_t vs_offset;
+   /* pixel shader memory address*/
+   uint32_t ps_offset;
+   /* vertex/fragment shader max instructions */
+   uint32_t max_instructions;
+   /* maximum number of varyings */
+   unsigned max_varyings;
+   /* maximum number of registers */
+   unsigned max_registers;
+   /* maximum vertex uniforms */
+   unsigned max_vs_uniforms;
+   /* maximum pixel uniforms */
+   unsigned max_ps_uniforms;
+   /* maximum texture size */
+   unsigned max_texture_size;
+   /* maximum texture size */
+   unsigned max_rendertarget_size;
+   /* available pixel pipes */
+   unsigned pixel_pipes;
+   /* number of constants */
+   unsigned num_constants;
+};
+
+/* Compiled Gallium state. All the different compiled state atoms are woven
+ * together and uploaded only when it is necessary to synchronize the state,
+ * for example before rendering. */
+
+/* Compiled pipe_blend_color */
+struct compiled_blend_color {
+   uint32_t PE_ALPHA_BLEND_COLOR;
+};
+
+/* Compiled pipe_stencil_ref */
+struct compiled_stencil_ref {
+   uint32_t PE_STENCIL_CONFIG;
+   uint32_t PE_STENCIL_CONFIG_EXT;
+};
+
+/* Compiled pipe_scissor_state */
+struct compiled_scissor_state {
+   uint32_t SE_SCISSOR_LEFT;
+   uint32_t SE_SCISSOR_TOP;
+   uint32_t SE_SCISSOR_RIGHT;
+   uint32_t SE_SCISSOR_BOTTOM;
+};
+
+/* Compiled pipe_viewport_state */
+struct compiled_viewport_state {
+   uint32_t PA_VIEWPORT_SCALE_X;
+   uint32_t PA_VIEWPORT_SCALE_Y;
+   uint32_t PA_VIEWPORT_SCALE_Z;
+   uint32_t PA_VIEWPORT_OFFSET_X;
+   uint32_t PA_VIEWPORT_OFFSET_Y;
+   uint32_t PA_VIEWPORT_OFFSET_Z;
+   uint32_t SE_SCISSOR_LEFT;
+   uint32_t SE_SCISSOR_TOP;
+   uint32_t SE_SCISSOR_RIGHT;
+   uint32_t SE_SCISSOR_BOTTOM;
+   uint32_t PE_DEPTH_NEAR;
+   uint32_t PE_DEPTH_FAR;
+};
+
+/* Compiled pipe_framebuffer_state */
+struct compiled_framebuffer_state {
+   struct pipe_surface *cbuf, *zsbuf; /* keep reference to surfaces */
+   uint32_t GL_MULTI_SAMPLE_CONFIG;
+   uint32_t PE_COLOR_FORMAT;
+   uint32_t PE_DEPTH_CONFIG;
+   struct etna_reloc PE_DEPTH_ADDR;
+   struct etna_reloc PE_PIPE_DEPTH_ADDR[ETNA_MAX_PIXELPIPES];
+   uint32_t PE_DEPTH_STRIDE;
+   uint32_t PE_HDEPTH_CONTROL;
+   uint32_t PE_DEPTH_NORMALIZE;
+   struct etna_reloc PE_COLOR_ADDR;
+   struct etna_reloc PE_PIPE_COLOR_ADDR[ETNA_MAX_PIXELPIPES];
+   uint32_t PE_COLOR_STRIDE;
+   uint32_t SE_SCISSOR_LEFT;
+   uint32_t SE_SCISSOR_TOP;
+   uint32_t SE_SCISSOR_RIGHT;
+   uint32_t SE_SCISSOR_BOTTOM;
+   uint32_t RA_MULTISAMPLE_UNK00E04;
+   uint32_t RA_MULTISAMPLE_UNK00E10[VIVS_RA_MULTISAMPLE_UNK00E10__LEN];
+   uint32_t RA_CENTROID_TABLE[VIVS_RA_CENTROID_TABLE__LEN];
+   uint32_t TS_MEM_CONFIG;
+   uint32_t TS_DEPTH_CLEAR_VALUE;
+   struct etna_reloc TS_DEPTH_STATUS_BASE;
+   struct etna_reloc TS_DEPTH_SURFACE_BASE;
+   uint32_t TS_COLOR_CLEAR_VALUE;
+   struct etna_reloc TS_COLOR_STATUS_BASE;
+   struct etna_reloc TS_COLOR_SURFACE_BASE;
+   bool msaa_mode; /* adds input (and possible temp) to PS */
+};
+
+/* Compiled context->create_vertex_elements_state */
+struct compiled_vertex_elements_state {
+   unsigned num_elements;
+   uint32_t FE_VERTEX_ELEMENT_CONFIG[VIVS_FE_VERTEX_ELEMENT_CONFIG__LEN];
+};
+
+/* Compiled context->set_vertex_buffer result */
+struct compiled_set_vertex_buffer {
+   uint32_t FE_VERTEX_STREAM_CONTROL;
+   struct etna_reloc FE_VERTEX_STREAM_BASE_ADDR;
+};
+
+/* Compiled linked VS+PS shader state */
+struct compiled_shader_state {
+   uint32_t RA_CONTROL;
+   uint32_t PA_ATTRIBUTE_ELEMENT_COUNT;
+   uint32_t PA_CONFIG;
+   uint32_t PA_SHADER_ATTRIBUTES[VIVS_PA_SHADER_ATTRIBUTES__LEN];
+   uint32_t VS_END_PC;
+   uint32_t VS_OUTPUT_COUNT; /* number of outputs if point size per vertex disabled */
+   uint32_t VS_OUTPUT_COUNT_PSIZE; /* number of outputs of point size per vertex enabled */
+   uint32_t VS_INPUT_COUNT;
+   uint32_t VS_TEMP_REGISTER_CONTROL;
+   uint32_t VS_OUTPUT[4];
+   uint32_t VS_INPUT[4];
+   uint32_t VS_LOAD_BALANCING;
+   uint32_t VS_START_PC;
+   uint32_t PS_END_PC;
+   uint32_t PS_OUTPUT_REG;
+   uint32_t PS_INPUT_COUNT;
+   uint32_t PS_INPUT_COUNT_MSAA; /* Adds an input */
+   uint32_t PS_TEMP_REGISTER_CONTROL;
+   uint32_t PS_TEMP_REGISTER_CONTROL_MSAA; /* Adds a temporary if needed to make space for extra input */
+   uint32_t PS_CONTROL;
+   uint32_t PS_START_PC;
+   uint32_t GL_VARYING_TOTAL_COMPONENTS;
+   uint32_t GL_VARYING_NUM_COMPONENTS;
+   uint32_t GL_VARYING_COMPONENT_USE[2];
+   unsigned vs_inst_mem_size;
+   unsigned vs_uniforms_size;
+   unsigned ps_inst_mem_size;
+   unsigned ps_uniforms_size;
+   uint32_t *VS_INST_MEM;
+   uint32_t VS_UNIFORMS[ETNA_MAX_UNIFORMS * 4];
+   uint32_t *PS_INST_MEM;
+   uint32_t PS_UNIFORMS[ETNA_MAX_UNIFORMS * 4];
+};
+
+/* state of some 3d and common registers relevant to etna driver */
+struct etna_3d_state {
+   unsigned vs_uniforms_size;
+   unsigned ps_uniforms_size;
+
+   uint32_t /*01008*/ PS_INPUT_COUNT;
+   uint32_t /*0100C*/ PS_TEMP_REGISTER_CONTROL;
+   uint32_t /*03818*/ GL_MULTI_SAMPLE_CONFIG;
+   uint32_t /*05000*/ VS_UNIFORMS[VIVS_VS_UNIFORMS__LEN];
+   uint32_t /*07000*/ PS_UNIFORMS[VIVS_PS_UNIFORMS__LEN];
+};
+
+/* Helpers to assist creating and setting bitarrays (eg, for varyings).
+ * field_size must be a power of two, and <= 32. */
+#define DEFINE_ETNA_BITARRAY(name, num, field_size) \
+   uint32_t name[(num) * (field_size) / 32]
+
+static inline void
+etna_bitarray_set(uint32_t *array, size_t array_size, size_t field_size,
+                  size_t index, uint32_t value)
+{
+   size_t shift = (index * field_size) % 32;
+   size_t offset = (index * field_size) / 32;
+
+   assert(index < array_size * 32 / field_size);
+   assert(value < 1 << field_size);
+
+   array[offset] |= value << shift;
+}
+
+#define etna_bitarray_set(array, field_size, index, value) \
+   etna_bitarray_set((array), ARRAY_SIZE(array), field_size, index, value)
+
+#endif
diff --git a/src/gallium/drivers/etnaviv/etnaviv_query.c b/src/gallium/drivers/etnaviv/etnaviv_query.c
new file mode 100644
index 0000000..b33e580
--- /dev/null
+++ b/src/gallium/drivers/etnaviv/etnaviv_query.c
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2016 Etnaviv Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Rob Clark <robclark at freedesktop.org>
+ *    Christian Gmeiner <christian.gmeiner at gmail.com>
+ */
+
+#include "pipe/p_screen.h"
+
+#include "etnaviv_context.h"
+#include "etnaviv_query.h"
+#include "etnaviv_query_sw.h"
+
+static struct pipe_query *
+etna_create_query(struct pipe_context *pctx, unsigned query_type,
+                  unsigned index)
+{
+   struct etna_context *ctx = etna_context(pctx);
+   struct etna_query *q;
+
+   q = etna_sw_create_query(ctx, query_type);
+
+   return (struct pipe_query *)q;
+}
+
+static void
+etna_destroy_query(struct pipe_context *pctx, struct pipe_query *pq)
+{
+   struct etna_query *q = etna_query(pq);
+
+   q->funcs->destroy_query(etna_context(pctx), q);
+}
+
+static boolean
+etna_begin_query(struct pipe_context *pctx, struct pipe_query *pq)
+{
+   struct etna_query *q = etna_query(pq);
+
+   return q->funcs->begin_query(etna_context(pctx), q);
+}
+
+static bool
+etna_end_query(struct pipe_context *pctx, struct pipe_query *pq)
+{
+   struct etna_query *q = etna_query(pq);
+
+   q->funcs->end_query(etna_context(pctx), q);
+   return true;
+}
+
+static boolean
+etna_get_query_result(struct pipe_context *pctx, struct pipe_query *pq,
+                      boolean wait, union pipe_query_result *result)
+{
+   struct etna_query *q = etna_query(pq);
+
+   return q->funcs->get_query_result(etna_context(pctx), q, wait, result);
+}
+
+static int
+etna_get_driver_query_info(struct pipe_screen *pscreen, unsigned index,
+                           struct pipe_driver_query_info *info)
+{
+   struct pipe_driver_query_info list[] = {
+      {"prims-emitted", PIPE_QUERY_PRIMITIVES_EMITTED, { 0 }},
+      {"draw-calls", ETNA_QUERY_DRAW_CALLS, { 0 }},
+   };
+
+   if (!info)
+      return ARRAY_SIZE(list);
+
+   if (index >= ARRAY_SIZE(list))
+      return 0;
+
+   *info = list[index];
+
+   return 1;
+}
+
+static void
+etna_set_active_query_state(struct pipe_context *pipe, boolean enable)
+{
+}
+
+void
+etna_query_screen_init(struct pipe_screen *pscreen)
+{
+   pscreen->get_driver_query_info = etna_get_driver_query_info;
+}
+
+void
+etna_query_context_init(struct pipe_context *pctx)
+{
+   pctx->create_query = etna_create_query;
+   pctx->destroy_query = etna_destroy_query;
+   pctx->begin_query = etna_begin_query;
+   pctx->end_query = etna_end_query;
+   pctx->get_query_result = etna_get_query_result;
+   pctx->set_active_query_state = etna_set_active_query_state;
+}
diff --git a/src/gallium/drivers/etnaviv/etnaviv_query.h b/src/gallium/drivers/etnaviv/etnaviv_query.h
new file mode 100644
index 0000000..9a8d579
--- /dev/null
+++ b/src/gallium/drivers/etnaviv/etnaviv_query.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2016 Etnaviv Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Rob Clark <robclark at freedesktop.org>
+ *    Christian Gmeiner <christian.gmeiner at gmail.com>
+ */
+
+#ifndef H_ETNAVIV_QUERY
+#define H_ETNAVIV_QUERY
+
+#include "pipe/p_context.h"
+
+struct etna_context;
+struct etna_query;
+
+struct etna_query_funcs {
+   void (*destroy_query)(struct etna_context *ctx, struct etna_query *q);
+   boolean (*begin_query)(struct etna_context *ctx, struct etna_query *q);
+   void (*end_query)(struct etna_context *ctx, struct etna_query *q);
+   boolean (*get_query_result)(struct etna_context *ctx, struct etna_query *q,
+                               boolean wait, union pipe_query_result *result);
+};
+
+struct etna_query {
+   const struct etna_query_funcs *funcs;
+   bool active;
+   int type;
+};
+
+static inline struct etna_query *
+etna_query(struct pipe_query *pq)
+{
+   return (struct etna_query *)pq;
+}
+
+#define ETNA_QUERY_DRAW_CALLS    (PIPE_QUERY_DRIVER_SPECIFIC + 0)
+
+void
+etna_query_screen_init(struct pipe_screen *pscreen);
+
+void
+etna_query_context_init(struct pipe_context *pctx);
+
+#endif
diff --git a/src/gallium/drivers/etnaviv/etnaviv_query_sw.c b/src/gallium/drivers/etnaviv/etnaviv_query_sw.c
new file mode 100644
index 0000000..d6420d9
--- /dev/null
+++ b/src/gallium/drivers/etnaviv/etnaviv_query_sw.c
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2016 Etnaviv Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Rob Clark <robclark at freedesktop.org>
+ *    Christian Gmeiner <christian.gmeiner at gmail.com>
+ */
+
+#include "os/os_time.h"
+#include "pipe/p_state.h"
+#include "util/u_inlines.h"
+#include "util/u_memory.h"
+#include "util/u_string.h"
+
+#include "etnaviv_context.h"
+#include "etnaviv_query_sw.h"
+
+static void
+etna_sw_destroy_query(struct etna_context *ctx, struct etna_query *q)
+{
+   struct etna_sw_query *sq = etna_sw_query(q);
+
+   FREE(sq);
+}
+
+static uint64_t
+read_counter(struct etna_context *ctx, int type)
+{
+   switch (type) {
+   case PIPE_QUERY_PRIMITIVES_EMITTED:
+      return ctx->stats.prims_emitted;
+   case ETNA_QUERY_DRAW_CALLS:
+      return ctx->stats.draw_calls;
+   }
+
+   return 0;
+}
+
+static boolean
+etna_sw_begin_query(struct etna_context *ctx, struct etna_query *q)
+{
+   struct etna_sw_query *sq = etna_sw_query(q);
+
+   q->active = true;
+   sq->begin_value = read_counter(ctx, q->type);
+
+   return true;
+}
+
+static void
+etna_sw_end_query(struct etna_context *ctx, struct etna_query *q)
+{
+   struct etna_sw_query *sq = etna_sw_query(q);
+
+   q->active = false;
+   sq->end_value = read_counter(ctx, q->type);
+}
+
+static boolean
+etna_sw_get_query_result(struct etna_context *ctx, struct etna_query *q,
+                         boolean wait, union pipe_query_result *result)
+{
+   struct etna_sw_query *sq = etna_sw_query(q);
+
+   if (q->active)
+      return false;
+
+   util_query_clear_result(result, q->type);
+   result->u64 = sq->end_value - sq->begin_value;
+
+   return true;
+}
+
+static const struct etna_query_funcs sw_query_funcs = {
+   .destroy_query = etna_sw_destroy_query,
+   .begin_query = etna_sw_begin_query,
+   .end_query = etna_sw_end_query,
+   .get_query_result = etna_sw_get_query_result,
+};
+
+struct etna_query *
+etna_sw_create_query(struct etna_context *ctx, unsigned query_type)
+{
+   struct etna_sw_query *sq;
+   struct etna_query *q;
+
+   switch (query_type) {
+   case PIPE_QUERY_PRIMITIVES_EMITTED:
+   case ETNA_QUERY_DRAW_CALLS:
+      break;
+   default:
+      return NULL;
+   }
+
+   sq = CALLOC_STRUCT(etna_sw_query);
+   if (!sq)
+      return NULL;
+
+   q = &sq->base;
+   q->funcs = &sw_query_funcs;
+   q->type = query_type;
+
+   return q;
+}
diff --git a/src/gallium/drivers/etnaviv/etnaviv_query_sw.h b/src/gallium/drivers/etnaviv/etnaviv_query_sw.h
new file mode 100644
index 0000000..9de2bc6
--- /dev/null
+++ b/src/gallium/drivers/etnaviv/etnaviv_query_sw.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2016 Etnaviv Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Rob Clark <robclark at freedesktop.org>
+ *    Christian Gmeiner <christian.gmeiner at gmail.com>
+ */
+
+#ifndef H_ETNAVIV_QUERY_SW
+#define H_ETNAVIV_QUERY_SW
+
+#include "etnaviv_query.h"
+
+struct etna_sw_query {
+   struct etna_query base;
+   uint64_t begin_value, end_value;
+};
+
+static inline struct etna_sw_query *
+etna_sw_query(struct etna_query *q)
+{
+   return (struct etna_sw_query *)q;
+}
+
+struct etna_query *
+etna_sw_create_query(struct etna_context *ctx, unsigned query_type);
+
+#endif
diff --git a/src/gallium/drivers/etnaviv/etnaviv_rasterizer.c b/src/gallium/drivers/etnaviv/etnaviv_rasterizer.c
new file mode 100644
index 0000000..4990fd1
--- /dev/null
+++ b/src/gallium/drivers/etnaviv/etnaviv_rasterizer.c
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2012-2015 Etnaviv Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include "etnaviv_rasterizer.h"
+#include "etnaviv_context.h"
+#include "etnaviv_screen.h"
+
+#include "hw/common.xml.h"
+
+#include "etnaviv_translate.h"
+#include "util/u_math.h"
+#include "util/u_memory.h"
+
+void *
+etna_rasterizer_state_create(struct pipe_context *pctx,
+                             const struct pipe_rasterizer_state *so)
+{
+   struct etna_rasterizer_state *cs;
+   struct etna_context *ctx = etna_context(pctx);
+
+    /* Disregard flatshading on GC880+, as a HW bug there seem to disable all
+     * varying interpolation if it's enabled */
+   bool flatshade = ctx->screen->model < 880 ? so->flatshade : false;
+
+   if (so->fill_front != so->fill_back)
+      DBG("Different front and back fill mode not supported");
+
+   cs = CALLOC_STRUCT(etna_rasterizer_state);
+   if (!cs)
+      return NULL;
+
+   cs->base = *so;
+
+   cs->PA_CONFIG = (flatshade ? VIVS_PA_CONFIG_SHADE_MODEL_FLAT : VIVS_PA_CONFIG_SHADE_MODEL_SMOOTH) |
+                   translate_cull_face(so->cull_face, so->front_ccw) |
+                   translate_polygon_mode(so->fill_front) |
+                   COND(so->point_quad_rasterization, VIVS_PA_CONFIG_POINT_SPRITE_ENABLE) |
+                   COND(so->point_size_per_vertex, VIVS_PA_CONFIG_POINT_SIZE_ENABLE) |
+                   COND(VIV_FEATURE(ctx->screen, chipMinorFeatures1, WIDE_LINE), VIVS_PA_CONFIG_WIDE_LINE);
+   cs->PA_LINE_WIDTH = fui(so->line_width / 2.0f);
+   cs->PA_POINT_SIZE = fui(so->point_size / 2.0f);
+   cs->SE_DEPTH_SCALE = fui(so->offset_scale);
+   cs->SE_DEPTH_BIAS = fui(so->offset_units) / 65535.0f;
+   cs->SE_CONFIG = COND(so->line_last_pixel, VIVS_SE_CONFIG_LAST_PIXEL_ENABLE);
+   /* XXX anything else? */
+   /* XXX bottom_edge_rule */
+   cs->PA_SYSTEM_MODE =
+      COND(so->half_pixel_center, VIVS_PA_SYSTEM_MODE_UNK0 | VIVS_PA_SYSTEM_MODE_UNK4);
+
+   /* so->scissor overrides the scissor, defaulting to the whole framebuffer,
+    * with the scissor state */
+   cs->scissor = so->scissor;
+
+   /* point size per vertex adds a vertex shader output */
+   cs->point_size_per_vertex = so->point_size_per_vertex;
+
+   assert(!so->clip_halfz); /* could be supported with shader magic, actually
+                               D3D z is default on older gc */
+
+   return cs;
+}
diff --git a/src/gallium/drivers/etnaviv/etnaviv_rasterizer.h b/src/gallium/drivers/etnaviv/etnaviv_rasterizer.h
new file mode 100644
index 0000000..d715dd0
--- /dev/null
+++ b/src/gallium/drivers/etnaviv/etnaviv_rasterizer.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2012-2015 Etnaviv Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Wladimir J. van der Laan <laanwj at gmail.com>
+ */
+
+#ifndef H_ETNAVIV_RASTERIZER
+#define H_ETNAVIV_RASTERIZER
+
+#include "pipe/p_context.h"
+#include "pipe/p_state.h"
+
+struct etna_rasterizer_state {
+   struct pipe_rasterizer_state base;
+
+   uint32_t PA_CONFIG;
+   uint32_t PA_LINE_WIDTH;
+   uint32_t PA_POINT_SIZE;
+   uint32_t PA_SYSTEM_MODE;
+   uint32_t SE_DEPTH_SCALE;
+   uint32_t SE_DEPTH_BIAS;
+   uint32_t SE_CONFIG;
+   bool point_size_per_vertex;
+   bool scissor;
+};
+
+static inline struct etna_rasterizer_state *
+etna_rasterizer_state(struct pipe_rasterizer_state *rast)
+{
+   return (struct etna_rasterizer_state *)rast;
+}
+
+void *
+etna_rasterizer_state_create(struct pipe_context *pctx,
+                             const struct pipe_rasterizer_state *so);
+
+#endif
diff --git a/src/gallium/drivers/etnaviv/etnaviv_resource.c b/src/gallium/drivers/etnaviv/etnaviv_resource.c
new file mode 100644
index 0000000..aefe65b
--- /dev/null
+++ b/src/gallium/drivers/etnaviv/etnaviv_resource.c
@@ -0,0 +1,438 @@
+/*
+ * Copyright (c) 2012-2015 Etnaviv Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Wladimir J. van der Laan <laanwj at gmail.com>
+ */
+
+#include "etnaviv_resource.h"
+
+#include "hw/common.xml.h"
+
+#include "etnaviv_context.h"
+#include "etnaviv_debug.h"
+#include "etnaviv_screen.h"
+#include "etnaviv_translate.h"
+
+#include "util/u_inlines.h"
+#include "util/u_memory.h"
+
+/* A tile is 4x4 pixels, having 'screen->specs.bits_per_tile' of tile status.
+ * So, in a buffer of N pixels, there are N / (4 * 4) tiles.
+ * We need N * screen->specs.bits_per_tile / (4 * 4) bits of tile status, or
+ * N * screen->specs.bits_per_tile / (4 * 4 * 8) bytes.
+ */
+bool
+etna_screen_resource_alloc_ts(struct pipe_screen *pscreen,
+                              struct etna_resource *rsc)
+{
+   struct etna_screen *screen = etna_screen(pscreen);
+   size_t rt_ts_size, ts_layer_stride, pixels;
+
+   assert(!rsc->ts_bo);
+
+   /* TS only for level 0 -- XXX is this formula correct? */
+   pixels = rsc->levels[0].layer_stride / util_format_get_blocksize(rsc->base.format);
+   ts_layer_stride = align(pixels * screen->specs.bits_per_tile / 0x80, 0x100);
+   rt_ts_size = ts_layer_stride * rsc->base.array_size;
+   if (rt_ts_size == 0)
+      return true;
+
+   DBG_F(ETNA_DBG_RESOURCE_MSGS, "%p: Allocating tile status of size %zu",
+         rsc, rt_ts_size);
+
+   struct etna_bo *rt_ts;
+   rt_ts = etna_bo_new(screen->dev, rt_ts_size, DRM_ETNA_GEM_CACHE_WC);
+
+   if (unlikely(!rt_ts)) {
+      BUG("Problem allocating tile status for resource");
+      return false;
+   }
+
+   rsc->ts_bo = rt_ts;
+   rsc->levels[0].ts_offset = 0;
+   rsc->levels[0].ts_layer_stride = ts_layer_stride;
+   rsc->levels[0].ts_size = rt_ts_size;
+
+   /* It is important to initialize the TS, as random pattern
+    * can result in crashes. Do this on the CPU as this only happens once
+    * per surface anyway and it's a small area, so it may not be worth
+    * queuing this to the GPU. */
+   void *ts_map = etna_bo_map(rt_ts);
+   memset(ts_map, screen->specs.ts_clear_value, rt_ts_size);
+
+   return true;
+}
+
+static boolean
+etna_screen_can_create_resource(struct pipe_screen *pscreen,
+                                const struct pipe_resource *templat)
+{
+   struct etna_screen *screen = etna_screen(pscreen);
+   if (!translate_samples_to_xyscale(templat->nr_samples, NULL, NULL, NULL))
+      return false;
+
+   /* templat->bind is not set here, so we must use the minimum sizes */
+   uint max_size =
+      MIN2(screen->specs.max_rendertarget_size, screen->specs.max_texture_size);
+
+   if (templat->width0 > max_size || templat->height0 > max_size)
+      return false;
+
+   return true;
+}
+
+static unsigned
+setup_miptree(struct etna_resource *rsc, unsigned paddingX, unsigned paddingY,
+              unsigned msaa_xscale, unsigned msaa_yscale)
+{
+   struct pipe_resource *prsc = &rsc->base;
+   unsigned level, size = 0;
+   unsigned width = prsc->width0;
+   unsigned height = prsc->height0;
+   unsigned depth = prsc->depth0;
+
+   for (level = 0; level <= prsc->last_level; level++) {
+      struct etna_resource_level *mip = &rsc->levels[level];
+
+      mip->width = width;
+      mip->height = height;
+      mip->padded_width = align(width * msaa_xscale, paddingX);
+      mip->padded_height = align(height * msaa_yscale, paddingY);
+      mip->stride = util_format_get_stride(prsc->format, mip->padded_width);
+      mip->offset = size;
+      mip->layer_stride = mip->stride * util_format_get_nblocksy(prsc->format, mip->padded_height);
+      mip->size = prsc->array_size * mip->layer_stride;
+
+      /* align levels to 64 bytes to be able to render to them */
+      size += align(mip->size, ETNA_PE_ALIGNMENT) * depth;
+
+      width = u_minify(width, 1);
+      height = u_minify(height, 1);
+      depth = u_minify(depth, 1);
+   }
+
+   return size;
+}
+
+/* Create a new resource object, using the given template info */
+struct pipe_resource *
+etna_resource_alloc(struct pipe_screen *pscreen, unsigned layout,
+                    const struct pipe_resource *templat)
+{
+   struct etna_screen *screen = etna_screen(pscreen);
+   unsigned size;
+
+   DBG_F(ETNA_DBG_RESOURCE_MSGS,
+         "target=%d, format=%s, %ux%ux%u, array_size=%u, "
+         "last_level=%u, nr_samples=%u, usage=%u, bind=%x, flags=%x",
+         templat->target, util_format_name(templat->format), templat->width0,
+         templat->height0, templat->depth0, templat->array_size,
+         templat->last_level, templat->nr_samples, templat->usage,
+         templat->bind, templat->flags);
+
+   /* Determine scaling for antialiasing, allow override using debug flag */
+   int nr_samples = templat->nr_samples;
+   if ((templat->bind & (PIPE_BIND_RENDER_TARGET | PIPE_BIND_DEPTH_STENCIL)) &&
+       !(templat->bind & PIPE_BIND_SAMPLER_VIEW)) {
+      if (DBG_ENABLED(ETNA_DBG_MSAA_2X))
+         nr_samples = 2;
+      if (DBG_ENABLED(ETNA_DBG_MSAA_4X))
+         nr_samples = 4;
+   }
+
+   int msaa_xscale = 1, msaa_yscale = 1;
+   if (!translate_samples_to_xyscale(nr_samples, &msaa_xscale, &msaa_yscale, NULL)) {
+      /* Number of samples not supported */
+      return NULL;
+   }
+
+   /* If we have the TEXTURE_HALIGN feature, we can always align to the
+    * resolve engine's width.  If not, we must not align resources used
+    * only for textures. */
+   bool rs_align = VIV_FEATURE(screen, chipMinorFeatures1, TEXTURE_HALIGN) ||
+                   !etna_resource_sampler_only(templat);
+
+   /* Determine needed padding (alignment of height/width) */
+   unsigned paddingX = 0, paddingY = 0;
+   unsigned halign = TEXTURE_HALIGN_FOUR;
+   etna_layout_multiple(layout, screen->specs.pixel_pipes, rs_align, &paddingX,
+                        &paddingY, &halign);
+   assert(paddingX && paddingY);
+
+   if (templat->bind != PIPE_BUFFER) {
+      unsigned min_paddingY = 4 * screen->specs.pixel_pipes;
+      if (paddingY < min_paddingY)
+         paddingY = min_paddingY;
+   }
+
+   struct etna_resource *rsc = CALLOC_STRUCT(etna_resource);
+
+   if (!rsc)
+      return NULL;
+
+   rsc->base = *templat;
+   rsc->base.screen = pscreen;
+   rsc->base.nr_samples = nr_samples;
+   rsc->layout = layout;
+   rsc->halign = halign;
+
+   pipe_reference_init(&rsc->base.reference, 1);
+   list_inithead(&rsc->list);
+
+   size = setup_miptree(rsc, paddingX, paddingY, msaa_xscale, msaa_yscale);
+
+   struct etna_bo *bo = etna_bo_new(screen->dev, size, DRM_ETNA_GEM_CACHE_WC);
+   if (unlikely(bo == NULL)) {
+      BUG("Problem allocating video memory for resource");
+      return NULL;
+   }
+
+   rsc->bo = bo;
+   rsc->ts_bo = 0; /* TS is only created when first bound to surface */
+
+   if (templat->bind & PIPE_BIND_SCANOUT)
+      rsc->scanout = renderonly_scanout_for_resource(&rsc->base, screen->ro);
+
+   if (DBG_ENABLED(ETNA_DBG_ZERO)) {
+      void *map = etna_bo_map(bo);
+      memset(map, 0, size);
+   }
+
+   return &rsc->base;
+}
+
+static struct pipe_resource *
+etna_resource_create(struct pipe_screen *pscreen,
+                     const struct pipe_resource *templat)
+{
+   struct etna_screen *screen = etna_screen(pscreen);
+
+   /* Figure out what tiling to use -- for now, assume that textures cannot be
+    * supertiled, and cannot be linear.
+    * There is a feature flag SUPERTILED_TEXTURE (not supported on any known hw)
+    * that may allow this, as well
+    * as LINEAR_TEXTURE_SUPPORT (supported on gc880 and gc2000 at least), but
+    * not sure how it works.
+    * Buffers always have LINEAR layout.
+    */
+   unsigned layout = ETNA_LAYOUT_LINEAR;
+   if (etna_resource_sampler_only(templat)) {
+      /* The buffer is only used for texturing, so create something
+       * directly compatible with the sampler.  Such a buffer can
+       * never be rendered to. */
+      layout = ETNA_LAYOUT_TILED;
+
+      if (util_format_is_compressed(templat->format))
+         layout = ETNA_LAYOUT_LINEAR;
+   } else if (templat->target != PIPE_BUFFER) {
+      bool want_multitiled = screen->specs.pixel_pipes > 1;
+      bool want_supertiled = screen->specs.can_supertile && !DBG_ENABLED(ETNA_DBG_NO_SUPERTILE);
+
+      /* Keep single byte blocksized resources as tiled, since we
+       * are unable to use the RS blit to de-tile them. However,
+       * if they're used as a render target or depth/stencil, they
+       * must be multi-tiled for GPUs with multiple pixel pipes.
+       * Ignore depth/stencil here, but it is an error for a render
+       * target.
+       */
+      if (util_format_get_blocksize(templat->format) == 1 &&
+          !(templat->bind & PIPE_BIND_DEPTH_STENCIL)) {
+         assert(!(templat->bind & PIPE_BIND_RENDER_TARGET && want_multitiled));
+         want_multitiled = want_supertiled = false;
+      }
+
+      layout = ETNA_LAYOUT_BIT_TILE;
+      if (want_multitiled)
+         layout |= ETNA_LAYOUT_BIT_MULTI;
+      if (want_supertiled)
+         layout |= ETNA_LAYOUT_BIT_SUPER;
+   }
+
+   if (templat->target == PIPE_TEXTURE_3D)
+      layout = ETNA_LAYOUT_LINEAR;
+
+   return etna_resource_alloc(pscreen, layout, templat);
+}
+
+static void
+etna_resource_destroy(struct pipe_screen *pscreen, struct pipe_resource *prsc)
+{
+   struct etna_resource *rsc = etna_resource(prsc);
+
+   if (rsc->bo)
+      etna_bo_del(rsc->bo);
+
+   if (rsc->ts_bo)
+      etna_bo_del(rsc->ts_bo);
+
+   if (rsc->scanout)
+      renderonly_scanout_destroy(rsc->scanout);
+
+   list_delinit(&rsc->list);
+
+   pipe_resource_reference(&rsc->texture, NULL);
+
+   FREE(rsc);
+}
+
+static struct pipe_resource *
+etna_resource_from_handle(struct pipe_screen *pscreen,
+                          const struct pipe_resource *tmpl,
+                          struct winsys_handle *handle, unsigned usage)
+{
+   struct etna_screen *screen = etna_screen(pscreen);
+   struct etna_resource *rsc = CALLOC_STRUCT(etna_resource);
+   struct etna_resource_level *level = &rsc->levels[0];
+   struct pipe_resource *prsc = &rsc->base;
+   struct pipe_resource *ptiled = NULL;
+
+   DBG("target=%d, format=%s, %ux%ux%u, array_size=%u, last_level=%u, "
+       "nr_samples=%u, usage=%u, bind=%x, flags=%x",
+       tmpl->target, util_format_name(tmpl->format), tmpl->width0,
+       tmpl->height0, tmpl->depth0, tmpl->array_size, tmpl->last_level,
+       tmpl->nr_samples, tmpl->usage, tmpl->bind, tmpl->flags);
+
+   if (!rsc)
+      return NULL;
+
+   *prsc = *tmpl;
+
+   pipe_reference_init(&prsc->reference, 1);
+   list_inithead(&rsc->list);
+   prsc->screen = pscreen;
+
+   rsc->bo = etna_screen_bo_from_handle(pscreen, handle, &level->stride);
+   if (!rsc->bo)
+      goto fail;
+
+   level->width = tmpl->width0;
+   level->height = tmpl->height0;
+
+   /* We will be using the RS to copy with this resource, so we must
+    * ensure that it is appropriately aligned for the RS requirements. */
+   unsigned paddingX = ETNA_RS_WIDTH_MASK + 1;
+   unsigned paddingY = (ETNA_RS_HEIGHT_MASK + 1) * screen->specs.pixel_pipes;
+
+   level->padded_width = align(level->width, paddingX);
+   level->padded_height = align(level->height, paddingY);
+
+   /* The DDX must give us a BO which conforms to our padding size.
+    * The stride of the BO must be greater or equal to our padded
+    * stride. The size of the BO must accomodate the padded height. */
+   if (level->stride < util_format_get_stride(tmpl->format, level->padded_width)) {
+      BUG("BO stride is too small for RS engine width padding");
+      goto fail;
+   }
+   if (etna_bo_size(rsc->bo) < level->stride * level->padded_height) {
+      BUG("BO size is too small for RS engine height padding");
+      goto fail;
+   }
+
+   if (handle->type == DRM_API_HANDLE_TYPE_SHARED && tmpl->bind & PIPE_BIND_RENDER_TARGET) {
+      /* Render targets are linear in Xorg but must be tiled
+      * here. It would be nice if dri_drawable_get_format()
+      * set scanout for these buffers too. */
+      struct etna_resource *tiled;
+
+      ptiled = etna_resource_create(pscreen, tmpl);
+      if (!ptiled)
+         goto fail;
+
+      tiled = etna_resource(ptiled);
+      tiled->scanout = renderonly_scanout_for_prime(prsc, screen->ro);
+      if (!tiled->scanout)
+         goto fail;
+
+      return ptiled;
+   }
+
+   return prsc;
+
+fail:
+   etna_resource_destroy(pscreen, prsc);
+   if (ptiled)
+      etna_resource_destroy(pscreen, ptiled);
+
+   return NULL;
+}
+
+static boolean
+etna_resource_get_handle(struct pipe_screen *pscreen,
+                         struct pipe_context *pctx,
+                         struct pipe_resource *prsc,
+                         struct winsys_handle *handle, unsigned usage)
+{
+   struct etna_resource *rsc = etna_resource(prsc);
+
+   if (renderonly_get_handle(rsc->scanout, handle))
+      return TRUE;
+
+   return etna_screen_bo_get_handle(pscreen, rsc->bo, rsc->levels[0].stride,
+                                    handle);
+}
+
+void
+etna_resource_used(struct etna_context *ctx, struct pipe_resource *prsc,
+                   enum etna_resource_status status)
+{
+   struct etna_resource *rsc;
+
+   if (!prsc)
+      return;
+
+   rsc = etna_resource(prsc);
+   rsc->status |= status;
+
+   /* TODO resources can actually be shared across contexts,
+    * so I'm not sure a single list-head will do the trick? */
+   debug_assert((rsc->pending_ctx == ctx) || !rsc->pending_ctx);
+   list_delinit(&rsc->list);
+   list_addtail(&rsc->list, &ctx->used_resources);
+   rsc->pending_ctx = ctx;
+}
+
+void
+etna_resource_wait(struct pipe_context *pctx, struct etna_resource *rsc)
+{
+   if (rsc->status & ETNA_PENDING_WRITE) {
+      struct pipe_fence_handle *fence;
+      struct pipe_screen *pscreen = pctx->screen;
+
+      pctx->flush(pctx, &fence, 0);
+
+      if (!pscreen->fence_finish(pscreen, pctx, fence, 5000000000ULL))
+         BUG("fence timed out (hung GPU?)");
+
+      pscreen->fence_reference(pscreen, &fence, NULL);
+   }
+}
+
+void
+etna_resource_screen_init(struct pipe_screen *pscreen)
+{
+   pscreen->can_create_resource = etna_screen_can_create_resource;
+   pscreen->resource_create = etna_resource_create;
+   pscreen->resource_from_handle = etna_resource_from_handle;
+   pscreen->resource_get_handle = etna_resource_get_handle;
+   pscreen->resource_destroy = etna_resource_destroy;
+}
diff --git a/src/gallium/drivers/etnaviv/etnaviv_resource.h b/src/gallium/drivers/etnaviv/etnaviv_resource.h
new file mode 100644
index 0000000..a9b288e
--- /dev/null
+++ b/src/gallium/drivers/etnaviv/etnaviv_resource.h
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2012-2015 Etnaviv Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Wladimir J. van der Laan <laanwj at gmail.com>
+ */
+
+#ifndef H_ETNAVIV_RESOURCE
+#define H_ETNAVIV_RESOURCE
+
+#include "etnaviv_internal.h"
+#include "etnaviv_tiling.h"
+#include "pipe/p_state.h"
+#include "util/list.h"
+
+struct pipe_screen;
+
+struct etna_resource_level {
+   unsigned width, padded_width; /* in pixels */
+   unsigned height, padded_height; /* in samples */
+   unsigned offset; /* offset into memory area */
+   uint32_t stride; /* row stride */
+   uint32_t layer_stride; /* layer stride */
+   unsigned size; /* total size of memory area */
+
+   uint32_t ts_offset;
+   uint32_t ts_layer_stride;
+   uint32_t ts_size;
+   uint32_t clear_value; /* clear value of resource level (mainly for TS) */
+};
+
+/* status of queued up but not flushed reads and write operations.
+ * In _transfer_map() we need to know if queued up rendering needs
+ * to be flushed to preserve the order of cpu and gpu access. */
+enum etna_resource_status {
+   ETNA_PENDING_WRITE = 0x01,
+   ETNA_PENDING_READ = 0x02,
+};
+
+struct etna_resource {
+   struct pipe_resource base;
+   struct renderonly_scanout *scanout;
+   uint32_t seqno;
+
+   /* only lod 0 used for non-texture buffers */
+   /* Layout for surface (tiled, multitiled, split tiled, ...) */
+   enum etna_surface_layout layout;
+   /* Horizontal alignment for texture unit (TEXTURE_HALIGN_*) */
+   unsigned halign;
+   struct etna_bo *bo; /* Surface video memory */
+   struct etna_bo *ts_bo; /* Tile status video memory */
+
+   struct etna_resource_level levels[ETNA_NUM_LOD];
+
+   /* When we are rendering to a texture, we need a differently tiled resource */
+   struct pipe_resource *texture;
+
+   enum etna_resource_status status;
+
+   /* resources accessed by queued but not flushed draws are tracked
+    * in the used_resources list. */
+   struct list_head list;
+   struct etna_context *pending_ctx;
+};
+
+/* returns TRUE if a is newer than b */
+static inline bool
+etna_resource_newer(struct etna_resource *a, struct etna_resource *b)
+{
+   return (int)(a->seqno - b->seqno) > 0;
+}
+
+/* returns TRUE if a is older than b */
+static inline bool
+etna_resource_older(struct etna_resource *a, struct etna_resource *b)
+{
+   return (int)(a->seqno - b->seqno) < 0;
+}
+
+/* is the resource only used on the sampler? */
+static inline bool
+etna_resource_sampler_only(const struct pipe_resource *pres)
+{
+   return (pres->bind & (PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_RENDER_TARGET |
+                         PIPE_BIND_DEPTH_STENCIL | PIPE_BIND_BLENDABLE)) ==
+          PIPE_BIND_SAMPLER_VIEW;
+}
+
+static inline struct etna_resource *
+etna_resource(struct pipe_resource *p)
+{
+   return (struct etna_resource *)p;
+}
+
+void
+etna_resource_used(struct etna_context *ctx, struct pipe_resource *prsc,
+                   enum etna_resource_status status);
+
+void
+etna_resource_wait(struct pipe_context *ctx, struct etna_resource *rsc);
+
+static inline void
+resource_read(struct etna_context *ctx, struct pipe_resource *prsc)
+{
+   etna_resource_used(ctx, prsc, ETNA_PENDING_READ);
+}
+
+static inline void
+resource_written(struct etna_context *ctx, struct pipe_resource *prsc)
+{
+   etna_resource_used(ctx, prsc, ETNA_PENDING_WRITE);
+}
+
+/* Allocate Tile Status for an etna resource.
+ * Tile status is a cache of the clear status per tile. This means a smaller
+ * surface has to be cleared which is faster.
+ * This is also called "fast clear". */
+bool
+etna_screen_resource_alloc_ts(struct pipe_screen *pscreen,
+                              struct etna_resource *prsc);
+
+struct pipe_resource *
+etna_resource_alloc(struct pipe_screen *pscreen, unsigned layout,
+                    const struct pipe_resource *templat);
+
+void
+etna_resource_screen_init(struct pipe_screen *pscreen);
+
+#endif
diff --git a/src/gallium/drivers/etnaviv/etnaviv_rs.c b/src/gallium/drivers/etnaviv/etnaviv_rs.c
new file mode 100644
index 0000000..295ca10
--- /dev/null
+++ b/src/gallium/drivers/etnaviv/etnaviv_rs.c
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2012-2015 Etnaviv Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Wladimir J. van der Laan <laanwj at gmail.com>
+ */
+
+#include "etnaviv_rs.h"
+#include "etnaviv_screen.h"
+#include "etnaviv_tiling.h"
+#include "etnaviv_util.h"
+
+#include "hw/common.xml.h"
+#include "hw/state.xml.h"
+#include "hw/state_3d.xml.h"
+
+#include <assert.h>
+
+void
+etna_compile_rs_state(struct etna_context *ctx, struct compiled_rs_state *cs,
+                      const struct rs_state *rs)
+{
+   memset(cs, 0, sizeof(*cs));
+
+   /* TILED and SUPERTILED layout have their strides multiplied with 4 in RS */
+   unsigned source_stride_shift = COND(rs->source_tiling != ETNA_LAYOUT_LINEAR, 2);
+   unsigned dest_stride_shift = COND(rs->dest_tiling != ETNA_LAYOUT_LINEAR, 2);
+
+   /* tiling == ETNA_LAYOUT_MULTI_TILED or ETNA_LAYOUT_MULTI_SUPERTILED? */
+   int source_multi = COND(rs->source_tiling & ETNA_LAYOUT_BIT_MULTI, 1);
+   int dest_multi = COND(rs->dest_tiling & ETNA_LAYOUT_BIT_MULTI, 1);
+
+   /* Vivante RS needs widths to be a multiple of 16 or bad things
+    * happen, such as scribbing over memory, or the GPU hanging,
+    * even for non-tiled formats.  As this is serious, use abort().
+    */
+   if (rs->width & ETNA_RS_WIDTH_MASK)
+      abort();
+
+   /* TODO could just pre-generate command buffer, would simply submit to one memcpy */
+   cs->RS_CONFIG = VIVS_RS_CONFIG_SOURCE_FORMAT(rs->source_format) |
+                   COND(rs->downsample_x, VIVS_RS_CONFIG_DOWNSAMPLE_X) |
+                   COND(rs->downsample_y, VIVS_RS_CONFIG_DOWNSAMPLE_Y) |
+                   COND(rs->source_tiling & 1, VIVS_RS_CONFIG_SOURCE_TILED) |
+                   VIVS_RS_CONFIG_DEST_FORMAT(rs->dest_format) |
+                   COND(rs->dest_tiling & 1, VIVS_RS_CONFIG_DEST_TILED) |
+                   COND(rs->swap_rb, VIVS_RS_CONFIG_SWAP_RB) |
+                   COND(rs->flip, VIVS_RS_CONFIG_FLIP);
+
+   cs->RS_SOURCE_STRIDE = (rs->source_stride << source_stride_shift) |
+                          COND(rs->source_tiling & 2, VIVS_RS_SOURCE_STRIDE_TILING) |
+                          COND(source_multi, VIVS_RS_SOURCE_STRIDE_MULTI);
+
+   cs->source[0].bo = rs->source;
+   cs->source[0].offset = rs->source_offset;
+   cs->source[0].flags = ETNA_RELOC_READ;
+
+   cs->dest[0].bo = rs->dest;
+   cs->dest[0].offset = rs->dest_offset;
+   cs->dest[0].flags = ETNA_RELOC_WRITE;
+
+   cs->RS_DEST_STRIDE = (rs->dest_stride << dest_stride_shift) |
+                        COND(rs->dest_tiling & 2, VIVS_RS_DEST_STRIDE_TILING) |
+                        COND(dest_multi, VIVS_RS_DEST_STRIDE_MULTI);
+
+   if (ctx->specs.pixel_pipes == 1) {
+      cs->RS_WINDOW_SIZE = VIVS_RS_WINDOW_SIZE_WIDTH(rs->width) |
+                           VIVS_RS_WINDOW_SIZE_HEIGHT(rs->height);
+   } else if (ctx->specs.pixel_pipes == 2) {
+      assert((rs->height & 7) == 0); /* GPU hangs happen if height not 8-aligned */
+
+      if (source_multi) {
+         cs->source[1].bo = rs->source;
+         cs->source[1].offset = rs->source_offset + rs->source_stride * rs->source_padded_height / 2;
+         cs->source[1].flags = ETNA_RELOC_READ;
+      }
+
+      if (dest_multi) {
+         cs->dest[1].bo = rs->dest;
+         cs->dest[1].offset = rs->dest_offset + rs->dest_stride * rs->dest_padded_height / 2;
+         cs->dest[1].flags = ETNA_RELOC_WRITE;
+      }
+
+      cs->RS_WINDOW_SIZE = VIVS_RS_WINDOW_SIZE_WIDTH(rs->width) |
+                           VIVS_RS_WINDOW_SIZE_HEIGHT(rs->height / 2);
+   } else {
+      abort();
+   }
+
+   cs->RS_PIPE_OFFSET[0] = VIVS_RS_PIPE_OFFSET_X(0) | VIVS_RS_PIPE_OFFSET_Y(0);
+   cs->RS_PIPE_OFFSET[1] = VIVS_RS_PIPE_OFFSET_X(0) | VIVS_RS_PIPE_OFFSET_Y(rs->height / 2);
+   cs->RS_DITHER[0] = rs->dither[0];
+   cs->RS_DITHER[1] = rs->dither[1];
+   cs->RS_CLEAR_CONTROL = VIVS_RS_CLEAR_CONTROL_BITS(rs->clear_bits) | rs->clear_mode;
+   cs->RS_FILL_VALUE[0] = rs->clear_value[0];
+   cs->RS_FILL_VALUE[1] = rs->clear_value[1];
+   cs->RS_FILL_VALUE[2] = rs->clear_value[2];
+   cs->RS_FILL_VALUE[3] = rs->clear_value[3];
+   cs->RS_EXTRA_CONFIG = VIVS_RS_EXTRA_CONFIG_AA(rs->aa) |
+                         VIVS_RS_EXTRA_CONFIG_ENDIAN(rs->endian_mode);
+}
+
+void
+etna_modify_rs_clearbits(struct compiled_rs_state *cs, uint32_t clear_bits)
+{
+   cs->RS_CLEAR_CONTROL &= ~VIVS_RS_CLEAR_CONTROL_BITS__MASK;
+   cs->RS_CLEAR_CONTROL |= VIVS_RS_CLEAR_CONTROL_BITS(clear_bits);
+}
diff --git a/src/gallium/drivers/etnaviv/etnaviv_rs.h b/src/gallium/drivers/etnaviv/etnaviv_rs.h
new file mode 100644
index 0000000..ec5b659
--- /dev/null
+++ b/src/gallium/drivers/etnaviv/etnaviv_rs.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2012-2013 Etnaviv Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Wladimir J. van der Laan <laanwj at gmail.com>
+ */
+
+#ifndef H_ETNAVIV_RS
+#define H_ETNAVIV_RS
+
+#include "etnaviv_context.h"
+#include <stdint.h>
+
+struct rs_state {
+   uint8_t downsample_x : 1; /* Downsample in x direction */
+   uint8_t downsample_y : 1; /* Downsample in y direction */
+
+   uint8_t source_format; /* RS_FORMAT_XXX */
+   uint8_t source_tiling; /* ETNA_LAYOUT_XXX */
+   uint8_t dest_tiling; /* ETNA_LAYOUT_XXX */
+   uint8_t dest_format; /* RS_FORMAT_XXX */
+   uint8_t swap_rb;
+   uint8_t flip;
+   struct etna_bo *source;
+   uint32_t source_offset;
+   uint32_t source_stride;
+   uint32_t source_padded_height; /* total padded height */
+   struct etna_bo *dest;
+   uint32_t dest_offset;
+   uint32_t dest_stride;
+   uint32_t dest_padded_height; /* total padded height */
+   uint16_t width; /* source width */
+   uint16_t height; /* source height */
+   uint32_t dither[2];
+   uint32_t clear_bits;
+   uint32_t clear_mode; /* VIVS_RS_CLEAR_CONTROL_MODE_XXX */
+   uint32_t clear_value[4];
+   uint8_t aa;
+   uint8_t endian_mode; /* ENDIAN_MODE_XXX */
+};
+
+/* treat this as opaque structure */
+struct compiled_rs_state {
+   uint32_t RS_CONFIG;
+   uint32_t RS_SOURCE_STRIDE;
+   uint32_t RS_DEST_STRIDE;
+   uint32_t RS_WINDOW_SIZE;
+   uint32_t RS_DITHER[2];
+   uint32_t RS_CLEAR_CONTROL;
+   uint32_t RS_FILL_VALUE[4];
+   uint32_t RS_EXTRA_CONFIG;
+   uint32_t RS_PIPE_OFFSET[2];
+
+   struct etna_reloc source[2];
+   struct etna_reloc dest[2];
+};
+
+/* compile RS state struct */
+void
+etna_compile_rs_state(struct etna_context *ctx, struct compiled_rs_state *cs,
+                      const struct rs_state *rs);
+
+/* modify the clear bits value in the compiled RS state */
+void
+etna_modify_rs_clearbits(struct compiled_rs_state *cs, uint32_t clear_bits);
+
+#endif
diff --git a/src/gallium/drivers/etnaviv/etnaviv_screen.c b/src/gallium/drivers/etnaviv/etnaviv_screen.c
new file mode 100644
index 0000000..688c647
--- /dev/null
+++ b/src/gallium/drivers/etnaviv/etnaviv_screen.c
@@ -0,0 +1,812 @@
+/*
+ * Copyright (c) 2012-2015 Etnaviv Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Wladimir J. van der Laan <laanwj at gmail.com>
+ *    Christian Gmeiner <christian.gmeiner at gmail.com>
+ */
+
+#include "etnaviv_screen.h"
+
+#include "hw/common.xml.h"
+
+#include "etnaviv_compiler.h"
+#include "etnaviv_context.h"
+#include "etnaviv_debug.h"
+#include "etnaviv_fence.h"
+#include "etnaviv_format.h"
+#include "etnaviv_query.h"
+#include "etnaviv_resource.h"
+#include "etnaviv_translate.h"
+
+#include "os/os_time.h"
+#include "util/u_math.h"
+#include "util/u_memory.h"
+#include "util/u_string.h"
+
+#include "state_tracker/drm_driver.h"
+
+static const struct debug_named_value debug_options[] = {
+   {"dbg_msgs",       ETNA_DBG_MSGS, "Print debug messages"},
+   {"frame_msgs",     ETNA_DBG_FRAME_MSGS, "Print frame messages"},
+   {"resource_msgs",  ETNA_DBG_RESOURCE_MSGS, "Print resource messages"},
+   {"compiler_msgs",  ETNA_DBG_COMPILER_MSGS, "Print compiler messages"},
+   {"linker_msgs",    ETNA_DBG_LINKER_MSGS, "Print linker messages"},
+   {"dump_shaders",   ETNA_DBG_DUMP_SHADERS, "Dump shaders"},
+   {"no_ts",          ETNA_DBG_NO_TS, "Disable TS"},
+   {"no_autodisable", ETNA_DBG_NO_AUTODISABLE, "Disable autodisable"},
+   {"no_supertile",   ETNA_DBG_NO_SUPERTILE, "Disable supertiles"},
+   {"no_early_z",     ETNA_DBG_NO_EARLY_Z, "Disable early z"},
+   {"cflush_all",     ETNA_DBG_CFLUSH_ALL, "Flush every cash before state update"},
+   {"msaa2x",         ETNA_DBG_MSAA_2X, "Force 2x msaa"},
+   {"msaa4x",         ETNA_DBG_MSAA_4X, "Force 4x msaa"},
+   {"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"},
+   DEBUG_NAMED_VALUE_END
+};
+
+DEBUG_GET_ONCE_FLAGS_OPTION(etna_mesa_debug, "ETNA_MESA_DEBUG", debug_options, 0)
+int etna_mesa_debug = 0;
+
+static void
+etna_screen_destroy(struct pipe_screen *pscreen)
+{
+   struct etna_screen *screen = etna_screen(pscreen);
+
+   if (screen->pipe)
+      etna_pipe_del(screen->pipe);
+
+   if (screen->gpu)
+      etna_gpu_del(screen->gpu);
+
+   if (screen->ro)
+      FREE(screen->ro);
+
+   if (screen->dev)
+      etna_device_del(screen->dev);
+
+   FREE(screen);
+}
+
+static const char *
+etna_screen_get_name(struct pipe_screen *pscreen)
+{
+   struct etna_screen *priv = etna_screen(pscreen);
+   static char buffer[128];
+
+   util_snprintf(buffer, sizeof(buffer), "Vivante GC%x rev %04x", priv->model,
+                 priv->revision);
+
+   return buffer;
+}
+
+static const char *
+etna_screen_get_vendor(struct pipe_screen *pscreen)
+{
+   return "etnaviv";
+}
+
+static const char *
+etna_screen_get_device_vendor(struct pipe_screen *pscreen)
+{
+   return "Vivante";
+}
+
+static int
+etna_screen_get_param(struct pipe_screen *pscreen, enum pipe_cap param)
+{
+   struct etna_screen *screen = etna_screen(pscreen);
+
+   switch (param) {
+   /* Supported features (boolean caps). */
+   case PIPE_CAP_TWO_SIDED_STENCIL:
+   case PIPE_CAP_ANISOTROPIC_FILTER:
+   case PIPE_CAP_POINT_SPRITE:
+   case PIPE_CAP_TEXTURE_SHADOW_MAP:
+   case PIPE_CAP_BLEND_EQUATION_SEPARATE:
+   case PIPE_CAP_TGSI_FS_COORD_ORIGIN_UPPER_LEFT:
+   case PIPE_CAP_TGSI_FS_COORD_PIXEL_CENTER_HALF_INTEGER:
+   case PIPE_CAP_SM3:
+   case PIPE_CAP_TEXTURE_BARRIER:
+   case PIPE_CAP_QUADS_FOLLOW_PROVOKING_VERTEX_CONVENTION:
+   case PIPE_CAP_VERTEX_BUFFER_OFFSET_4BYTE_ALIGNED_ONLY:
+   case PIPE_CAP_VERTEX_BUFFER_STRIDE_4BYTE_ALIGNED_ONLY:
+   case PIPE_CAP_VERTEX_ELEMENT_SRC_OFFSET_4BYTE_ALIGNED_ONLY:
+   case PIPE_CAP_USER_CONSTANT_BUFFERS:
+   case PIPE_CAP_TGSI_TEXCOORD:
+   case PIPE_CAP_VERTEX_COLOR_UNCLAMPED:
+      return 1;
+
+   /* Memory */
+   case PIPE_CAP_CONSTANT_BUFFER_OFFSET_ALIGNMENT:
+      return 256;
+   case PIPE_CAP_MIN_MAP_BUFFER_ALIGNMENT:
+      return 4; /* XXX could easily be supported */
+   case PIPE_CAP_GLSL_FEATURE_LEVEL:
+      return 120;
+
+   case PIPE_CAP_NPOT_TEXTURES:
+      return true; /* VIV_FEATURE(priv->dev, chipMinorFeatures1,
+                      NON_POWER_OF_TWO); */
+
+   case PIPE_CAP_PRIMITIVE_RESTART:
+      return VIV_FEATURE(screen, chipMinorFeatures1, HALTI0);
+
+   case PIPE_CAP_ENDIANNESS:
+      return PIPE_ENDIAN_LITTLE; /* on most Viv hw this is configurable (feature
+                                    ENDIANNESS_CONFIG) */
+
+   /* Unsupported features. */
+   case PIPE_CAP_SEAMLESS_CUBE_MAP:
+   case PIPE_CAP_TEXTURE_SWIZZLE: /* XXX supported on gc2000 */
+   case PIPE_CAP_COMPUTE: /* XXX supported on gc2000 */
+   case PIPE_CAP_MIXED_COLORBUFFER_FORMATS: /* only one colorbuffer supported, so mixing makes no sense */
+   case PIPE_CAP_CONDITIONAL_RENDER: /* no occlusion queries */
+   case PIPE_CAP_TGSI_INSTANCEID: /* no idea, really */
+   case PIPE_CAP_START_INSTANCE: /* instancing not supported AFAIK */
+   case PIPE_CAP_VERTEX_ELEMENT_INSTANCE_DIVISOR: /* instancing not supported AFAIK */
+   case PIPE_CAP_SHADER_STENCIL_EXPORT: /* Fragment shader cannot export stencil value */
+   case PIPE_CAP_MAX_DUAL_SOURCE_RENDER_TARGETS: /* no dual-source supported */
+   case PIPE_CAP_TEXTURE_MULTISAMPLE: /* no texture multisample */
+   case PIPE_CAP_TEXTURE_MIRROR_CLAMP: /* only mirrored repeat */
+   case PIPE_CAP_INDEP_BLEND_ENABLE:
+   case PIPE_CAP_INDEP_BLEND_FUNC:
+   case PIPE_CAP_DEPTH_CLIP_DISABLE:
+   case PIPE_CAP_SEAMLESS_CUBE_MAP_PER_TEXTURE:
+   case PIPE_CAP_TGSI_FS_COORD_ORIGIN_LOWER_LEFT:
+   case PIPE_CAP_TGSI_FS_COORD_PIXEL_CENTER_INTEGER:
+   case PIPE_CAP_TGSI_CAN_COMPACT_CONSTANTS: /* Don't skip strict max uniform limit check */
+   case PIPE_CAP_FRAGMENT_COLOR_CLAMPED:
+   case PIPE_CAP_VERTEX_COLOR_CLAMPED:
+   case PIPE_CAP_USER_VERTEX_BUFFERS:
+   case PIPE_CAP_USER_INDEX_BUFFERS:
+   case PIPE_CAP_TEXTURE_BUFFER_OBJECTS:
+   case PIPE_CAP_TEXTURE_BUFFER_OFFSET_ALIGNMENT:
+   case PIPE_CAP_BUFFER_SAMPLER_VIEW_RGBA_ONLY:
+   case PIPE_CAP_MIXED_FRAMEBUFFER_SIZES: /* TODO: test me out with piglit */
+   case PIPE_CAP_TGSI_VS_LAYER_VIEWPORT:
+   case PIPE_CAP_MAX_TEXTURE_GATHER_COMPONENTS:
+   case PIPE_CAP_TEXTURE_GATHER_SM5:
+   case PIPE_CAP_BUFFER_MAP_PERSISTENT_COHERENT:
+   case PIPE_CAP_FAKE_SW_MSAA:
+   case PIPE_CAP_TEXTURE_QUERY_LOD:
+   case PIPE_CAP_SAMPLE_SHADING:
+   case PIPE_CAP_TEXTURE_GATHER_OFFSETS:
+   case PIPE_CAP_TGSI_VS_WINDOW_SPACE_POSITION:
+   case PIPE_CAP_DRAW_INDIRECT:
+   case PIPE_CAP_TGSI_FS_FINE_DERIVATIVE:
+   case PIPE_CAP_CONDITIONAL_RENDER_INVERTED:
+   case PIPE_CAP_SAMPLER_VIEW_TARGET:
+   case PIPE_CAP_CLIP_HALFZ:
+   case PIPE_CAP_VERTEXID_NOBASE:
+   case PIPE_CAP_POLYGON_OFFSET_CLAMP:
+   case PIPE_CAP_MULTISAMPLE_Z_RESOLVE:
+   case PIPE_CAP_RESOURCE_FROM_USER_MEMORY:
+   case PIPE_CAP_DEVICE_RESET_STATUS_QUERY:
+   case PIPE_CAP_MAX_SHADER_PATCH_VARYINGS:
+   case PIPE_CAP_TEXTURE_FLOAT_LINEAR:
+   case PIPE_CAP_TEXTURE_HALF_FLOAT_LINEAR:
+   case PIPE_CAP_DEPTH_BOUNDS_TEST:
+   case PIPE_CAP_TGSI_TXQS:
+   case PIPE_CAP_FORCE_PERSAMPLE_INTERP:
+   case PIPE_CAP_SHAREABLE_SHADERS:
+   case PIPE_CAP_COPY_BETWEEN_COMPRESSED_AND_PLAIN_FORMATS:
+   case PIPE_CAP_CLEAR_TEXTURE:
+   case PIPE_CAP_DRAW_PARAMETERS:
+   case PIPE_CAP_TGSI_PACK_HALF_FLOAT:
+   case PIPE_CAP_MULTI_DRAW_INDIRECT:
+   case PIPE_CAP_MULTI_DRAW_INDIRECT_PARAMS:
+   case PIPE_CAP_TGSI_FS_POSITION_IS_SYSVAL:
+   case PIPE_CAP_TGSI_FS_FACE_IS_INTEGER_SYSVAL:
+   case PIPE_CAP_SHADER_BUFFER_OFFSET_ALIGNMENT:
+   case PIPE_CAP_INVALIDATE_BUFFER:
+   case PIPE_CAP_GENERATE_MIPMAP:
+   case PIPE_CAP_STRING_MARKER:
+   case PIPE_CAP_SURFACE_REINTERPRET_BLOCKS:
+   case PIPE_CAP_QUERY_BUFFER_OBJECT:
+   case PIPE_CAP_QUERY_MEMORY_INFO:
+   case PIPE_CAP_FRAMEBUFFER_NO_ATTACHMENT:
+   case PIPE_CAP_ROBUST_BUFFER_ACCESS_BEHAVIOR:
+   case PIPE_CAP_CULL_DISTANCE:
+   case PIPE_CAP_PRIMITIVE_RESTART_FOR_PATCHES:
+   case PIPE_CAP_TGSI_VOTE:
+   case PIPE_CAP_MAX_WINDOW_RECTANGLES:
+   case PIPE_CAP_POLYGON_OFFSET_UNITS_UNSCALED:
+   case PIPE_CAP_VIEWPORT_SUBPIXEL_BITS:
+   case PIPE_CAP_MIXED_COLOR_DEPTH_BITS:
+   case PIPE_CAP_TGSI_ARRAY_COMPONENTS:
+   case PIPE_CAP_STREAM_OUTPUT_INTERLEAVE_BUFFERS:
+   case PIPE_CAP_TGSI_CAN_READ_OUTPUTS:
+   case PIPE_CAP_NATIVE_FENCE_FD:
+      return 0;
+
+   /* Stream output. */
+   case PIPE_CAP_MAX_STREAM_OUTPUT_BUFFERS:
+   case PIPE_CAP_STREAM_OUTPUT_PAUSE_RESUME:
+   case PIPE_CAP_MAX_STREAM_OUTPUT_SEPARATE_COMPONENTS:
+   case PIPE_CAP_MAX_STREAM_OUTPUT_INTERLEAVED_COMPONENTS:
+      return 0;
+
+   /* Geometry shader output, unsupported. */
+   case PIPE_CAP_MAX_GEOMETRY_OUTPUT_VERTICES:
+   case PIPE_CAP_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS:
+   case PIPE_CAP_MAX_VERTEX_STREAMS:
+      return 0;
+
+   case PIPE_CAP_MAX_VERTEX_ATTRIB_STRIDE:
+      return 128;
+
+   /* Texturing. */
+   case PIPE_CAP_MAX_TEXTURE_2D_LEVELS:
+   case PIPE_CAP_MAX_TEXTURE_CUBE_LEVELS:
+   {
+      int log2_max_tex_size = util_last_bit(screen->specs.max_texture_size);
+      assert(log2_max_tex_size > 0);
+      return log2_max_tex_size;
+   }
+   case PIPE_CAP_MAX_TEXTURE_3D_LEVELS: /* 3D textures not supported - fake it */
+      return 5;
+   case PIPE_CAP_MAX_TEXTURE_ARRAY_LAYERS:
+      return 0;
+   case PIPE_CAP_CUBE_MAP_ARRAY:
+      return 0;
+   case PIPE_CAP_MIN_TEXTURE_GATHER_OFFSET:
+   case PIPE_CAP_MIN_TEXEL_OFFSET:
+      return -8;
+   case PIPE_CAP_MAX_TEXTURE_GATHER_OFFSET:
+   case PIPE_CAP_MAX_TEXEL_OFFSET:
+      return 7;
+   case PIPE_CAP_TEXTURE_BORDER_COLOR_QUIRK:
+      return 0;
+   case PIPE_CAP_MAX_TEXTURE_BUFFER_SIZE:
+      return 65536;
+
+   /* Render targets. */
+   case PIPE_CAP_MAX_RENDER_TARGETS:
+      return 1;
+
+   /* Viewports and scissors. */
+   case PIPE_CAP_MAX_VIEWPORTS:
+      return 1;
+
+   /* Timer queries. */
+   case PIPE_CAP_QUERY_TIME_ELAPSED:
+   case PIPE_CAP_OCCLUSION_QUERY:
+      return 0;
+   case PIPE_CAP_QUERY_TIMESTAMP:
+      return 1;
+   case PIPE_CAP_QUERY_PIPELINE_STATISTICS:
+      return 0;
+
+   /* Preferences */
+   case PIPE_CAP_PREFER_BLIT_BASED_TEXTURE_TRANSFER:
+      return 0;
+
+   case PIPE_CAP_PCI_GROUP:
+   case PIPE_CAP_PCI_BUS:
+   case PIPE_CAP_PCI_DEVICE:
+   case PIPE_CAP_PCI_FUNCTION:
+      return 0;
+   case PIPE_CAP_VENDOR_ID:
+   case PIPE_CAP_DEVICE_ID:
+      return 0xFFFFFFFF;
+   case PIPE_CAP_ACCELERATED:
+      return 1;
+   case PIPE_CAP_VIDEO_MEMORY:
+      return 0;
+   case PIPE_CAP_UMA:
+      return 1;
+   }
+
+   debug_printf("unknown param %d", param);
+   return 0;
+}
+
+static float
+etna_screen_get_paramf(struct pipe_screen *pscreen, enum pipe_capf param)
+{
+   switch (param) {
+   case PIPE_CAPF_MAX_LINE_WIDTH:
+   case PIPE_CAPF_MAX_LINE_WIDTH_AA:
+   case PIPE_CAPF_MAX_POINT_WIDTH:
+   case PIPE_CAPF_MAX_POINT_WIDTH_AA:
+      return 8192.0f;
+   case PIPE_CAPF_MAX_TEXTURE_ANISOTROPY:
+      return 16.0f;
+   case PIPE_CAPF_MAX_TEXTURE_LOD_BIAS:
+      return 16.0f;
+   case PIPE_CAPF_GUARD_BAND_LEFT:
+   case PIPE_CAPF_GUARD_BAND_TOP:
+   case PIPE_CAPF_GUARD_BAND_RIGHT:
+   case PIPE_CAPF_GUARD_BAND_BOTTOM:
+      return 0.0f;
+   }
+
+   debug_printf("unknown paramf %d", param);
+   return 0;
+}
+
+static int
+etna_screen_get_shader_param(struct pipe_screen *pscreen, unsigned shader,
+                             enum pipe_shader_cap param)
+{
+   struct etna_screen *screen = etna_screen(pscreen);
+
+   switch (shader) {
+   case PIPE_SHADER_FRAGMENT:
+   case PIPE_SHADER_VERTEX:
+      break;
+   case PIPE_SHADER_COMPUTE:
+   case PIPE_SHADER_GEOMETRY:
+   case PIPE_SHADER_TESS_CTRL:
+   case PIPE_SHADER_TESS_EVAL:
+      return 0;
+   default:
+      DBG("unknown shader type %d", shader);
+      return 0;
+   }
+
+   switch (param) {
+   case PIPE_SHADER_CAP_MAX_INSTRUCTIONS:
+   case PIPE_SHADER_CAP_MAX_ALU_INSTRUCTIONS:
+   case PIPE_SHADER_CAP_MAX_TEX_INSTRUCTIONS:
+   case PIPE_SHADER_CAP_MAX_TEX_INDIRECTIONS:
+      return ETNA_MAX_TOKENS;
+   case PIPE_SHADER_CAP_MAX_CONTROL_FLOW_DEPTH:
+      return ETNA_MAX_DEPTH; /* XXX */
+   case PIPE_SHADER_CAP_MAX_INPUTS:
+      /* Maximum number of inputs for the vertex shader is the number
+       * of vertex elements - each element defines one vertex shader
+       * input register.  For the fragment shader, this is the number
+       * of varyings. */
+      return shader == PIPE_SHADER_FRAGMENT ? screen->specs.max_varyings
+                                            : screen->specs.vertex_max_elements;
+   case PIPE_SHADER_CAP_MAX_OUTPUTS:
+      return 16; /* see VIVS_VS_OUTPUT */
+   case PIPE_SHADER_CAP_MAX_TEMPS:
+      return 64; /* Max native temporaries. */
+   case PIPE_SHADER_CAP_MAX_CONST_BUFFERS:
+      return 1;
+   case PIPE_SHADER_CAP_MAX_PREDS:
+      return 0; /* nothing uses this */
+   case PIPE_SHADER_CAP_TGSI_CONT_SUPPORTED:
+      return 1;
+   case PIPE_SHADER_CAP_INDIRECT_INPUT_ADDR:
+   case PIPE_SHADER_CAP_INDIRECT_OUTPUT_ADDR:
+   case PIPE_SHADER_CAP_INDIRECT_TEMP_ADDR:
+   case PIPE_SHADER_CAP_INDIRECT_CONST_ADDR:
+      return 1;
+   case PIPE_SHADER_CAP_SUBROUTINES:
+      return 0;
+   case PIPE_SHADER_CAP_TGSI_SQRT_SUPPORTED:
+      return VIV_FEATURE(screen, chipMinorFeatures0, HAS_SQRT_TRIG);
+   case PIPE_SHADER_CAP_INTEGERS:
+      return 0;
+   case PIPE_SHADER_CAP_MAX_TEXTURE_SAMPLERS:
+   case PIPE_SHADER_CAP_MAX_SAMPLER_VIEWS:
+      return shader == PIPE_SHADER_FRAGMENT
+                ? screen->specs.fragment_sampler_count
+                : screen->specs.vertex_sampler_count;
+   case PIPE_SHADER_CAP_PREFERRED_IR:
+      return PIPE_SHADER_IR_TGSI;
+   case PIPE_SHADER_CAP_MAX_CONST_BUFFER_SIZE:
+      return 4096;
+   case PIPE_SHADER_CAP_DOUBLES:
+   case PIPE_SHADER_CAP_TGSI_DROUND_SUPPORTED:
+   case PIPE_SHADER_CAP_TGSI_DFRACEXP_DLDEXP_SUPPORTED:
+   case PIPE_SHADER_CAP_TGSI_FMA_SUPPORTED:
+   case PIPE_SHADER_CAP_TGSI_ANY_INOUT_DECL_RANGE:
+      return false;
+   case PIPE_SHADER_CAP_SUPPORTED_IRS:
+      return 0;
+   case PIPE_SHADER_CAP_MAX_UNROLL_ITERATIONS_HINT:
+      return 32;
+   case PIPE_SHADER_CAP_MAX_SHADER_BUFFERS:
+   case PIPE_SHADER_CAP_MAX_SHADER_IMAGES:
+   case PIPE_SHADER_CAP_LOWER_IF_THRESHOLD:
+      return 0;
+   }
+
+   debug_printf("unknown shader param %d", param);
+   return 0;
+}
+
+static uint64_t
+etna_screen_get_timestamp(struct pipe_screen *pscreen)
+{
+   return os_time_get_nano();
+}
+
+static bool
+gpu_supports_texure_format(struct etna_screen *screen, uint32_t fmt)
+{
+   if (fmt == TEXTURE_FORMAT_ETC1)
+      return VIV_FEATURE(screen, chipFeatures, ETC1_TEXTURE_COMPRESSION);
+
+   if (fmt >= TEXTURE_FORMAT_DXT1 && fmt <= TEXTURE_FORMAT_DXT4_DXT5)
+      return VIV_FEATURE(screen, chipFeatures, DXT_TEXTURE_COMPRESSION);
+
+   return true;
+}
+
+static boolean
+etna_screen_is_format_supported(struct pipe_screen *pscreen,
+                                enum pipe_format format,
+                                enum pipe_texture_target target,
+                                unsigned sample_count, unsigned usage)
+{
+   struct etna_screen *screen = etna_screen(pscreen);
+   unsigned allowed = 0;
+
+   if (target != PIPE_BUFFER &&
+       target != PIPE_TEXTURE_1D &&
+       target != PIPE_TEXTURE_2D &&
+       target != PIPE_TEXTURE_3D &&
+       target != PIPE_TEXTURE_CUBE &&
+       target != PIPE_TEXTURE_RECT)
+      return FALSE;
+
+   if (usage & PIPE_BIND_RENDER_TARGET) {
+      /* 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) {
+            if (translate_samples_to_xyscale(sample_count, NULL, NULL, NULL) &&
+                translate_msaa_format(format) != ETNA_NO_MATCH) {
+               allowed |= PIPE_BIND_RENDER_TARGET;
+            }
+         } else {
+            allowed |= PIPE_BIND_RENDER_TARGET;
+         }
+      }
+   }
+
+   if (usage & PIPE_BIND_DEPTH_STENCIL) {
+      if (translate_depth_format(format) != ETNA_NO_MATCH)
+         allowed |= PIPE_BIND_DEPTH_STENCIL;
+   }
+
+   if (usage & PIPE_BIND_SAMPLER_VIEW) {
+      uint32_t fmt = translate_texture_format(format);
+
+      if (!gpu_supports_texure_format(screen, fmt))
+         fmt = ETNA_NO_MATCH;
+
+      if (sample_count < 2 && fmt != ETNA_NO_MATCH)
+         allowed |= PIPE_BIND_SAMPLER_VIEW;
+   }
+
+   if (usage & PIPE_BIND_VERTEX_BUFFER) {
+      if (translate_vertex_format_type(format) != ETNA_NO_MATCH)
+         allowed |= PIPE_BIND_VERTEX_BUFFER;
+   }
+
+   if (usage & PIPE_BIND_INDEX_BUFFER) {
+      /* must be supported index format */
+      if (format == PIPE_FORMAT_I8_UINT || format == PIPE_FORMAT_I16_UINT ||
+          (format == PIPE_FORMAT_I32_UINT &&
+           VIV_FEATURE(screen, chipFeatures, 32_BIT_INDICES))) {
+         allowed |= PIPE_BIND_INDEX_BUFFER;
+      }
+   }
+
+   /* Always allowed */
+   allowed |=
+      usage & (PIPE_BIND_DISPLAY_TARGET | PIPE_BIND_SCANOUT | PIPE_BIND_SHARED);
+
+   if (usage != allowed) {
+      DBG("not supported: format=%s, target=%d, sample_count=%d, "
+          "usage=%x, allowed=%x",
+          util_format_name(format), target, sample_count, usage, allowed);
+   }
+
+   return usage == allowed;
+}
+
+static boolean
+etna_get_specs(struct etna_screen *screen)
+{
+   uint64_t val;
+   uint32_t instruction_count;
+
+   if (etna_gpu_get_param(screen->gpu, ETNA_GPU_INSTRUCTION_COUNT, &val)) {
+      DBG("could not get ETNA_GPU_INSTRUCTION_COUNT");
+      goto fail;
+   }
+   instruction_count = val;
+
+   if (etna_gpu_get_param(screen->gpu, ETNA_GPU_VERTEX_OUTPUT_BUFFER_SIZE,
+                          &val)) {
+      DBG("could not get ETNA_GPU_VERTEX_OUTPUT_BUFFER_SIZE");
+      goto fail;
+   }
+   screen->specs.vertex_output_buffer_size = val;
+
+   if (etna_gpu_get_param(screen->gpu, ETNA_GPU_VERTEX_CACHE_SIZE, &val)) {
+      DBG("could not get ETNA_GPU_VERTEX_CACHE_SIZE");
+      goto fail;
+   }
+   screen->specs.vertex_cache_size = val;
+
+   if (etna_gpu_get_param(screen->gpu, ETNA_GPU_SHADER_CORE_COUNT, &val)) {
+      DBG("could not get ETNA_GPU_SHADER_CORE_COUNT");
+      goto fail;
+   }
+   screen->specs.shader_core_count = val;
+
+   if (etna_gpu_get_param(screen->gpu, ETNA_GPU_STREAM_COUNT, &val)) {
+      DBG("could not get ETNA_GPU_STREAM_COUNT");
+      goto fail;
+   }
+   screen->specs.stream_count = val;
+
+   if (etna_gpu_get_param(screen->gpu, ETNA_GPU_REGISTER_MAX, &val)) {
+      DBG("could not get ETNA_GPU_REGISTER_MAX");
+      goto fail;
+   }
+   screen->specs.max_registers = val;
+
+   if (etna_gpu_get_param(screen->gpu, ETNA_GPU_PIXEL_PIPES, &val)) {
+      DBG("could not get ETNA_GPU_PIXEL_PIPES");
+      goto fail;
+   }
+   if (val < 1 && val > ETNA_MAX_PIXELPIPES) {
+      if (val == 0) {
+         fprintf(stderr, "Warning: zero pixel pipes (update kernel?)\n");
+         val = 1;
+      } else {
+         fprintf(stderr, "Error: bad pixel pipes value %u\n",
+                 (unsigned int)val);
+         goto fail;
+      }
+   }
+   screen->specs.pixel_pipes = val;
+
+   if (etna_gpu_get_param(screen->gpu, ETNA_GPU_NUM_CONSTANTS, &val)) {
+      DBG("could not get %s", "ETNA_GPU_NUM_CONSTANTS");
+      goto fail;
+   }
+   if (val == 0) {
+      fprintf(stderr, "Warning: zero num constants (update kernel?)\n");
+      val = 168;
+   }
+   screen->specs.num_constants = val;
+
+   screen->specs.can_supertile =
+      VIV_FEATURE(screen, chipMinorFeatures0, SUPER_TILED);
+   screen->specs.bits_per_tile =
+      VIV_FEATURE(screen, chipMinorFeatures0, 2BITPERTILE) ? 2 : 4;
+   screen->specs.ts_clear_value =
+      VIV_FEATURE(screen, chipMinorFeatures0, 2BITPERTILE) ? 0x55555555
+                                                           : 0x11111111;
+
+   /* vertex and fragment samplers live in one address space */
+   screen->specs.vertex_sampler_offset = 8;
+   screen->specs.fragment_sampler_count = 8;
+   screen->specs.vertex_sampler_count = 4;
+   screen->specs.vs_need_z_div =
+      screen->model < 0x1000 && screen->model != 0x880;
+   screen->specs.has_sin_cos_sqrt =
+      VIV_FEATURE(screen, chipMinorFeatures0, HAS_SQRT_TRIG);
+   screen->specs.has_sign_floor_ceil =
+      VIV_FEATURE(screen, chipMinorFeatures0, HAS_SIGN_FLOOR_CEIL);
+   screen->specs.has_shader_range_registers =
+      screen->model >= 0x1000 || screen->model == 0x880;
+   screen->specs.npot_tex_any_wrap =
+      VIV_FEATURE(screen, chipMinorFeatures1, NON_POWER_OF_TWO);
+
+   if (instruction_count > 256) { /* unified instruction memory? */
+      screen->specs.vs_offset = 0xC000;
+      screen->specs.ps_offset = 0xD000; /* like vivante driver */
+      screen->specs.max_instructions = 256;
+   } else {
+      screen->specs.vs_offset = 0x4000;
+      screen->specs.ps_offset = 0x6000;
+      screen->specs.max_instructions = instruction_count / 2;
+   }
+
+   if (VIV_FEATURE(screen, chipMinorFeatures1, HALTI0)) {
+      screen->specs.max_varyings = 12;
+      screen->specs.vertex_max_elements = 16;
+   } else {
+      screen->specs.max_varyings = 8;
+      /* Etna_viv documentation seems confused over the correct value
+       * here so choose the lower to be safe: HALTI0 says 16 i.s.o.
+       * 10, but VERTEX_ELEMENT_CONFIG register says 16 i.s.o. 12. */
+      screen->specs.vertex_max_elements = 10;
+   }
+
+   /* Etna_viv documentation does not indicate where varyings above 8 are
+    * stored. Moreover, if we are passed more than 8 varyings, we will
+    * walk off the end of some arrays. Limit the maximum number of varyings. */
+   if (screen->specs.max_varyings > ETNA_NUM_VARYINGS)
+      screen->specs.max_varyings = ETNA_NUM_VARYINGS;
+
+   /* from QueryShaderCaps in kernel driver */
+   if (screen->model < chipModel_GC4000) {
+      screen->specs.max_vs_uniforms = 168;
+      screen->specs.max_ps_uniforms = 64;
+   } else {
+      screen->specs.max_vs_uniforms = 256;
+      screen->specs.max_ps_uniforms = 256;
+   }
+
+   screen->specs.max_texture_size =
+      VIV_FEATURE(screen, chipMinorFeatures0, TEXTURE_8K) ? 8192 : 2048;
+   screen->specs.max_rendertarget_size =
+      VIV_FEATURE(screen, chipMinorFeatures0, RENDERTARGET_8K) ? 8192 : 2048;
+
+   return true;
+
+fail:
+   return false;
+}
+
+boolean
+etna_screen_bo_get_handle(struct pipe_screen *pscreen, struct etna_bo *bo,
+                          unsigned stride, struct winsys_handle *whandle)
+{
+   whandle->stride = stride;
+
+   if (whandle->type == DRM_API_HANDLE_TYPE_SHARED) {
+      return etna_bo_get_name(bo, &whandle->handle) == 0;
+   } else if (whandle->type == DRM_API_HANDLE_TYPE_KMS) {
+      whandle->handle = etna_bo_handle(bo);
+      return TRUE;
+   } else if (whandle->type == DRM_API_HANDLE_TYPE_FD) {
+      whandle->handle = etna_bo_dmabuf(bo);
+      return TRUE;
+   } else {
+      return FALSE;
+   }
+}
+
+struct etna_bo *
+etna_screen_bo_from_handle(struct pipe_screen *pscreen,
+                           struct winsys_handle *whandle, unsigned *out_stride)
+{
+   struct etna_screen *screen = etna_screen(pscreen);
+   struct etna_bo *bo;
+
+   if (whandle->type == DRM_API_HANDLE_TYPE_SHARED) {
+      bo = etna_bo_from_name(screen->dev, whandle->handle);
+   } else if (whandle->type == DRM_API_HANDLE_TYPE_FD) {
+      bo = etna_bo_from_dmabuf(screen->dev, whandle->handle);
+   } else {
+      DBG("Attempt to import unsupported handle type %d", whandle->type);
+      return NULL;
+   }
+
+   if (!bo) {
+      DBG("ref name 0x%08x failed", whandle->handle);
+      return NULL;
+   }
+
+   *out_stride = whandle->stride;
+
+   return bo;
+}
+
+struct pipe_screen *
+etna_screen_create(struct etna_device *dev, struct etna_gpu *gpu,
+                   struct renderonly *ro)
+{
+   struct etna_screen *screen = CALLOC_STRUCT(etna_screen);
+   struct pipe_screen *pscreen;
+   uint64_t val;
+
+   if (!screen)
+      return NULL;
+
+   pscreen = &screen->base;
+   screen->dev = dev;
+   screen->gpu = gpu;
+   screen->ro = renderonly_dup(ro);
+
+   if (!screen->ro) {
+      DBG("could not create renderonly object");
+      goto fail;
+   }
+
+   etna_mesa_debug = debug_get_option_etna_mesa_debug();
+
+   /* FIXME: Disable tile status for stability at the moment */
+   etna_mesa_debug |= ETNA_DBG_NO_TS;
+
+   screen->pipe = etna_pipe_new(gpu, ETNA_PIPE_3D);
+   if (!screen->pipe) {
+      DBG("could not create 3d pipe");
+      goto fail;
+   }
+
+   if (etna_gpu_get_param(screen->gpu, ETNA_GPU_MODEL, &val)) {
+      DBG("could not get ETNA_GPU_MODEL");
+      goto fail;
+   }
+   screen->model = val;
+
+   if (etna_gpu_get_param(screen->gpu, ETNA_GPU_REVISION, &val)) {
+      DBG("could not get ETNA_GPU_REVISION");
+      goto fail;
+   }
+   screen->revision = val;
+
+   if (etna_gpu_get_param(screen->gpu, ETNA_GPU_FEATURES_0, &val)) {
+      DBG("could not get ETNA_GPU_FEATURES_0");
+      goto fail;
+   }
+   screen->features[0] = val;
+
+   if (etna_gpu_get_param(screen->gpu, ETNA_GPU_FEATURES_1, &val)) {
+      DBG("could not get ETNA_GPU_FEATURES_1");
+      goto fail;
+   }
+   screen->features[1] = val;
+
+   if (etna_gpu_get_param(screen->gpu, ETNA_GPU_FEATURES_2, &val)) {
+      DBG("could not get ETNA_GPU_FEATURES_2");
+      goto fail;
+   }
+   screen->features[2] = val;
+
+   if (etna_gpu_get_param(screen->gpu, ETNA_GPU_FEATURES_3, &val)) {
+      DBG("could not get ETNA_GPU_FEATURES_3");
+      goto fail;
+   }
+   screen->features[3] = val;
+
+   if (etna_gpu_get_param(screen->gpu, ETNA_GPU_FEATURES_4, &val)) {
+      DBG("could not get ETNA_GPU_FEATURES_4");
+      goto fail;
+   }
+   screen->features[4] = val;
+
+   if (!etna_get_specs(screen))
+      goto fail;
+
+   pscreen->destroy = etna_screen_destroy;
+   pscreen->get_param = etna_screen_get_param;
+   pscreen->get_paramf = etna_screen_get_paramf;
+   pscreen->get_shader_param = etna_screen_get_shader_param;
+
+   pscreen->get_name = etna_screen_get_name;
+   pscreen->get_vendor = etna_screen_get_vendor;
+   pscreen->get_device_vendor = etna_screen_get_device_vendor;
+
+   pscreen->get_timestamp = etna_screen_get_timestamp;
+   pscreen->context_create = etna_context_create;
+   pscreen->is_format_supported = etna_screen_is_format_supported;
+
+   etna_fence_screen_init(pscreen);
+   etna_query_screen_init(pscreen);
+   etna_resource_screen_init(pscreen);
+
+   slab_create_parent(&screen->transfer_pool, sizeof(struct etna_transfer), 16);
+
+   return pscreen;
+
+fail:
+   etna_screen_destroy(pscreen);
+   return NULL;
+}
diff --git a/src/gallium/drivers/etnaviv/etnaviv_screen.h b/src/gallium/drivers/etnaviv/etnaviv_screen.h
new file mode 100644
index 0000000..c33a9e3
--- /dev/null
+++ b/src/gallium/drivers/etnaviv/etnaviv_screen.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2012-2015 Etnaviv Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Wladimir J. van der Laan <laanwj at gmail.com>
+ *    Christian Gmeiner <christian.gmeiner at gmail.com>
+ */
+
+#ifndef H_ETNAVIV_SCREEN
+#define H_ETNAVIV_SCREEN
+
+#include "etnaviv_internal.h"
+
+#include "os/os_thread.h"
+#include "pipe/p_screen.h"
+#include "renderonly/renderonly.h"
+#include "util/slab.h"
+
+struct etna_bo;
+
+/* Enum with indices for each of the feature words */
+enum viv_features_word {
+   viv_chipFeatures = 0,
+   viv_chipMinorFeatures0 = 1,
+   viv_chipMinorFeatures1 = 2,
+   viv_chipMinorFeatures2 = 3,
+   viv_chipMinorFeatures3 = 4,
+   VIV_FEATURES_WORD_COUNT /* Must be last */
+};
+
+/** Convenience macro to probe features from state.xml.h:
+ * VIV_FEATURE(chipFeatures, FAST_CLEAR)
+ * VIV_FEATURE(chipMinorFeatures1, AUTO_DISABLE)
+ */
+#define VIV_FEATURE(screen, word, feature) \
+   ((screen->features[viv_ ## word] & (word ## _ ## feature)) != 0)
+
+struct etna_screen {
+   struct pipe_screen base;
+
+   int refcnt;
+   void *winsys_priv;
+
+   struct etna_device *dev;
+   struct etna_gpu *gpu;
+   struct etna_pipe *pipe;
+   struct renderonly *ro;
+
+   struct slab_parent_pool transfer_pool;
+
+   uint32_t model;
+   uint32_t revision;
+   uint32_t features[5];
+
+   struct etna_specs specs;
+};
+
+static inline struct etna_screen *
+etna_screen(struct pipe_screen *pscreen)
+{
+   return (struct etna_screen *)pscreen;
+}
+
+boolean
+etna_screen_bo_get_handle(struct pipe_screen *pscreen, struct etna_bo *bo,
+                          unsigned stride, struct winsys_handle *whandle);
+
+struct etna_bo *
+etna_screen_bo_from_handle(struct pipe_screen *pscreen,
+                           struct winsys_handle *whandle, unsigned *out_stride);
+
+struct pipe_screen *
+etna_screen_create(struct etna_device *dev, struct etna_gpu *gpu,
+                   struct renderonly *ro);
+
+#endif
diff --git a/src/gallium/drivers/etnaviv/etnaviv_shader.c b/src/gallium/drivers/etnaviv/etnaviv_shader.c
new file mode 100644
index 0000000..8895311
--- /dev/null
+++ b/src/gallium/drivers/etnaviv/etnaviv_shader.c
@@ -0,0 +1,285 @@
+/*
+ * Copyright (c) 2012-2015 Etnaviv Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Wladimir J. van der Laan <laanwj at gmail.com>
+ */
+
+#include "etnaviv_shader.h"
+
+#include "etnaviv_compiler.h"
+#include "etnaviv_context.h"
+#include "etnaviv_debug.h"
+#include "etnaviv_util.h"
+
+#include "util/u_math.h"
+#include "util/u_memory.h"
+
+/* Link vs and fs together: fill in shader_state from vs and fs
+ * as this function is called every time a new fs or vs is bound, the goal is to
+ * do little processing as possible here, and to precompute as much as possible in
+ * the vs/fs shader_object.
+ *
+ * XXX we could cache the link result for a certain set of VS/PS; usually a pair
+ * of VS and PS will be used together anyway.
+ */
+static bool
+etna_link_shaders(struct etna_context *ctx, struct compiled_shader_state *cs,
+                  const struct etna_shader *vs, const struct etna_shader *fs)
+{
+   struct etna_shader_link_info link = { };
+
+   assert(vs->processor == PIPE_SHADER_VERTEX);
+   assert(fs->processor == PIPE_SHADER_FRAGMENT);
+
+#ifdef DEBUG
+   if (DBG_ENABLED(ETNA_DBG_DUMP_SHADERS)) {
+      etna_dump_shader(vs);
+      etna_dump_shader(fs);
+   }
+#endif
+
+   if (etna_link_shader(&link, vs, fs)) {
+      /* linking failed: some fs inputs do not have corresponding
+       * vs outputs */
+      assert(0);
+
+      return false;
+   }
+
+   if (DBG_ENABLED(ETNA_DBG_LINKER_MSGS)) {
+      debug_printf("link result:\n");
+      debug_printf("  vs  -> fs  comps use     pa_attr\n");
+
+      for (int idx = 0; idx < link.num_varyings; ++idx)
+         debug_printf("  t%-2u -> t%-2u %-5.*s %u,%u,%u,%u 0x%08x\n",
+                      link.varyings[idx].reg, idx + 1,
+                      link.varyings[idx].num_components, "xyzw",
+                      link.varyings[idx].use[0], link.varyings[idx].use[1],
+                      link.varyings[idx].use[2], link.varyings[idx].use[3],
+                      link.varyings[idx].pa_attributes);
+   }
+
+   /* set last_varying_2x flag if the last varying has 1 or 2 components */
+   bool last_varying_2x = false;
+   if (link.num_varyings > 0 && link.varyings[link.num_varyings - 1].num_components <= 2)
+      last_varying_2x = true;
+
+   cs->RA_CONTROL = VIVS_RA_CONTROL_UNK0 |
+                    COND(last_varying_2x, VIVS_RA_CONTROL_LAST_VARYING_2X);
+
+   cs->PA_ATTRIBUTE_ELEMENT_COUNT = VIVS_PA_ATTRIBUTE_ELEMENT_COUNT_COUNT(link.num_varyings);
+   for (int idx = 0; idx < link.num_varyings; ++idx)
+      cs->PA_SHADER_ATTRIBUTES[idx] = link.varyings[idx].pa_attributes;
+
+   cs->VS_END_PC = vs->code_size / 4;
+   cs->VS_OUTPUT_COUNT = 1 + link.num_varyings; /* position + varyings */
+
+   /* vs outputs (varyings) */
+   DEFINE_ETNA_BITARRAY(vs_output, 16, 8) = {0};
+   int varid = 0;
+   etna_bitarray_set(vs_output, 8, varid++, vs->vs_pos_out_reg);
+   for (int idx = 0; idx < link.num_varyings; ++idx)
+      etna_bitarray_set(vs_output, 8, varid++, link.varyings[idx].reg);
+   if (vs->vs_pointsize_out_reg >= 0)
+      etna_bitarray_set(vs_output, 8, varid++, vs->vs_pointsize_out_reg); /* pointsize is last */
+
+   for (int idx = 0; idx < ARRAY_SIZE(cs->VS_OUTPUT); ++idx)
+      cs->VS_OUTPUT[idx] = vs_output[idx];
+
+   if (vs->vs_pointsize_out_reg != -1) {
+      /* vertex shader outputs point coordinate, provide extra output and make
+       * sure PA config is
+       * not masked */
+      cs->PA_CONFIG = ~0;
+      cs->VS_OUTPUT_COUNT_PSIZE = cs->VS_OUTPUT_COUNT + 1;
+   } else {
+      /* vertex shader does not output point coordinate, make sure thate
+       * POINT_SIZE_ENABLE is masked
+       * and no extra output is given */
+      cs->PA_CONFIG = ~VIVS_PA_CONFIG_POINT_SIZE_ENABLE;
+      cs->VS_OUTPUT_COUNT_PSIZE = cs->VS_OUTPUT_COUNT;
+   }
+
+   cs->VS_LOAD_BALANCING = vs->vs_load_balancing;
+   cs->VS_START_PC = 0;
+
+   cs->PS_END_PC = fs->code_size / 4;
+   cs->PS_OUTPUT_REG = fs->ps_color_out_reg;
+   cs->PS_INPUT_COUNT =
+      VIVS_PS_INPUT_COUNT_COUNT(link.num_varyings + 1) | /* Number of inputs plus position */
+      VIVS_PS_INPUT_COUNT_UNK8(fs->input_count_unk8);
+   cs->PS_TEMP_REGISTER_CONTROL =
+      VIVS_PS_TEMP_REGISTER_CONTROL_NUM_TEMPS(MAX2(fs->num_temps, link.num_varyings + 1));
+   cs->PS_CONTROL = VIVS_PS_CONTROL_UNK1; /* XXX when can we set BYPASS? */
+   cs->PS_START_PC = 0;
+
+   /* Precompute PS_INPUT_COUNT and TEMP_REGISTER_CONTROL in the case of MSAA
+    * mode, avoids some fumbling in sync_context. */
+   cs->PS_INPUT_COUNT_MSAA =
+      VIVS_PS_INPUT_COUNT_COUNT(link.num_varyings + 2) | /* MSAA adds another input */
+      VIVS_PS_INPUT_COUNT_UNK8(fs->input_count_unk8);
+   cs->PS_TEMP_REGISTER_CONTROL_MSAA =
+      VIVS_PS_TEMP_REGISTER_CONTROL_NUM_TEMPS(MAX2(fs->num_temps, link.num_varyings + 2));
+
+   uint32_t total_components = 0;
+   DEFINE_ETNA_BITARRAY(num_components, ETNA_NUM_VARYINGS, 4) = {0};
+   DEFINE_ETNA_BITARRAY(component_use, 4 * ETNA_NUM_VARYINGS, 2) = {0};
+   for (int idx = 0; idx < link.num_varyings; ++idx) {
+      const struct etna_varying *varying = &link.varyings[idx];
+
+      etna_bitarray_set(num_components, 4, idx, varying->num_components);
+      for (int comp = 0; comp < varying->num_components; ++comp) {
+         etna_bitarray_set(component_use, 2, total_components, varying->use[comp]);
+         total_components += 1;
+      }
+   }
+
+   cs->GL_VARYING_TOTAL_COMPONENTS =
+      VIVS_GL_VARYING_TOTAL_COMPONENTS_NUM(align(total_components, 2));
+   cs->GL_VARYING_NUM_COMPONENTS = num_components[0];
+   cs->GL_VARYING_COMPONENT_USE[0] = component_use[0];
+   cs->GL_VARYING_COMPONENT_USE[1] = component_use[1];
+
+   /* reference instruction memory */
+   cs->vs_inst_mem_size = vs->code_size;
+   cs->VS_INST_MEM = vs->code;
+   cs->ps_inst_mem_size = fs->code_size;
+   cs->PS_INST_MEM = fs->code;
+
+   return true;
+}
+
+bool
+etna_shader_link(struct etna_context *ctx)
+{
+   if (!ctx->vs || !ctx->fs)
+      return false;
+
+   /* re-link vs and fs if needed */
+   return etna_link_shaders(ctx, &ctx->shader_state, ctx->vs, ctx->fs);
+}
+
+static bool
+etna_shader_update_vs_inputs(struct etna_context *ctx,
+                             struct compiled_shader_state *cs,
+                             const struct etna_shader *vs,
+                             const struct compiled_vertex_elements_state *ves)
+{
+   unsigned num_temps, cur_temp, num_vs_inputs;
+
+   if (!vs)
+      return false;
+
+   /* Number of vertex elements determines number of VS inputs. Otherwise,
+    * the GPU crashes. Allocate any unused vertex elements to VS temporary
+    * registers. */
+   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);
+      return false;
+   }
+
+   cur_temp = vs->num_temps;
+   num_temps = num_vs_inputs - vs->infile.num_reg + cur_temp;
+
+   cs->VS_INPUT_COUNT = VIVS_VS_INPUT_COUNT_COUNT(num_vs_inputs) |
+                        VIVS_VS_INPUT_COUNT_UNK8(vs->input_count_unk8);
+   cs->VS_TEMP_REGISTER_CONTROL =
+      VIVS_VS_TEMP_REGISTER_CONTROL_NUM_TEMPS(num_temps);
+
+   /* vs inputs (attributes) */
+   DEFINE_ETNA_BITARRAY(vs_input, 16, 8) = {0};
+   for (int idx = 0; idx < num_vs_inputs; ++idx) {
+      if (idx < vs->infile.num_reg)
+         etna_bitarray_set(vs_input, 8, idx, vs->infile.reg[idx].reg);
+      else
+         etna_bitarray_set(vs_input, 8, idx, cur_temp++);
+   }
+
+   for (int idx = 0; idx < ARRAY_SIZE(cs->VS_INPUT); ++idx)
+      cs->VS_INPUT[idx] = vs_input[idx];
+
+   return true;
+}
+
+bool
+etna_shader_update_vertex(struct etna_context *ctx)
+{
+   return etna_shader_update_vs_inputs(ctx, &ctx->shader_state, ctx->vs,
+                                       ctx->vertex_elements);
+}
+
+static void *
+etna_create_shader_state(struct pipe_context *pctx,
+                         const struct pipe_shader_state *pss)
+{
+   struct etna_context *ctx = etna_context(pctx);
+
+   return etna_compile_shader(&ctx->specs, pss->tokens);
+}
+
+static void
+etna_delete_shader_state(struct pipe_context *pctx, void *ss)
+{
+   etna_destroy_shader(ss);
+}
+
+static void
+etna_bind_fs_state(struct pipe_context *pctx, void *fss_)
+{
+   struct etna_context *ctx = etna_context(pctx);
+   struct etna_shader *fss = fss_;
+
+   if (ctx->fs == fss) /* skip if already bound */
+      return;
+
+   assert(fss == NULL || fss->processor == PIPE_SHADER_FRAGMENT);
+   ctx->fs = fss;
+   ctx->dirty |= ETNA_DIRTY_SHADER;
+}
+
+static void
+etna_bind_vs_state(struct pipe_context *pctx, void *vss_)
+{
+   struct etna_context *ctx = etna_context(pctx);
+   struct etna_shader *vss = vss_;
+
+   if (ctx->vs == vss) /* skip if already bound */
+      return;
+
+   assert(vss == NULL || vss->processor == PIPE_SHADER_VERTEX);
+   ctx->vs = vss;
+   ctx->dirty |= ETNA_DIRTY_SHADER;
+}
+
+void
+etna_shader_init(struct pipe_context *pctx)
+{
+   pctx->create_fs_state = etna_create_shader_state;
+   pctx->bind_fs_state = etna_bind_fs_state;
+   pctx->delete_fs_state = etna_delete_shader_state;
+   pctx->create_vs_state = etna_create_shader_state;
+   pctx->bind_vs_state = etna_bind_vs_state;
+   pctx->delete_vs_state = etna_delete_shader_state;
+}
diff --git a/src/gallium/drivers/etnaviv/etnaviv_shader.h b/src/gallium/drivers/etnaviv/etnaviv_shader.h
new file mode 100644
index 0000000..b309370
--- /dev/null
+++ b/src/gallium/drivers/etnaviv/etnaviv_shader.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2012-2015 Etnaviv Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Wladimir J. van der Laan <laanwj at gmail.com>
+ */
+
+#ifndef H_ETNAVIV_SHADER
+#define H_ETNAVIV_SHADER
+
+#include "pipe/p_state.h"
+
+struct etna_context;
+struct etna_shader;
+struct compiled_shader_state;
+
+bool
+etna_shader_link(struct etna_context *ctx);
+
+bool
+etna_shader_update_vertex(struct etna_context *ctx);
+
+void
+etna_shader_init(struct pipe_context *pctx);
+
+#endif
diff --git a/src/gallium/drivers/etnaviv/etnaviv_state.c b/src/gallium/drivers/etnaviv/etnaviv_state.c
new file mode 100644
index 0000000..2256261
--- /dev/null
+++ b/src/gallium/drivers/etnaviv/etnaviv_state.c
@@ -0,0 +1,664 @@
+/*
+ * Copyright (c) 2012-2015 Etnaviv Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Wladimir J. van der Laan <laanwj at gmail.com>
+ *    Christian Gmeiner <christian.gmeiner at gmail.com>
+ */
+
+#include "etnaviv_state.h"
+
+#include "hw/common.xml.h"
+
+#include "etnaviv_clear_blit.h"
+#include "etnaviv_context.h"
+#include "etnaviv_format.h"
+#include "etnaviv_shader.h"
+#include "etnaviv_surface.h"
+#include "etnaviv_translate.h"
+#include "etnaviv_util.h"
+#include "util/u_helpers.h"
+#include "util/u_inlines.h"
+#include "util/u_math.h"
+#include "util/u_memory.h"
+
+static void
+etna_set_blend_color(struct pipe_context *pctx, const struct pipe_blend_color *bc)
+{
+   struct etna_context *ctx = etna_context(pctx);
+   struct compiled_blend_color *cs = &ctx->blend_color;
+
+   cs->PE_ALPHA_BLEND_COLOR =
+      VIVS_PE_ALPHA_BLEND_COLOR_R(etna_cfloat_to_uint8(bc->color[0])) |
+      VIVS_PE_ALPHA_BLEND_COLOR_G(etna_cfloat_to_uint8(bc->color[1])) |
+      VIVS_PE_ALPHA_BLEND_COLOR_B(etna_cfloat_to_uint8(bc->color[2])) |
+      VIVS_PE_ALPHA_BLEND_COLOR_A(etna_cfloat_to_uint8(bc->color[3]));
+   ctx->dirty |= ETNA_DIRTY_BLEND_COLOR;
+}
+
+static void
+etna_set_stencil_ref(struct pipe_context *pctx, const struct pipe_stencil_ref *sr)
+{
+   struct etna_context *ctx = etna_context(pctx);
+   struct compiled_stencil_ref *cs = &ctx->stencil_ref;
+
+   ctx->stencil_ref_s = *sr;
+
+   cs->PE_STENCIL_CONFIG = VIVS_PE_STENCIL_CONFIG_REF_FRONT(sr->ref_value[0]);
+   /* rest of bits weaved in from depth_stencil_alpha */
+   cs->PE_STENCIL_CONFIG_EXT =
+      VIVS_PE_STENCIL_CONFIG_EXT_REF_BACK(sr->ref_value[0]);
+   ctx->dirty |= ETNA_DIRTY_STENCIL_REF;
+}
+
+static void
+etna_set_clip_state(struct pipe_context *pctx, const struct pipe_clip_state *pcs)
+{
+   /* NOOP */
+}
+
+static void
+etna_set_sample_mask(struct pipe_context *pctx, unsigned sample_mask)
+{
+   struct etna_context *ctx = etna_context(pctx);
+
+   ctx->sample_mask = sample_mask;
+   ctx->dirty |= ETNA_DIRTY_SAMPLE_MASK;
+}
+
+static void
+etna_set_constant_buffer(struct pipe_context *pctx, uint shader, uint index,
+      const struct pipe_constant_buffer *cb)
+{
+   struct etna_context *ctx = etna_context(pctx);
+
+   if (unlikely(index > 0)) {
+      DBG("Unhandled buffer index %i", index);
+      return;
+   }
+
+
+   util_copy_constant_buffer(&ctx->constant_buffer[shader], cb);
+
+   /* Note that the state tracker can unbind constant buffers by
+    * passing NULL here. */
+   if (unlikely(!cb))
+      return;
+
+   /* there is no support for ARB_uniform_buffer_object */
+   assert(cb->buffer == NULL && cb->user_buffer != NULL);
+
+   ctx->dirty |= ETNA_DIRTY_CONSTBUF;
+}
+
+static void
+etna_update_render_resource(struct pipe_context *pctx, struct pipe_resource *pres)
+{
+   struct etna_resource *res = etna_resource(pres);
+
+   if (res->texture && etna_resource_older(res, etna_resource(res->texture))) {
+      /* The render buffer is older than the texture buffer. Copy it over. */
+      etna_copy_resource(pctx, pres, res->texture, 0, pres->last_level);
+      res->seqno = etna_resource(res->texture)->seqno;
+   }
+}
+
+static void
+etna_set_framebuffer_state(struct pipe_context *pctx,
+      const struct pipe_framebuffer_state *sv)
+{
+   struct etna_context *ctx = etna_context(pctx);
+   struct compiled_framebuffer_state *cs = &ctx->framebuffer;
+   int nr_samples_color = -1;
+   int nr_samples_depth = -1;
+
+   /* Set up TS as well. Warning: this state is used by both the RS and PE */
+   uint32_t ts_mem_config = 0;
+
+   if (sv->nr_cbufs > 0) { /* at least one color buffer? */
+      struct etna_surface *cbuf = etna_surface(sv->cbufs[0]);
+      struct etna_resource *res = etna_resource(cbuf->base.texture);
+      bool color_supertiled = (res->layout & ETNA_LAYOUT_BIT_SUPER) != 0;
+
+      assert(res->layout & ETNA_LAYOUT_BIT_TILE); /* Cannot render to linear surfaces */
+      etna_update_render_resource(pctx, cbuf->base.texture);
+
+      pipe_surface_reference(&cs->cbuf, &cbuf->base);
+      cs->PE_COLOR_FORMAT =
+         VIVS_PE_COLOR_FORMAT_FORMAT(translate_rs_format(cbuf->base.format)) |
+         VIVS_PE_COLOR_FORMAT_COMPONENTS__MASK |
+         VIVS_PE_COLOR_FORMAT_OVERWRITE |
+         COND(color_supertiled, VIVS_PE_COLOR_FORMAT_SUPER_TILED);
+      /* VIVS_PE_COLOR_FORMAT_COMPONENTS() and
+       * VIVS_PE_COLOR_FORMAT_OVERWRITE comes from blend_state
+       * but only if we set the bits above. */
+      /* merged with depth_stencil_alpha */
+      if ((cbuf->surf.offset & 63) ||
+          (((cbuf->surf.stride * 4) & 63) && cbuf->surf.height > 4)) {
+         /* XXX Must make temporary surface here.
+          * Need the same mechanism on gc2000 when we want to do mipmap
+          * generation by
+          * rendering to levels > 1 due to multitiled / tiled conversion. */
+         BUG("Alignment error, trying to render to offset %08x with tile "
+             "stride %i",
+             cbuf->surf.offset, cbuf->surf.stride * 4);
+      }
+
+      if (ctx->specs.pixel_pipes == 1) {
+         cs->PE_COLOR_ADDR = cbuf->reloc[0];
+         cs->PE_COLOR_ADDR.flags = ETNA_RELOC_READ | ETNA_RELOC_WRITE;
+      } else {
+         /* Rendered textures must always be multi-tiled */
+         assert(res->layout & ETNA_LAYOUT_BIT_MULTI);
+         for (int i = 0; i < ctx->specs.pixel_pipes; i++) {
+            cs->PE_PIPE_COLOR_ADDR[i] = cbuf->reloc[i];
+            cs->PE_PIPE_COLOR_ADDR[i].flags = ETNA_RELOC_READ | ETNA_RELOC_WRITE;
+         }
+      }
+      cs->PE_COLOR_STRIDE = cbuf->surf.stride;
+
+      if (cbuf->surf.ts_size) {
+         ts_mem_config |= VIVS_TS_MEM_CONFIG_COLOR_FAST_CLEAR;
+         cs->TS_COLOR_CLEAR_VALUE = cbuf->level->clear_value;
+
+         cs->TS_COLOR_STATUS_BASE = cbuf->ts_reloc;
+         cs->TS_COLOR_STATUS_BASE.flags = ETNA_RELOC_READ | ETNA_RELOC_WRITE;
+
+         cs->TS_COLOR_SURFACE_BASE = cbuf->reloc[0];
+         cs->TS_COLOR_SURFACE_BASE.flags = ETNA_RELOC_READ | ETNA_RELOC_WRITE;
+      }
+
+      /* MSAA */
+      if (cbuf->base.texture->nr_samples > 1)
+         ts_mem_config |=
+            VIVS_TS_MEM_CONFIG_MSAA | translate_msaa_format(cbuf->base.format);
+
+      nr_samples_color = cbuf->base.texture->nr_samples;
+   } else {
+      pipe_surface_reference(&cs->cbuf, NULL);
+      /* Clearing VIVS_PE_COLOR_FORMAT_COMPONENTS__MASK and
+       * VIVS_PE_COLOR_FORMAT_OVERWRITE prevents us from overwriting the
+       * color target */
+      cs->PE_COLOR_FORMAT = 0;
+      cs->PE_COLOR_STRIDE = 0;
+      cs->TS_COLOR_STATUS_BASE.bo = NULL;
+      cs->TS_COLOR_SURFACE_BASE.bo = NULL;
+
+      for (int i = 0; i < ETNA_MAX_PIXELPIPES; i++)
+         cs->PE_PIPE_COLOR_ADDR[i].bo = NULL;
+   }
+
+   if (sv->zsbuf != NULL) {
+      struct etna_surface *zsbuf = etna_surface(sv->zsbuf);
+      struct etna_resource *res = etna_resource(zsbuf->base.texture);
+
+      etna_update_render_resource(pctx, zsbuf->base.texture);
+
+      pipe_surface_reference(&cs->zsbuf, &zsbuf->base);
+      assert(res->layout &ETNA_LAYOUT_BIT_TILE); /* Cannot render to linear surfaces */
+
+      uint32_t depth_format = translate_depth_format(zsbuf->base.format);
+      unsigned depth_bits =
+         depth_format == VIVS_PE_DEPTH_CONFIG_DEPTH_FORMAT_D16 ? 16 : 24;
+      bool depth_supertiled = (res->layout & ETNA_LAYOUT_BIT_SUPER) != 0;
+
+      cs->PE_DEPTH_CONFIG =
+         depth_format |
+         COND(depth_supertiled, VIVS_PE_DEPTH_CONFIG_SUPER_TILED) |
+         VIVS_PE_DEPTH_CONFIG_DEPTH_MODE_Z;
+      /* VIVS_PE_DEPTH_CONFIG_ONLY_DEPTH */
+      /* merged with depth_stencil_alpha */
+
+      if (ctx->specs.pixel_pipes == 1) {
+         cs->PE_DEPTH_ADDR = zsbuf->reloc[0];
+         cs->PE_DEPTH_ADDR.flags = ETNA_RELOC_READ | ETNA_RELOC_WRITE;
+      } else {
+         for (int i = 0; i < ctx->specs.pixel_pipes; i++) {
+            cs->PE_PIPE_DEPTH_ADDR[i] = zsbuf->reloc[i];
+            cs->PE_PIPE_DEPTH_ADDR[i].flags = ETNA_RELOC_READ | ETNA_RELOC_WRITE;
+         }
+      }
+
+      cs->PE_DEPTH_STRIDE = zsbuf->surf.stride;
+      cs->PE_HDEPTH_CONTROL = VIVS_PE_HDEPTH_CONTROL_FORMAT_DISABLED;
+      cs->PE_DEPTH_NORMALIZE = fui(exp2f(depth_bits) - 1.0f);
+
+      if (zsbuf->surf.ts_size) {
+         ts_mem_config |= VIVS_TS_MEM_CONFIG_DEPTH_FAST_CLEAR;
+         cs->TS_DEPTH_CLEAR_VALUE = zsbuf->level->clear_value;
+
+         cs->TS_DEPTH_STATUS_BASE = zsbuf->ts_reloc;
+         cs->TS_DEPTH_STATUS_BASE.flags = ETNA_RELOC_READ | ETNA_RELOC_WRITE;
+
+         cs->TS_DEPTH_SURFACE_BASE = zsbuf->reloc[0];
+         cs->TS_DEPTH_SURFACE_BASE.flags = ETNA_RELOC_READ | ETNA_RELOC_WRITE;
+      }
+
+      ts_mem_config |= COND(depth_bits == 16, VIVS_TS_MEM_CONFIG_DEPTH_16BPP);
+
+      /* MSAA */
+      if (zsbuf->base.texture->nr_samples > 1)
+         /* XXX VIVS_TS_MEM_CONFIG_DEPTH_COMPRESSION;
+          * Disable without MSAA for now, as it causes corruption in glquake. */
+         ts_mem_config |= VIVS_TS_MEM_CONFIG_DEPTH_COMPRESSION;
+
+      nr_samples_depth = zsbuf->base.texture->nr_samples;
+   } else {
+      pipe_surface_reference(&cs->zsbuf, NULL);
+      cs->PE_DEPTH_CONFIG = VIVS_PE_DEPTH_CONFIG_DEPTH_MODE_NONE;
+      cs->PE_DEPTH_ADDR.bo = NULL;
+      cs->PE_DEPTH_STRIDE = 0;
+      cs->TS_DEPTH_STATUS_BASE.bo = NULL;
+      cs->TS_DEPTH_SURFACE_BASE.bo = NULL;
+
+      for (int i = 0; i < ETNA_MAX_PIXELPIPES; i++)
+         cs->PE_PIPE_DEPTH_ADDR[i].bo = NULL;
+   }
+
+   /* MSAA setup */
+   if (nr_samples_depth != -1 && nr_samples_color != -1 &&
+       nr_samples_depth != nr_samples_color) {
+      BUG("Number of samples in color and depth texture must match (%i and %i respectively)",
+          nr_samples_color, nr_samples_depth);
+   }
+
+   switch (MAX2(nr_samples_depth, nr_samples_color)) {
+   case 0:
+   case 1: /* Are 0 and 1 samples allowed? */
+      cs->GL_MULTI_SAMPLE_CONFIG =
+         VIVS_GL_MULTI_SAMPLE_CONFIG_MSAA_SAMPLES_NONE;
+      cs->msaa_mode = false;
+      break;
+   case 2:
+      cs->GL_MULTI_SAMPLE_CONFIG = VIVS_GL_MULTI_SAMPLE_CONFIG_MSAA_SAMPLES_2X;
+      cs->msaa_mode = true; /* Add input to PS */
+      cs->RA_MULTISAMPLE_UNK00E04 = 0x0;
+      cs->RA_MULTISAMPLE_UNK00E10[0] = 0x0000aa22;
+      cs->RA_CENTROID_TABLE[0] = 0x66aa2288;
+      cs->RA_CENTROID_TABLE[1] = 0x88558800;
+      cs->RA_CENTROID_TABLE[2] = 0x88881100;
+      cs->RA_CENTROID_TABLE[3] = 0x33888800;
+      break;
+   case 4:
+      cs->GL_MULTI_SAMPLE_CONFIG = VIVS_GL_MULTI_SAMPLE_CONFIG_MSAA_SAMPLES_4X;
+      cs->msaa_mode = true; /* Add input to PS */
+      cs->RA_MULTISAMPLE_UNK00E04 = 0x0;
+      cs->RA_MULTISAMPLE_UNK00E10[0] = 0xeaa26e26;
+      cs->RA_MULTISAMPLE_UNK00E10[1] = 0xe6ae622a;
+      cs->RA_MULTISAMPLE_UNK00E10[2] = 0xaaa22a22;
+      cs->RA_CENTROID_TABLE[0] = 0x4a6e2688;
+      cs->RA_CENTROID_TABLE[1] = 0x888888a2;
+      cs->RA_CENTROID_TABLE[2] = 0x888888ea;
+      cs->RA_CENTROID_TABLE[3] = 0x888888c6;
+      cs->RA_CENTROID_TABLE[4] = 0x46622a88;
+      cs->RA_CENTROID_TABLE[5] = 0x888888ae;
+      cs->RA_CENTROID_TABLE[6] = 0x888888e6;
+      cs->RA_CENTROID_TABLE[7] = 0x888888ca;
+      cs->RA_CENTROID_TABLE[8] = 0x262a2288;
+      cs->RA_CENTROID_TABLE[9] = 0x886688a2;
+      cs->RA_CENTROID_TABLE[10] = 0x888866aa;
+      cs->RA_CENTROID_TABLE[11] = 0x668888a6;
+      break;
+   }
+
+   /* Scissor setup */
+   cs->SE_SCISSOR_LEFT = 0; /* affected by rasterizer and scissor state as well */
+   cs->SE_SCISSOR_TOP = 0;
+   cs->SE_SCISSOR_RIGHT = (sv->width << 16) - 1;
+   cs->SE_SCISSOR_BOTTOM = (sv->height << 16) - 1;
+
+   cs->TS_MEM_CONFIG = ts_mem_config;
+
+   ctx->framebuffer_s = *sv; /* keep copy of original structure */
+   ctx->dirty |= ETNA_DIRTY_FRAMEBUFFER;
+}
+
+static void
+etna_set_polygon_stipple(struct pipe_context *pctx,
+      const struct pipe_poly_stipple *stipple)
+{
+   /* NOP */
+}
+
+static void
+etna_set_scissor_states(struct pipe_context *pctx, unsigned start_slot,
+      unsigned num_scissors, const struct pipe_scissor_state *ss)
+{
+   struct etna_context *ctx = etna_context(pctx);
+   struct compiled_scissor_state *cs = &ctx->scissor;
+
+   /* note that this state is only used when rasterizer_state->scissor is on */
+   ctx->scissor_s = *ss;
+   cs->SE_SCISSOR_LEFT = (ss->minx << 16);
+   cs->SE_SCISSOR_TOP = (ss->miny << 16);
+   cs->SE_SCISSOR_RIGHT = (ss->maxx << 16) - 1;
+   cs->SE_SCISSOR_BOTTOM = (ss->maxy << 16) - 1;
+
+   ctx->dirty |= ETNA_DIRTY_SCISSOR;
+}
+
+static void
+etna_set_viewport_states(struct pipe_context *pctx, unsigned start_slot,
+      unsigned num_scissors, const struct pipe_viewport_state *vs)
+{
+   struct etna_context *ctx = etna_context(pctx);
+   struct compiled_viewport_state *cs = &ctx->viewport;
+
+   ctx->viewport_s = *vs;
+   /**
+    * For Vivante GPU, viewport z transformation is 0..1 to 0..1 instead of
+    * -1..1 to 0..1.
+    * scaling and translation to 0..1 already happened, so remove that
+    *
+    * z' = (z * 2 - 1) * scale + translate
+    *    = z * (2 * scale) + (translate - scale)
+    *
+    * scale' = 2 * scale
+    * translate' = translate - scale
+    */
+
+   /* must be fixp as v4 state deltas assume it is */
+   cs->PA_VIEWPORT_SCALE_X = etna_f32_to_fixp16(vs->scale[0]);
+   cs->PA_VIEWPORT_SCALE_Y = etna_f32_to_fixp16(vs->scale[1]);
+   cs->PA_VIEWPORT_SCALE_Z = fui(vs->scale[2] * 2.0f);
+   cs->PA_VIEWPORT_OFFSET_X = etna_f32_to_fixp16(vs->translate[0]);
+   cs->PA_VIEWPORT_OFFSET_Y = etna_f32_to_fixp16(vs->translate[1]);
+   cs->PA_VIEWPORT_OFFSET_Z = fui(vs->translate[2] - vs->scale[2]);
+
+   /* Compute scissor rectangle (fixp) from viewport.
+    * Make sure left is always < right and top always < bottom.
+    */
+   cs->SE_SCISSOR_LEFT = etna_f32_to_fixp16(MAX2(vs->translate[0] - vs->scale[0], 0.0f));
+   cs->SE_SCISSOR_TOP = etna_f32_to_fixp16(MAX2(vs->translate[1] - vs->scale[1], 0.0f));
+   cs->SE_SCISSOR_RIGHT = etna_f32_to_fixp16(MAX2(vs->translate[0] + vs->scale[0], 0.0f));
+   cs->SE_SCISSOR_BOTTOM = etna_f32_to_fixp16(MAX2(vs->translate[1] + vs->scale[1], 0.0f));
+
+   if (cs->SE_SCISSOR_LEFT > cs->SE_SCISSOR_RIGHT) {
+      uint32_t tmp = cs->SE_SCISSOR_RIGHT;
+      cs->SE_SCISSOR_RIGHT = cs->SE_SCISSOR_LEFT;
+      cs->SE_SCISSOR_LEFT = tmp;
+   }
+
+   if (cs->SE_SCISSOR_TOP > cs->SE_SCISSOR_BOTTOM) {
+      uint32_t tmp = cs->SE_SCISSOR_BOTTOM;
+      cs->SE_SCISSOR_BOTTOM = cs->SE_SCISSOR_TOP;
+      cs->SE_SCISSOR_TOP = tmp;
+   }
+
+   cs->PE_DEPTH_NEAR = fui(0.0); /* not affected if depth mode is Z (as in GL) */
+   cs->PE_DEPTH_FAR = fui(1.0);
+   ctx->dirty |= ETNA_DIRTY_VIEWPORT;
+}
+
+static void
+etna_set_vertex_buffers(struct pipe_context *pctx, unsigned start_slot,
+      unsigned num_buffers, const struct pipe_vertex_buffer *vb)
+{
+   struct etna_context *ctx = etna_context(pctx);
+   struct etna_vertexbuf_state *so = &ctx->vertex_buffer;
+
+   util_set_vertex_buffers_mask(so->vb, &so->enabled_mask, vb, start_slot, num_buffers);
+   so->count = util_last_bit(so->enabled_mask);
+
+   for (unsigned idx = start_slot; idx < start_slot + num_buffers; ++idx) {
+      struct compiled_set_vertex_buffer *cs = &so->cvb[idx];
+      struct pipe_vertex_buffer *vbi = &so->vb[idx];
+
+      assert(!vbi->user_buffer); /* XXX support user_buffer using
+                                    etna_usermem_map */
+
+      if (vbi->buffer) { /* GPU buffer */
+         cs->FE_VERTEX_STREAM_BASE_ADDR.bo = etna_resource(vbi->buffer)->bo;
+         cs->FE_VERTEX_STREAM_BASE_ADDR.offset = vbi->buffer_offset;
+         cs->FE_VERTEX_STREAM_BASE_ADDR.flags = ETNA_RELOC_READ;
+         cs->FE_VERTEX_STREAM_CONTROL =
+            FE_VERTEX_STREAM_CONTROL_VERTEX_STRIDE(vbi->stride);
+      } else {
+         cs->FE_VERTEX_STREAM_BASE_ADDR.bo = NULL;
+         cs->FE_VERTEX_STREAM_CONTROL = 0;
+      }
+   }
+
+   ctx->dirty |= ETNA_DIRTY_VERTEX_BUFFERS;
+}
+
+static void
+etna_set_index_buffer(struct pipe_context *pctx, const struct pipe_index_buffer *ib)
+{
+   struct etna_context *ctx = etna_context(pctx);
+   uint32_t ctrl;
+
+   if (ib) {
+      pipe_resource_reference(&ctx->index_buffer.ib.buffer, ib->buffer);
+      memcpy(&ctx->index_buffer.ib, ib, sizeof(ctx->index_buffer.ib));
+      ctrl = translate_index_size(ctx->index_buffer.ib.index_size);
+   } else {
+      pipe_resource_reference(&ctx->index_buffer.ib.buffer, NULL);
+      ctrl = 0;
+   }
+
+   if (ctx->index_buffer.ib.buffer && ctrl != ETNA_NO_MATCH) {
+      ctx->index_buffer.FE_INDEX_STREAM_BASE_ADDR.bo = etna_resource(ctx->index_buffer.ib.buffer)->bo;
+      ctx->index_buffer.FE_INDEX_STREAM_BASE_ADDR.offset = ctx->index_buffer.ib.offset;
+      ctx->index_buffer.FE_INDEX_STREAM_BASE_ADDR.flags = ETNA_RELOC_READ;
+      ctx->index_buffer.FE_INDEX_STREAM_CONTROL = ctrl;
+   } else {
+      ctx->index_buffer.FE_INDEX_STREAM_BASE_ADDR.bo = NULL;
+      ctx->index_buffer.FE_INDEX_STREAM_CONTROL = 0;
+   }
+
+   ctx->dirty |= ETNA_DIRTY_INDEX_BUFFER;
+}
+
+static void
+etna_blend_state_bind(struct pipe_context *pctx, void *bs)
+{
+   struct etna_context *ctx = etna_context(pctx);
+
+   ctx->blend = bs;
+   ctx->dirty |= ETNA_DIRTY_BLEND;
+}
+
+static void
+etna_blend_state_delete(struct pipe_context *pctx, void *bs)
+{
+   FREE(bs);
+}
+
+static void
+etna_rasterizer_state_bind(struct pipe_context *pctx, void *rs)
+{
+   struct etna_context *ctx = etna_context(pctx);
+
+   ctx->rasterizer = rs;
+   ctx->dirty |= ETNA_DIRTY_RASTERIZER;
+}
+
+static void
+etna_rasterizer_state_delete(struct pipe_context *pctx, void *rs)
+{
+   FREE(rs);
+}
+
+static void
+etna_zsa_state_bind(struct pipe_context *pctx, void *zs)
+{
+   struct etna_context *ctx = etna_context(pctx);
+
+   ctx->zsa = zs;
+   ctx->dirty |= ETNA_DIRTY_ZSA;
+}
+
+static void
+etna_zsa_state_delete(struct pipe_context *pctx, void *zs)
+{
+   FREE(zs);
+}
+
+/** Create vertex element states, which define a layout for fetching
+ * vertices for rendering.
+ */
+static void *
+etna_vertex_elements_state_create(struct pipe_context *pctx,
+      unsigned num_elements, const struct pipe_vertex_element *elements)
+{
+   struct etna_context *ctx = etna_context(pctx);
+   struct compiled_vertex_elements_state *cs = CALLOC_STRUCT(compiled_vertex_elements_state);
+
+   if (!cs)
+      return NULL;
+
+   if (num_elements > ctx->specs.vertex_max_elements) {
+      BUG("number of elements (%u) exceeds chip maximum (%u)", num_elements,
+          ctx->specs.vertex_max_elements);
+      return NULL;
+   }
+
+   /* XXX could minimize number of consecutive stretches here by sorting, and
+    * permuting the inputs in shader or does Mesa do this already? */
+
+   /* Check that vertex element binding is compatible with hardware; thus
+    * elements[idx].vertex_buffer_index are < stream_count. If not, the binding
+    * uses more streams than is supported, and u_vbuf should have done some
+    * reorganization for compatibility. */
+
+   /* TODO: does mesa this for us? */
+   bool incompatible = false;
+   for (unsigned idx = 0; idx < num_elements; ++idx) {
+      if (elements[idx].vertex_buffer_index >= ctx->specs.stream_count || elements[idx].instance_divisor > 0)
+         incompatible = true;
+   }
+
+   cs->num_elements = num_elements;
+   if (incompatible || num_elements == 0) {
+      DBG("Error: zero vertex elements, or more vertex buffers used than supported");
+      FREE(cs);
+      return NULL;
+   }
+
+   unsigned start_offset = 0; /* start of current consecutive stretch */
+   bool nonconsecutive = true; /* previous value of nonconsecutive */
+
+   for (unsigned idx = 0; idx < num_elements; ++idx) {
+      unsigned element_size = util_format_get_blocksize(elements[idx].src_format);
+      unsigned end_offset = elements[idx].src_offset + element_size;
+      uint32_t format_type, normalize;
+
+      if (nonconsecutive)
+         start_offset = elements[idx].src_offset;
+
+      /* maximum vertex size is 256 bytes */
+      assert(element_size != 0 && end_offset <= 256);
+
+      /* check whether next element is consecutive to this one */
+      nonconsecutive = (idx == (num_elements - 1)) ||
+                       elements[idx + 1].vertex_buffer_index != elements[idx].vertex_buffer_index ||
+                       end_offset != elements[idx + 1].src_offset;
+
+      format_type = translate_vertex_format_type(elements[idx].src_format);
+      normalize = translate_vertex_format_normalize(elements[idx].src_format);
+
+      assert(format_type != ETNA_NO_MATCH);
+      assert(normalize != ETNA_NO_MATCH);
+
+      cs->FE_VERTEX_ELEMENT_CONFIG[idx] =
+         COND(nonconsecutive, VIVS_FE_VERTEX_ELEMENT_CONFIG_NONCONSECUTIVE) |
+         format_type |
+         VIVS_FE_VERTEX_ELEMENT_CONFIG_NUM(util_format_get_nr_components(elements[idx].src_format)) |
+         normalize | VIVS_FE_VERTEX_ELEMENT_CONFIG_ENDIAN(ENDIAN_MODE_NO_SWAP) |
+         VIVS_FE_VERTEX_ELEMENT_CONFIG_STREAM(elements[idx].vertex_buffer_index) |
+         VIVS_FE_VERTEX_ELEMENT_CONFIG_START(elements[idx].src_offset) |
+         VIVS_FE_VERTEX_ELEMENT_CONFIG_END(end_offset - start_offset);
+   }
+
+   return cs;
+}
+
+static void
+etna_vertex_elements_state_delete(struct pipe_context *pctx, void *ve)
+{
+   FREE(ve);
+}
+
+static void
+etna_vertex_elements_state_bind(struct pipe_context *pctx, void *ve)
+{
+   struct etna_context *ctx = etna_context(pctx);
+
+   ctx->vertex_elements = ve;
+   ctx->dirty |= ETNA_DIRTY_VERTEX_ELEMENTS;
+}
+
+struct etna_state_updater {
+   bool (*update)(struct etna_context *ctx);
+   uint32_t dirty;
+};
+
+static const struct etna_state_updater etna_state_updates[] = {
+   {
+      etna_shader_update_vertex, ETNA_DIRTY_SHADER | ETNA_DIRTY_VERTEX_ELEMENTS,
+   },
+   {
+      etna_shader_link, ETNA_DIRTY_SHADER,
+   }
+};
+
+bool
+etna_state_update(struct etna_context *ctx)
+{
+   for (unsigned int i = 0; i < ARRAY_SIZE(etna_state_updates); i++)
+      if (ctx->dirty & etna_state_updates[i].dirty)
+         if (!etna_state_updates[i].update(ctx))
+            return false;
+
+   return true;
+}
+
+void
+etna_state_init(struct pipe_context *pctx)
+{
+   pctx->set_blend_color = etna_set_blend_color;
+   pctx->set_stencil_ref = etna_set_stencil_ref;
+   pctx->set_clip_state = etna_set_clip_state;
+   pctx->set_sample_mask = etna_set_sample_mask;
+   pctx->set_constant_buffer = etna_set_constant_buffer;
+   pctx->set_framebuffer_state = etna_set_framebuffer_state;
+   pctx->set_polygon_stipple = etna_set_polygon_stipple;
+   pctx->set_scissor_states = etna_set_scissor_states;
+   pctx->set_viewport_states = etna_set_viewport_states;
+
+   pctx->set_vertex_buffers = etna_set_vertex_buffers;
+   pctx->set_index_buffer = etna_set_index_buffer;
+
+   pctx->bind_blend_state = etna_blend_state_bind;
+   pctx->delete_blend_state = etna_blend_state_delete;
+
+   pctx->bind_rasterizer_state = etna_rasterizer_state_bind;
+   pctx->delete_rasterizer_state = etna_rasterizer_state_delete;
+
+   pctx->bind_depth_stencil_alpha_state = etna_zsa_state_bind;
+   pctx->delete_depth_stencil_alpha_state = etna_zsa_state_delete;
+
+   pctx->create_vertex_elements_state = etna_vertex_elements_state_create;
+   pctx->delete_vertex_elements_state = etna_vertex_elements_state_delete;
+   pctx->bind_vertex_elements_state = etna_vertex_elements_state_bind;
+}
diff --git a/src/gallium/drivers/etnaviv/etnaviv_state.h b/src/gallium/drivers/etnaviv/etnaviv_state.h
new file mode 100644
index 0000000..a1db9f7
--- /dev/null
+++ b/src/gallium/drivers/etnaviv/etnaviv_state.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2012-2015 Etnaviv Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Wladimir J. van der Laan <laanwj at gmail.com>
+ *    Christian Gmeiner <christian.gmeiner at gmail.com>
+ */
+
+#ifndef ETNAVIV_STATE_H_
+#define ETNAVIV_STATE_H_
+
+#include "etnaviv_context.h"
+#include "pipe/p_context.h"
+
+static inline bool
+etna_depth_enabled(struct etna_context *ctx)
+{
+   return ctx->zsa && ctx->zsa->depth.enabled;
+}
+
+static inline bool
+etna_stencil_enabled(struct etna_context *ctx)
+{
+   return ctx->zsa && ctx->zsa->stencil[0].enabled;
+}
+
+bool
+etna_state_update(struct etna_context *ctx);
+
+void
+etna_state_init(struct pipe_context *pctx);
+
+#endif /* ETNAVIV_STATE_H_ */
diff --git a/src/gallium/drivers/etnaviv/etnaviv_surface.c b/src/gallium/drivers/etnaviv/etnaviv_surface.c
new file mode 100644
index 0000000..a0013a4
--- /dev/null
+++ b/src/gallium/drivers/etnaviv/etnaviv_surface.c
@@ -0,0 +1,152 @@
+/*
+ * Copyright (c) 2012-2013 Etnaviv Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Wladimir J. van der Laan <laanwj at gmail.com>
+ */
+
+#include "etnaviv_surface.h"
+#include "etnaviv_screen.h"
+
+#include "etnaviv_clear_blit.h"
+#include "etnaviv_context.h"
+#include "etnaviv_translate.h"
+#include "pipe/p_defines.h"
+#include "pipe/p_state.h"
+#include "util/u_inlines.h"
+#include "util/u_memory.h"
+
+#include "hw/common.xml.h"
+
+static struct pipe_surface *
+etna_create_surface(struct pipe_context *pctx, struct pipe_resource *prsc,
+                    const struct pipe_surface *templat)
+{
+   struct etna_context *ctx = etna_context(pctx);
+   struct etna_resource *rsc = etna_resource(prsc);
+   struct etna_surface *surf = CALLOC_STRUCT(etna_surface);
+
+   if (!surf)
+      return NULL;
+
+   assert(templat->u.tex.first_layer == templat->u.tex.last_layer);
+   unsigned layer = templat->u.tex.first_layer;
+   unsigned level = templat->u.tex.level;
+   assert(layer < rsc->base.array_size);
+
+   surf->base.context = pctx;
+
+   pipe_reference_init(&surf->base.reference, 1);
+   pipe_resource_reference(&surf->base.texture, &rsc->base);
+
+   /* Allocate a TS for the resource if there isn't one yet,
+    * and it is allowed by the hw (width is a multiple of 16).
+    * Avoid doing this for GPUs with MC1.0, as kernel sources
+    * indicate the tile status module bypasses the memory
+    * offset and MMU. */
+
+   /* XXX for now, don't do TS for render textures as this path
+    * is not stable. */
+   if (VIV_FEATURE(ctx->screen, chipFeatures, FAST_CLEAR) &&
+       VIV_FEATURE(ctx->screen, chipMinorFeatures0, MC20) &&
+       !DBG_ENABLED(ETNA_DBG_NO_TS) && !rsc->ts_bo &&
+       !(rsc->base.bind & (PIPE_BIND_SAMPLER_VIEW)) &&
+       (rsc->levels[level].padded_width & ETNA_RS_WIDTH_MASK) == 0 &&
+       (rsc->levels[level].padded_height & ETNA_RS_HEIGHT_MASK) == 0) {
+      etna_screen_resource_alloc_ts(pctx->screen, rsc);
+   }
+
+   surf->base.texture = &rsc->base;
+   surf->base.format = rsc->base.format;
+   surf->base.width = rsc->levels[level].width;
+   surf->base.height = rsc->levels[level].height;
+   surf->base.writable = templat->writable; /* what is this for anyway */
+   surf->base.u = templat->u;
+
+   surf->level = &rsc->levels[level]; /* Keep pointer to actual level to set
+                                       * clear color on underlying resource
+                                       * instead of surface */
+   surf->surf = rsc->levels [level];  /* Make copy of level to narrow down
+                                       * address to layer */
+
+   /* XXX we don't really need a copy but it's convenient */
+   surf->surf.offset += layer * surf->surf.layer_stride;
+
+   struct etna_resource_level *lev = &rsc->levels[level];
+
+   /* Setup template relocations for this surface */
+   surf->reloc[0].bo = rsc->bo;
+   surf->reloc[0].offset = surf->surf.offset;
+   surf->reloc[0].flags = 0;
+   surf->reloc[1].bo = rsc->bo;
+   surf->reloc[1].offset = surf->surf.offset + lev->stride * lev->padded_height / 2;
+   surf->reloc[1].flags = 0;
+
+   if (surf->surf.ts_size) {
+      unsigned int layer_offset = layer * surf->surf.ts_layer_stride;
+      assert(layer_offset < surf->surf.ts_size);
+
+      surf->surf.ts_offset += layer_offset;
+      surf->surf.ts_size -= layer_offset;
+
+      surf->ts_reloc.bo = rsc->ts_bo;
+      surf->ts_reloc.offset = surf->surf.ts_offset;
+      surf->ts_reloc.flags = 0;
+
+      /* This (ab)uses the RS as a plain buffer memset().
+       * Currently uses a fixed row size of 64 bytes. Some benchmarking with
+       * different sizes may be in order. */
+      struct etna_bo *ts_bo = etna_resource(surf->base.texture)->ts_bo;
+      etna_compile_rs_state(ctx, &surf->clear_command, &(struct rs_state) {
+         .source_format = RS_FORMAT_A8R8G8B8,
+         .dest_format = RS_FORMAT_A8R8G8B8,
+         .dest = ts_bo,
+         .dest_offset = surf->surf.ts_offset,
+         .dest_stride = 0x40,
+         .dest_tiling = ETNA_LAYOUT_TILED,
+         .dither = {0xffffffff, 0xffffffff},
+         .width = 16,
+         .height = etna_align_up(surf->surf.ts_size / 0x40, 4),
+         .clear_value = {ctx->specs.ts_clear_value},
+         .clear_mode = VIVS_RS_CLEAR_CONTROL_MODE_ENABLED1,
+         .clear_bits = 0xffff
+      });
+   } else {
+      etna_rs_gen_clear_surface(ctx, surf, surf->level->clear_value);
+   }
+
+   return &surf->base;
+}
+
+static void
+etna_surface_destroy(struct pipe_context *pctx, struct pipe_surface *psurf)
+{
+   pipe_resource_reference(&psurf->texture, NULL);
+   FREE(psurf);
+}
+
+void
+etna_surface_init(struct pipe_context *pctx)
+{
+   pctx->create_surface = etna_create_surface;
+   pctx->surface_destroy = etna_surface_destroy;
+}
diff --git a/src/gallium/drivers/etnaviv/etnaviv_surface.h b/src/gallium/drivers/etnaviv/etnaviv_surface.h
new file mode 100644
index 0000000..e8cfd20
--- /dev/null
+++ b/src/gallium/drivers/etnaviv/etnaviv_surface.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2012-2015 Etnaviv Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Wladimir J. van der Laan <laanwj at gmail.com>
+ */
+
+#ifndef H_ETNAVIV_SURFACE
+#define H_ETNAVIV_SURFACE
+
+#include "etnaviv_resource.h"
+#include "etnaviv_rs.h"
+#include "etnaviv_tiling.h"
+#include "pipe/p_state.h"
+
+struct etna_surface {
+   struct pipe_surface base;
+
+   struct etna_resource_level surf;
+   struct compiled_rs_state clear_command;
+   /* Keep pointer to resource level, for fast clear */
+   struct etna_resource_level *level;
+   struct etna_reloc reloc[ETNA_MAX_PIXELPIPES];
+   struct etna_reloc ts_reloc;
+};
+
+static inline struct etna_surface *
+etna_surface(struct pipe_surface *p)
+{
+   return (struct etna_surface *)p;
+}
+
+void
+etna_surface_init(struct pipe_context *pctx);
+
+#endif
diff --git a/src/gallium/drivers/etnaviv/etnaviv_texture.c b/src/gallium/drivers/etnaviv/etnaviv_texture.c
new file mode 100644
index 0000000..6b64de2
--- /dev/null
+++ b/src/gallium/drivers/etnaviv/etnaviv_texture.c
@@ -0,0 +1,338 @@
+/*
+ * Copyright (c) 2012-2015 Etnaviv Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Wladimir J. van der Laan <laanwj at gmail.com>
+ */
+
+#include "etnaviv_texture.h"
+
+#include "hw/common.xml.h"
+
+#include "etnaviv_clear_blit.h"
+#include "etnaviv_context.h"
+#include "etnaviv_emit.h"
+#include "etnaviv_format.h"
+#include "etnaviv_translate.h"
+#include "util/u_inlines.h"
+#include "util/u_memory.h"
+
+static void *
+etna_create_sampler_state(struct pipe_context *pipe,
+                          const struct pipe_sampler_state *ss)
+{
+   struct etna_sampler_state *cs = CALLOC_STRUCT(etna_sampler_state);
+
+   if (!cs)
+      return NULL;
+
+   cs->TE_SAMPLER_CONFIG0 =
+      VIVS_TE_SAMPLER_CONFIG0_UWRAP(translate_texture_wrapmode(ss->wrap_s)) |
+      VIVS_TE_SAMPLER_CONFIG0_VWRAP(translate_texture_wrapmode(ss->wrap_t)) |
+      VIVS_TE_SAMPLER_CONFIG0_MIN(translate_texture_filter(ss->min_img_filter)) |
+      VIVS_TE_SAMPLER_CONFIG0_MIP(translate_texture_mipfilter(ss->min_mip_filter)) |
+      VIVS_TE_SAMPLER_CONFIG0_MAG(translate_texture_filter(ss->mag_img_filter)) |
+      COND(ss->normalized_coords, VIVS_TE_SAMPLER_CONFIG0_ROUND_UV);
+   cs->TE_SAMPLER_CONFIG1 = 0; /* VIVS_TE_SAMPLER_CONFIG1 (swizzle, extended
+                                  format) fully determined by sampler view */
+   cs->TE_SAMPLER_LOD_CONFIG =
+      COND(ss->lod_bias != 0.0, VIVS_TE_SAMPLER_LOD_CONFIG_BIAS_ENABLE) |
+      VIVS_TE_SAMPLER_LOD_CONFIG_BIAS(etna_float_to_fixp55(ss->lod_bias));
+
+   if (ss->min_mip_filter != PIPE_TEX_MIPFILTER_NONE) {
+      cs->min_lod = etna_float_to_fixp55(ss->min_lod);
+      cs->max_lod = etna_float_to_fixp55(ss->max_lod);
+   } else {
+      /* when not mipmapping, we need to set max/min lod so that always
+       * lowest LOD is selected */
+      cs->min_lod = cs->max_lod = etna_float_to_fixp55(ss->min_lod);
+   }
+
+   return cs;
+}
+
+static void
+etna_bind_sampler_states(struct pipe_context *pctx, unsigned shader,
+                         unsigned start_slot, unsigned num_samplers,
+                         void **samplers)
+{
+   /* bind fragment sampler */
+   struct etna_context *ctx = etna_context(pctx);
+   int offset;
+
+   switch (shader) {
+   case PIPE_SHADER_FRAGMENT:
+      offset = 0;
+      ctx->num_fragment_samplers = num_samplers;
+      break;
+   case PIPE_SHADER_VERTEX:
+      offset = ctx->specs.vertex_sampler_offset;
+      break;
+   default:
+      assert(!"Invalid shader");
+      return;
+   }
+
+   uint32_t mask = 1 << offset;
+   for (int idx = 0; idx < num_samplers; ++idx, mask <<= 1) {
+      ctx->sampler[offset + idx] = samplers[idx];
+      if (samplers[idx])
+         ctx->active_samplers |= mask;
+      else
+         ctx->active_samplers &= ~mask;
+   }
+
+   ctx->dirty |= ETNA_DIRTY_SAMPLERS;
+}
+
+static void
+etna_delete_sampler_state(struct pipe_context *pctx, void *ss)
+{
+   FREE(ss);
+}
+
+static void
+etna_update_sampler_source(struct pipe_sampler_view *view)
+{
+   struct etna_resource *res = etna_resource(view->texture);
+
+   if (res->texture && etna_resource_older(etna_resource(res->texture), res)) {
+      /* Texture is older than render buffer, copy the texture using RS */
+      etna_copy_resource(view->context, res->texture, view->texture, 0,
+                         view->texture->last_level);
+      etna_resource(res->texture)->seqno = res->seqno;
+   }
+}
+
+static bool
+etna_resource_sampler_compatible(struct etna_resource *res)
+{
+   if (util_format_is_compressed(res->base.format))
+      return true;
+
+   /* The sampler (as we currently know it) only accepts tiled layouts */
+   if (res->layout != ETNA_LAYOUT_TILED)
+      return false;
+
+   /* If we have HALIGN support, we can allow for the RS padding */
+   struct etna_screen *screen = etna_screen(res->base.screen);
+   if (VIV_FEATURE(screen, chipMinorFeatures1, TEXTURE_HALIGN))
+      return true;
+
+   /* Non-HALIGN GPUs only accept 4x4 tile-aligned textures */
+   if (res->halign != TEXTURE_HALIGN_FOUR)
+      return false;
+
+   return true;
+}
+
+static struct pipe_sampler_view *
+etna_create_sampler_view(struct pipe_context *pctx, struct pipe_resource *prsc,
+                         const struct pipe_sampler_view *so)
+{
+   struct etna_sampler_view *sv = CALLOC_STRUCT(etna_sampler_view);
+   struct etna_resource *res = etna_resource(prsc);
+   struct etna_context *ctx = etna_context(pctx);
+
+   if (!sv)
+      return NULL;
+
+   if (!etna_resource_sampler_compatible(res)) {
+      /* The original resource is not compatible with the sampler.
+       * Allocate an appropriately tiled texture. */
+      if (!res->texture) {
+         struct pipe_resource templat = *prsc;
+
+         templat.bind &= ~(PIPE_BIND_DEPTH_STENCIL | PIPE_BIND_RENDER_TARGET |
+                           PIPE_BIND_BLENDABLE);
+         res->texture =
+            etna_resource_alloc(pctx->screen, ETNA_LAYOUT_TILED, &templat);
+      }
+
+      if (!res->texture) {
+         free(sv);
+         return NULL;
+      }
+      res = etna_resource(res->texture);
+   }
+
+   sv->base = *so;
+   pipe_reference(NULL, &prsc->reference);
+   sv->base.texture = prsc;
+   sv->base.reference.count = 1;
+   sv->base.context = pctx;
+
+   /* merged with sampler state */
+   sv->TE_SAMPLER_CONFIG0 =
+      VIVS_TE_SAMPLER_CONFIG0_FORMAT(translate_texture_format(sv->base.format));
+   sv->TE_SAMPLER_CONFIG0_MASK = 0xffffffff;
+
+   switch (sv->base.target) {
+   case PIPE_TEXTURE_1D:
+      /* For 1D textures, we will have a height of 1, so we can use 2D
+       * but set T wrap to repeat */
+      sv->TE_SAMPLER_CONFIG0_MASK = ~VIVS_TE_SAMPLER_CONFIG0_VWRAP__MASK;
+      sv->TE_SAMPLER_CONFIG0 |= VIVS_TE_SAMPLER_CONFIG0_VWRAP(TEXTURE_WRAPMODE_REPEAT);
+   case PIPE_TEXTURE_2D:
+   case PIPE_TEXTURE_RECT:
+      sv->TE_SAMPLER_CONFIG0 |= VIVS_TE_SAMPLER_CONFIG0_TYPE(TEXTURE_TYPE_2D);
+      break;
+   case PIPE_TEXTURE_CUBE:
+      sv->TE_SAMPLER_CONFIG0 |= VIVS_TE_SAMPLER_CONFIG0_TYPE(TEXTURE_TYPE_CUBE_MAP);
+      break;
+   default:
+      BUG("Unhandled texture target");
+      free(sv);
+      return NULL;
+   }
+
+   sv->TE_SAMPLER_CONFIG1 = VIVS_TE_SAMPLER_CONFIG1_SWIZZLE_R(so->swizzle_r) |
+                            VIVS_TE_SAMPLER_CONFIG1_SWIZZLE_G(so->swizzle_g) |
+                            VIVS_TE_SAMPLER_CONFIG1_SWIZZLE_B(so->swizzle_b) |
+                            VIVS_TE_SAMPLER_CONFIG1_SWIZZLE_A(so->swizzle_a) |
+                            VIVS_TE_SAMPLER_CONFIG1_HALIGN(res->halign);
+   sv->TE_SAMPLER_SIZE = VIVS_TE_SAMPLER_SIZE_WIDTH(res->base.width0) |
+                         VIVS_TE_SAMPLER_SIZE_HEIGHT(res->base.height0);
+   sv->TE_SAMPLER_LOG_SIZE =
+      VIVS_TE_SAMPLER_LOG_SIZE_WIDTH(etna_log2_fixp55(res->base.width0)) |
+      VIVS_TE_SAMPLER_LOG_SIZE_HEIGHT(etna_log2_fixp55(res->base.height0));
+
+   /* Set up levels-of-detail */
+   for (int lod = 0; lod <= res->base.last_level; ++lod) {
+      sv->TE_SAMPLER_LOD_ADDR[lod].bo = res->bo;
+      sv->TE_SAMPLER_LOD_ADDR[lod].offset = res->levels[lod].offset;
+      sv->TE_SAMPLER_LOD_ADDR[lod].flags = ETNA_RELOC_READ;
+   }
+   sv->min_lod = sv->base.u.tex.first_level << 5;
+   sv->max_lod = MIN2(sv->base.u.tex.last_level, res->base.last_level) << 5;
+
+   /* Workaround for npot textures -- it appears that only CLAMP_TO_EDGE is
+    * supported when the appropriate capability is not set. */
+   if (!ctx->specs.npot_tex_any_wrap &&
+       (!util_is_power_of_two(res->base.width0) || !util_is_power_of_two(res->base.height0))) {
+      sv->TE_SAMPLER_CONFIG0_MASK = ~(VIVS_TE_SAMPLER_CONFIG0_UWRAP__MASK |
+                                      VIVS_TE_SAMPLER_CONFIG0_VWRAP__MASK);
+      sv->TE_SAMPLER_CONFIG0 |=
+         VIVS_TE_SAMPLER_CONFIG0_UWRAP(TEXTURE_WRAPMODE_CLAMP_TO_EDGE) |
+         VIVS_TE_SAMPLER_CONFIG0_VWRAP(TEXTURE_WRAPMODE_CLAMP_TO_EDGE);
+   }
+
+   return &sv->base;
+}
+
+static void
+etna_sampler_view_destroy(struct pipe_context *pctx,
+                          struct pipe_sampler_view *view)
+{
+   pipe_resource_reference(&view->texture, NULL);
+   FREE(view);
+}
+
+static void
+set_sampler_views(struct etna_context *ctx, unsigned start, unsigned end,
+                  unsigned nr, struct pipe_sampler_view **views)
+{
+   unsigned i, j;
+   uint32_t mask = 1 << start;
+
+   for (i = start, j = 0; j < nr; i++, j++, mask <<= 1) {
+      pipe_sampler_view_reference(&ctx->sampler_view[i], views[j]);
+      if (views[j])
+         ctx->active_sampler_views |= mask;
+      else
+         ctx->active_sampler_views &= ~mask;
+   }
+
+   for (; i < end; i++, mask <<= 1) {
+      pipe_sampler_view_reference(&ctx->sampler_view[i], NULL);
+      ctx->active_sampler_views &= ~mask;
+   }
+}
+
+static inline void
+etna_fragtex_set_sampler_views(struct etna_context *ctx, unsigned nr,
+                               struct pipe_sampler_view **views)
+{
+   unsigned start = 0;
+   unsigned end = start + ctx->specs.fragment_sampler_count;
+
+   set_sampler_views(ctx, start, end, nr, views);
+   ctx->num_fragment_sampler_views = nr;
+}
+
+
+static inline void
+etna_vertex_set_sampler_views(struct etna_context *ctx, unsigned nr,
+                              struct pipe_sampler_view **views)
+{
+   unsigned start = ctx->specs.vertex_sampler_offset;
+   unsigned end = start + ctx->specs.vertex_sampler_count;
+
+   set_sampler_views(ctx, start, end, nr, views);
+}
+
+static void
+etna_set_sampler_views(struct pipe_context *pctx, unsigned shader,
+                       unsigned start_slot, unsigned num_views,
+                       struct pipe_sampler_view **views)
+{
+   struct etna_context *ctx = etna_context(pctx);
+   assert(start_slot == 0);
+
+   ctx->dirty |= ETNA_DIRTY_SAMPLER_VIEWS | ETNA_DIRTY_TEXTURE_CACHES;
+
+   for (unsigned idx = 0; idx < num_views; ++idx) {
+      if (views[idx])
+         etna_update_sampler_source(views[idx]);
+   }
+
+   switch (shader) {
+   case PIPE_SHADER_FRAGMENT:
+      etna_fragtex_set_sampler_views(ctx, num_views, views);
+      break;
+   case PIPE_SHADER_VERTEX:
+      etna_vertex_set_sampler_views(ctx, num_views, views);
+      break;
+   default:;
+   }
+}
+
+static void
+etna_texture_barrier(struct pipe_context *pctx)
+{
+   struct etna_context *ctx = etna_context(pctx);
+   /* clear color and texture cache to make sure that texture unit reads
+    * what has been written */
+   etna_set_state(ctx->stream, VIVS_GL_FLUSH_CACHE, VIVS_GL_FLUSH_CACHE_COLOR | VIVS_GL_FLUSH_CACHE_TEXTURE);
+}
+
+void
+etna_texture_init(struct pipe_context *pctx)
+{
+   pctx->create_sampler_state = etna_create_sampler_state;
+   pctx->bind_sampler_states = etna_bind_sampler_states;
+   pctx->delete_sampler_state = etna_delete_sampler_state;
+   pctx->set_sampler_views = etna_set_sampler_views;
+   pctx->create_sampler_view = etna_create_sampler_view;
+   pctx->sampler_view_destroy = etna_sampler_view_destroy;
+   pctx->texture_barrier = etna_texture_barrier;
+}
diff --git a/src/gallium/drivers/etnaviv/etnaviv_texture.h b/src/gallium/drivers/etnaviv/etnaviv_texture.h
new file mode 100644
index 0000000..a7a67fc
--- /dev/null
+++ b/src/gallium/drivers/etnaviv/etnaviv_texture.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2012-2015 Etnaviv Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Wladimir J. van der Laan <laanwj at gmail.com>
+ */
+
+#ifndef H_ETNAVIV_TEXTURE
+#define H_ETNAVIV_TEXTURE
+
+#include <etnaviv_drmif.h>
+
+#include "pipe/p_context.h"
+#include "pipe/p_state.h"
+
+#include "hw/state_3d.xml.h"
+
+struct etna_sampler_state {
+   struct pipe_sampler_state base;
+
+   /* sampler offset +4*sampler, interleave when committing state */
+   uint32_t TE_SAMPLER_CONFIG0;
+   uint32_t TE_SAMPLER_CONFIG1;
+   uint32_t TE_SAMPLER_LOD_CONFIG;
+   unsigned min_lod, max_lod;
+};
+
+static inline struct etna_sampler_state *
+etna_sampler_state(struct pipe_sampler_state *samp)
+{
+   return (struct etna_sampler_state *)samp;
+}
+
+struct etna_sampler_view {
+   struct pipe_sampler_view base;
+
+   /* sampler offset +4*sampler, interleave when committing state */
+   uint32_t TE_SAMPLER_CONFIG0;
+   uint32_t TE_SAMPLER_CONFIG0_MASK;
+   uint32_t TE_SAMPLER_CONFIG1;
+   uint32_t TE_SAMPLER_SIZE;
+   uint32_t TE_SAMPLER_LOG_SIZE;
+   struct etna_reloc TE_SAMPLER_LOD_ADDR[VIVS_TE_SAMPLER_LOD_ADDR__LEN];
+   unsigned min_lod, max_lod; /* 5.5 fixp */
+};
+
+static inline struct etna_sampler_view *
+etna_sampler_view(struct pipe_sampler_view *view)
+{
+   return (struct etna_sampler_view *)view;
+}
+
+void
+etna_texture_init(struct pipe_context *pctx);
+
+#endif
diff --git a/src/gallium/drivers/etnaviv/etnaviv_tiling.c b/src/gallium/drivers/etnaviv/etnaviv_tiling.c
new file mode 100644
index 0000000..f4f85c1
--- /dev/null
+++ b/src/gallium/drivers/etnaviv/etnaviv_tiling.c
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2012-2015 Etnaviv Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Wladimir J. van der Laan <laanwj at gmail.com>
+ */
+
+#include "etnaviv_tiling.h"
+
+#include <stdint.h>
+#include <stdio.h>
+
+#define TEX_TILE_WIDTH (4)
+#define TEX_TILE_HEIGHT (4)
+#define TEX_TILE_WORDS (TEX_TILE_WIDTH * TEX_TILE_HEIGHT)
+
+#define DO_TILE(type)                                                   \
+   src_stride /= sizeof(type);                                          \
+   dst_stride = (dst_stride * TEX_TILE_HEIGHT) / sizeof(type);          \
+   for (unsigned srcy = 0; srcy < height; ++srcy) {                     \
+      unsigned dsty = basey + srcy;                                     \
+      unsigned ty = (dsty / TEX_TILE_HEIGHT) * dst_stride +             \
+                    (dsty % TEX_TILE_HEIGHT) * TEX_TILE_WIDTH;          \
+      for (unsigned srcx = 0; srcx < width; ++srcx) {                   \
+         unsigned dstx = basex + srcx;                                  \
+         ((type *)dest)[ty + (dstx / TEX_TILE_WIDTH) * TEX_TILE_WORDS + \
+                        (dstx % TEX_TILE_WIDTH)] =                      \
+            ((type *)src)[srcy * src_stride + srcx];                    \
+      }                                                                 \
+   }
+
+#define DO_UNTILE(type)                                                   \
+   src_stride = (src_stride * TEX_TILE_HEIGHT) / sizeof(type);            \
+   dst_stride /= sizeof(type);                                            \
+   for (unsigned dsty = 0; dsty < height; ++dsty) {                       \
+      unsigned srcy = basey + dsty;                                       \
+      unsigned sy = (srcy / TEX_TILE_HEIGHT) * src_stride +               \
+                    (srcy % TEX_TILE_HEIGHT) * TEX_TILE_WIDTH;            \
+      for (unsigned dstx = 0; dstx < width; ++dstx) {                     \
+         unsigned srcx = basex + dstx;                                    \
+         ((type *)dest)[dsty * dst_stride + dstx] =                       \
+            ((type *)src)[sy + (srcx / TEX_TILE_WIDTH) * TEX_TILE_WORDS + \
+                          (srcx % TEX_TILE_WIDTH)];                       \
+      }                                                                   \
+   }
+
+void
+etna_texture_tile(void *dest, void *src, unsigned basex, unsigned basey,
+                  unsigned dst_stride, unsigned width, unsigned height,
+                  unsigned src_stride, unsigned elmtsize)
+{
+   if (elmtsize == 4) {
+      DO_TILE(uint32_t)
+   } else if (elmtsize == 2) {
+      DO_TILE(uint16_t)
+   } else if (elmtsize == 1) {
+      DO_TILE(uint8_t)
+   } else {
+      printf("etna_texture_tile: unhandled element size %i\n", elmtsize);
+   }
+}
+
+void
+etna_texture_untile(void *dest, void *src, unsigned basex, unsigned basey,
+                    unsigned src_stride, unsigned width, unsigned height,
+                    unsigned dst_stride, unsigned elmtsize)
+{
+   if (elmtsize == 4) {
+      DO_UNTILE(uint32_t);
+   } else if (elmtsize == 2) {
+      DO_UNTILE(uint16_t);
+   } else if (elmtsize == 1) {
+      DO_UNTILE(uint8_t);
+   } else {
+      printf("etna_texture_tile: unhandled element size %i\n", elmtsize);
+   }
+}
diff --git a/src/gallium/drivers/etnaviv/etnaviv_tiling.h b/src/gallium/drivers/etnaviv/etnaviv_tiling.h
new file mode 100644
index 0000000..3c69e22
--- /dev/null
+++ b/src/gallium/drivers/etnaviv/etnaviv_tiling.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2012-2015 Etnaviv Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Wladimir J. van der Laan <laanwj at gmail.com>
+ */
+
+#ifndef H_ETNAVIV_TILING
+#define H_ETNAVIV_TILING
+
+#include <stdint.h>
+
+/* texture or surface layout */
+enum etna_surface_layout {
+   ETNA_LAYOUT_BIT_TILE = (1 << 0),
+   ETNA_LAYOUT_BIT_SUPER = (1 << 1),
+   ETNA_LAYOUT_BIT_MULTI = (1 << 2),
+   ETNA_LAYOUT_LINEAR = 0,
+   ETNA_LAYOUT_TILED = ETNA_LAYOUT_BIT_TILE,
+   ETNA_LAYOUT_SUPER_TILED = ETNA_LAYOUT_BIT_TILE | ETNA_LAYOUT_BIT_SUPER,
+   ETNA_LAYOUT_MULTI_TILED = ETNA_LAYOUT_BIT_TILE | ETNA_LAYOUT_BIT_MULTI,
+   ETNA_LAYOUT_MULTI_SUPERTILED = ETNA_LAYOUT_BIT_TILE | ETNA_LAYOUT_BIT_SUPER | ETNA_LAYOUT_BIT_MULTI,
+};
+
+void
+etna_texture_tile(void *dest, void *src, unsigned basex, unsigned basey,
+                 unsigned dst_stride, unsigned width, unsigned height,
+                 unsigned src_stride, unsigned elmtsize);
+void
+etna_texture_untile(void *dest, void *src, unsigned basex, unsigned basey,
+                   unsigned src_stride, unsigned width, unsigned height,
+                   unsigned dst_stride, unsigned elmtsize);
+
+/* XXX from/to supertiling (can have different layouts, may be better
+ * to leave to RS) */
+
+#endif
diff --git a/src/gallium/drivers/etnaviv/etnaviv_transfer.c b/src/gallium/drivers/etnaviv/etnaviv_transfer.c
new file mode 100644
index 0000000..1a5aa7f
--- /dev/null
+++ b/src/gallium/drivers/etnaviv/etnaviv_transfer.c
@@ -0,0 +1,355 @@
+/*
+ * Copyright (c) 2012-2015 Etnaviv Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Wladimir J. van der Laan <laanwj at gmail.com>
+ */
+
+#include "etnaviv_transfer.h"
+#include "etnaviv_clear_blit.h"
+#include "etnaviv_context.h"
+#include "etnaviv_debug.h"
+
+#include "pipe/p_defines.h"
+#include "pipe/p_format.h"
+#include "pipe/p_screen.h"
+#include "pipe/p_state.h"
+#include "util/u_format.h"
+#include "util/u_inlines.h"
+#include "util/u_memory.h"
+#include "util/u_surface.h"
+#include "util/u_transfer.h"
+
+/* Compute offset into a 1D/2D/3D buffer of a certain box.
+ * This box must be aligned to the block width and height of the
+ * underlying format. */
+static inline size_t
+etna_compute_offset(enum pipe_format format, const struct pipe_box *box,
+                    size_t stride, size_t layer_stride)
+{
+   return box->z * layer_stride +
+          box->y / util_format_get_blockheight(format) * stride +
+          box->x / util_format_get_blockwidth(format) *
+             util_format_get_blocksize(format);
+}
+
+static void
+etna_transfer_unmap(struct pipe_context *pctx, struct pipe_transfer *ptrans)
+{
+   struct etna_context *ctx = etna_context(pctx);
+   struct etna_transfer *trans = etna_transfer(ptrans);
+   struct etna_resource *rsc = etna_resource(ptrans->resource);
+
+   /* XXX
+    * When writing to a resource that is already in use, replace the resource
+    * with a completely new buffer
+    * and free the old one using a fenced free.
+    * The most tricky case to implement will be: tiled or supertiled surface,
+    * partial write, target not aligned to 4/64. */
+   assert(ptrans->level <= rsc->base.last_level);
+
+   if (rsc->texture && !etna_resource_newer(rsc, etna_resource(rsc->texture)))
+      rsc = etna_resource(rsc->texture); /* switch to using the texture resource */
+
+   if (ptrans->usage & PIPE_TRANSFER_WRITE) {
+      if (trans->rsc) {
+         /* We have a temporary resource due to either tile status or
+          * tiling format. Write back the updated buffer contents.
+          * FIXME: we need to invalidate the tile status. */
+         etna_copy_resource(pctx, ptrans->resource, trans->rsc, ptrans->level,
+                            trans->rsc->last_level);
+      } else if (trans->staging) {
+         /* map buffer object */
+         struct etna_resource_level *res_level = &rsc->levels[ptrans->level];
+         void *mapped = etna_bo_map(rsc->bo) + res_level->offset;
+
+         if (rsc->layout == ETNA_LAYOUT_LINEAR || rsc->layout == ETNA_LAYOUT_TILED) {
+            if (rsc->layout == ETNA_LAYOUT_TILED && !util_format_is_compressed(rsc->base.format)) {
+               etna_texture_tile(
+                  mapped + ptrans->box.z * res_level->layer_stride,
+                  trans->staging, ptrans->box.x, ptrans->box.y,
+                  res_level->stride, ptrans->box.width, ptrans->box.height,
+                  ptrans->stride, util_format_get_blocksize(rsc->base.format));
+            } else { /* non-tiled or compressed format */
+               util_copy_box(mapped, rsc->base.format, res_level->stride,
+                             res_level->layer_stride, ptrans->box.x,
+                             ptrans->box.y, ptrans->box.z, ptrans->box.width,
+                             ptrans->box.height, ptrans->box.depth,
+                             trans->staging, ptrans->stride,
+                             ptrans->layer_stride, 0, 0, 0 /* src x,y,z */);
+            }
+         } else {
+            BUG("unsupported tiling %i", rsc->layout);
+         }
+
+         FREE(trans->staging);
+      }
+
+      rsc->seqno++;
+      etna_bo_cpu_fini(rsc->bo);
+
+      if (rsc->base.bind & PIPE_BIND_SAMPLER_VIEW) {
+         /* XXX do we need to flush the CPU cache too or start a write barrier
+          * to make sure the GPU sees it? */
+         ctx->dirty |= ETNA_DIRTY_TEXTURE_CACHES;
+      }
+   }
+
+   pipe_resource_reference(&trans->rsc, NULL);
+   pipe_resource_reference(&ptrans->resource, NULL);
+   slab_free(&ctx->transfer_pool, trans);
+}
+
+static void *
+etna_transfer_map(struct pipe_context *pctx, struct pipe_resource *prsc,
+                  unsigned level,
+                  unsigned usage,
+                  const struct pipe_box *box,
+                  struct pipe_transfer **out_transfer)
+{
+   struct etna_context *ctx = etna_context(pctx);
+   struct etna_resource *rsc = etna_resource(prsc);
+   struct etna_transfer *trans;
+   struct pipe_transfer *ptrans;
+   enum pipe_format format = prsc->format;
+
+   trans = slab_alloc(&ctx->transfer_pool);
+   if (!trans)
+      return NULL;
+
+   /* slab_alloc() doesn't zero */
+   memset(trans, 0, sizeof(*trans));
+
+   ptrans = &trans->base;
+   pipe_resource_reference(&ptrans->resource, prsc);
+   ptrans->level = level;
+   ptrans->usage = usage;
+   ptrans->box = *box;
+
+   assert(level <= prsc->last_level);
+
+   if (rsc->texture && !etna_resource_newer(rsc, etna_resource(rsc->texture))) {
+      /* We have a texture resource which is the same age or newer than the
+       * render resource. Use the texture resource, which avoids bouncing
+       * pixels between the two resources, and we can de-tile it in s/w. */
+      rsc = etna_resource(rsc->texture);
+   } else if (rsc->ts_bo ||
+              (rsc->layout != ETNA_LAYOUT_LINEAR &&
+               util_format_get_blocksize(format) > 1 &&
+               /* HALIGN 4 resources are incompatible with the resolve engine,
+                * so fall back to using software to detile this resource. */
+               rsc->halign != TEXTURE_HALIGN_FOUR)) {
+      /* If the surface has tile status, we need to resolve it first.
+       * The strategy we implement here is to use the RS to copy the
+       * depth buffer, filling in the "holes" where the tile status
+       * indicates that it's clear. We also do this for tiled
+       * resources, but only if the RS can blit them. */
+      if (usage & PIPE_TRANSFER_MAP_DIRECTLY) {
+         slab_free(&ctx->transfer_pool, trans);
+         BUG("unsupported transfer flags %#x with tile status/tiled layout", usage);
+         return NULL;
+      }
+
+      if (prsc->depth0 > 1) {
+         slab_free(&ctx->transfer_pool, trans);
+         BUG("resource has depth >1 with tile status");
+         return NULL;
+      }
+
+      struct pipe_resource templ = *prsc;
+      templ.nr_samples = 0;
+      templ.bind = PIPE_BIND_RENDER_TARGET;
+
+      trans->rsc = etna_resource_alloc(pctx->screen, ETNA_LAYOUT_LINEAR, &templ);
+      if (!trans->rsc) {
+         slab_free(&ctx->transfer_pool, trans);
+         return NULL;
+      }
+
+      etna_copy_resource(pctx, trans->rsc, prsc, level, trans->rsc->last_level);
+
+      /* Switch to using the temporary resource instead */
+      rsc = etna_resource(trans->rsc);
+   }
+
+   struct etna_resource_level *res_level = &rsc->levels[level];
+
+   /* Always sync if we have the temporary resource.  The PIPE_TRANSFER_READ
+    * case could be optimised if we knew whether the resource has outstanding
+    * rendering. */
+   if (usage & PIPE_TRANSFER_READ || trans->rsc)
+      etna_resource_wait(pctx, rsc);
+
+   /* XXX we don't handle PIPE_TRANSFER_FLUSH_EXPLICIT; this flag can be ignored
+    * when mapping in-place,
+    * but when not in place we need to fire off the copy operation in
+    * transfer_flush_region (currently
+    * a no-op) instead of unmap. Need to handle this to support
+    * ARB_map_buffer_range extension at least.
+    */
+   /* XXX we don't take care of current operations on the resource; which can
+      be, at some point in the pipeline
+      which is not yet executed:
+
+      - bound as surface
+      - bound through vertex buffer
+      - bound through index buffer
+      - bound in sampler view
+      - used in clear_render_target / clear_depth_stencil operation
+      - used in blit
+      - used in resource_copy_region
+
+      How do other drivers record this information over course of the rendering
+      pipeline?
+      Is it necessary at all? Only in case we want to provide a fast path and
+      map the resource directly
+      (and for PIPE_TRANSFER_MAP_DIRECTLY) and we don't want to force a sync.
+      We also need to know whether the resource is in use to determine if a sync
+      is needed (or just do it
+      always, but that comes at the expense of performance).
+
+      A conservative approximation without too much overhead would be to mark
+      all resources that have
+      been bound at some point as busy. A drawback would be that accessing
+      resources that have
+      been bound but are no longer in use for a while still carry a performance
+      penalty. On the other hand,
+      the program could be using PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE or
+      PIPE_TRANSFER_UNSYNCHRONIZED to
+      avoid this in the first place...
+
+      A) We use an in-pipe copy engine, and queue the copy operation after unmap
+      so that the copy
+         will be performed when all current commands have been executed.
+         Using the RS is possible, not sure if always efficient. This can also
+      do any kind of tiling for us.
+         Only possible when PIPE_TRANSFER_DISCARD_RANGE is set.
+      B) We discard the entire resource (or at least, the mipmap level) and
+      allocate new memory for it.
+         Only possible when mapping the entire resource or
+      PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE is set.
+    */
+
+   /* No need to allocate a buffer for copying if the resource is not in use,
+    * and no tiling is needed, can just return a direct pointer.
+    */
+   bool in_place = rsc->layout == ETNA_LAYOUT_LINEAR ||
+                   (rsc->layout == ETNA_LAYOUT_TILED &&
+                    util_format_is_compressed(prsc->format));
+
+   /* Ignore PIPE_TRANSFER_UNSYNCHRONIZED and PIPE_TRANSFER_DONTBLOCK here.
+    * It appears that Gallium operates the index/vertex buffers in a
+    * circular fashion, and the CPU can catch up with the GPU and starts
+    * overwriting yet-to-be-processed entries, causing rendering corruption. */
+   uint32_t prep_flags = 0;
+
+   if (usage & PIPE_TRANSFER_READ)
+      prep_flags |= DRM_ETNA_PREP_READ;
+   if (usage & PIPE_TRANSFER_WRITE)
+      prep_flags |= DRM_ETNA_PREP_WRITE;
+
+   if (etna_bo_cpu_prep(rsc->bo, prep_flags))
+      goto fail_prep;
+
+   /* map buffer object */
+   void *mapped = etna_bo_map(rsc->bo);
+   if (!mapped)
+      goto fail;
+
+   *out_transfer = ptrans;
+
+   if (in_place) {
+      ptrans->stride = res_level->stride;
+      ptrans->layer_stride = res_level->layer_stride;
+
+      return mapped + res_level->offset +
+             etna_compute_offset(prsc->format, box, res_level->stride,
+                                 res_level->layer_stride);
+   } else {
+      unsigned divSizeX = util_format_get_blockwidth(format);
+      unsigned divSizeY = util_format_get_blockheight(format);
+
+      /* No direct mappings of tiled, since we need to manually
+       * tile/untile.
+       */
+      if (usage & PIPE_TRANSFER_MAP_DIRECTLY)
+         goto fail;
+
+      mapped += res_level->offset;
+      ptrans->stride = align(box->width, divSizeX) * util_format_get_blocksize(format); /* row stride in bytes */
+      ptrans->layer_stride = align(box->height, divSizeY) * ptrans->stride;
+      size_t size = ptrans->layer_stride * box->depth;
+
+      trans->staging = MALLOC(size);
+      if (!trans->staging)
+         goto fail;
+
+      if (usage & PIPE_TRANSFER_READ) {
+         /* untile or copy resource for reading */
+         if (rsc->layout == ETNA_LAYOUT_LINEAR || rsc->layout == ETNA_LAYOUT_TILED) {
+            if (rsc->layout == ETNA_LAYOUT_TILED && !util_format_is_compressed(rsc->base.format)) {
+               etna_texture_untile(trans->staging,
+                                   mapped + ptrans->box.z * res_level->layer_stride,
+                                   ptrans->box.x, ptrans->box.y, res_level->stride,
+                                   ptrans->box.width, ptrans->box.height, ptrans->stride,
+                                   util_format_get_blocksize(rsc->base.format));
+            } else { /* non-tiled or compressed format */
+               util_copy_box(trans->staging, rsc->base.format, ptrans->stride,
+                             ptrans->layer_stride, 0, 0, 0, /* dst x,y,z */
+                             ptrans->box.width, ptrans->box.height,
+                             ptrans->box.depth, mapped, res_level->stride,
+                             res_level->layer_stride, ptrans->box.x,
+                             ptrans->box.y, ptrans->box.z);
+            }
+         } else /* TODO supertiling */
+         {
+            BUG("unsupported tiling %i for reading", rsc->layout);
+         }
+      }
+
+      return trans->staging;
+   }
+
+fail:
+   etna_bo_cpu_fini(rsc->bo);
+fail_prep:
+   etna_transfer_unmap(pctx, ptrans);
+   return NULL;
+}
+
+static void
+etna_transfer_flush_region(struct pipe_context *pctx,
+                           struct pipe_transfer *transfer,
+                           const struct pipe_box *box)
+{
+   /* NOOP for now */
+}
+
+void
+etna_transfer_init(struct pipe_context *pctx)
+{
+   pctx->transfer_map = etna_transfer_map;
+   pctx->transfer_flush_region = etna_transfer_flush_region;
+   pctx->transfer_unmap = etna_transfer_unmap;
+   pctx->buffer_subdata = u_default_buffer_subdata;
+   pctx->texture_subdata = u_default_texture_subdata;
+}
diff --git a/src/gallium/drivers/etnaviv/etnaviv_transfer.h b/src/gallium/drivers/etnaviv/etnaviv_transfer.h
new file mode 100644
index 0000000..ca156a4
--- /dev/null
+++ b/src/gallium/drivers/etnaviv/etnaviv_transfer.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2012-2015 Etnaviv Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Wladimir J. van der Laan <laanwj at gmail.com>
+ */
+
+#ifndef H_ETNAVIV_TRANSFER
+#define H_ETNAVIV_TRANSFER
+
+#include "pipe/p_state.h"
+
+void
+etna_transfer_init(struct pipe_context *pctx);
+
+#endif
diff --git a/src/gallium/drivers/etnaviv/etnaviv_translate.h b/src/gallium/drivers/etnaviv/etnaviv_translate.h
new file mode 100644
index 0000000..d0623db
--- /dev/null
+++ b/src/gallium/drivers/etnaviv/etnaviv_translate.h
@@ -0,0 +1,516 @@
+/*
+ * Copyright (c) 2012-2013 Etnaviv Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+/* inlined translation functions between gallium and vivante */
+#ifndef H_TRANSLATE
+#define H_TRANSLATE
+
+#include "pipe/p_defines.h"
+#include "pipe/p_format.h"
+#include "pipe/p_state.h"
+
+#include "etnaviv_debug.h"
+#include "etnaviv_format.h"
+#include "etnaviv_tiling.h"
+#include "etnaviv_util.h"
+#include "hw/cmdstream.xml.h"
+#include "hw/state.xml.h"
+#include "hw/state_3d.xml.h"
+
+#include "util/u_format.h"
+
+#include <stdio.h>
+
+/* Returned when there is no match of pipe value to etna value */
+#define ETNA_NO_MATCH (~0)
+
+static inline uint32_t
+translate_cull_face(unsigned cull_face, unsigned front_ccw)
+{
+   switch (cull_face) {
+   case PIPE_FACE_NONE:
+      return VIVS_PA_CONFIG_CULL_FACE_MODE_OFF;
+   case PIPE_FACE_BACK:
+      return front_ccw ? VIVS_PA_CONFIG_CULL_FACE_MODE_CW
+                       : VIVS_PA_CONFIG_CULL_FACE_MODE_CCW;
+   case PIPE_FACE_FRONT:
+      return front_ccw ? VIVS_PA_CONFIG_CULL_FACE_MODE_CCW
+                       : VIVS_PA_CONFIG_CULL_FACE_MODE_CW;
+   default:
+      DBG("Unhandled cull face mode %i", cull_face);
+      return ETNA_NO_MATCH;
+   }
+}
+
+static inline uint32_t
+translate_polygon_mode(unsigned polygon_mode)
+{
+   switch (polygon_mode) {
+   case PIPE_POLYGON_MODE_FILL:
+      return VIVS_PA_CONFIG_FILL_MODE_SOLID;
+   case PIPE_POLYGON_MODE_LINE:
+      return VIVS_PA_CONFIG_FILL_MODE_WIREFRAME;
+   case PIPE_POLYGON_MODE_POINT:
+      return VIVS_PA_CONFIG_FILL_MODE_POINT;
+   default:
+      DBG("Unhandled polygon mode %i", polygon_mode);
+      return ETNA_NO_MATCH;
+   }
+}
+
+static inline uint32_t
+translate_stencil_mode(bool enable_0, bool enable_1)
+{
+   if (enable_0) {
+      return enable_1 ? VIVS_PE_STENCIL_CONFIG_MODE_TWO_SIDED
+                      : VIVS_PE_STENCIL_CONFIG_MODE_ONE_SIDED;
+   } else {
+      return VIVS_PE_STENCIL_CONFIG_MODE_DISABLED;
+   }
+}
+
+static inline uint32_t
+translate_stencil_op(unsigned stencil_op)
+{
+   switch (stencil_op) {
+   case PIPE_STENCIL_OP_KEEP:
+      return STENCIL_OP_KEEP;
+   case PIPE_STENCIL_OP_ZERO:
+      return STENCIL_OP_ZERO;
+   case PIPE_STENCIL_OP_REPLACE:
+      return STENCIL_OP_REPLACE;
+   case PIPE_STENCIL_OP_INCR:
+      return STENCIL_OP_INCR;
+   case PIPE_STENCIL_OP_DECR:
+      return STENCIL_OP_DECR;
+   case PIPE_STENCIL_OP_INCR_WRAP:
+      return STENCIL_OP_INCR_WRAP;
+   case PIPE_STENCIL_OP_DECR_WRAP:
+      return STENCIL_OP_DECR_WRAP;
+   case PIPE_STENCIL_OP_INVERT:
+      return STENCIL_OP_INVERT;
+   default:
+      DBG("Unhandled stencil op: %i", stencil_op);
+      return ETNA_NO_MATCH;
+   }
+}
+
+static inline uint32_t
+translate_blend(unsigned blend)
+{
+   switch (blend) {
+   case PIPE_BLEND_ADD:
+      return BLEND_EQ_ADD;
+   case PIPE_BLEND_SUBTRACT:
+      return BLEND_EQ_SUBTRACT;
+   case PIPE_BLEND_REVERSE_SUBTRACT:
+      return BLEND_EQ_REVERSE_SUBTRACT;
+   case PIPE_BLEND_MIN:
+      return BLEND_EQ_MIN;
+   case PIPE_BLEND_MAX:
+      return BLEND_EQ_MAX;
+   default:
+      DBG("Unhandled blend: %i", blend);
+      return ETNA_NO_MATCH;
+   }
+}
+
+static inline uint32_t
+translate_blend_factor(unsigned blend_factor)
+{
+   switch (blend_factor) {
+   case PIPE_BLENDFACTOR_ONE:
+      return BLEND_FUNC_ONE;
+   case PIPE_BLENDFACTOR_SRC_COLOR:
+      return BLEND_FUNC_SRC_COLOR;
+   case PIPE_BLENDFACTOR_SRC_ALPHA:
+      return BLEND_FUNC_SRC_ALPHA;
+   case PIPE_BLENDFACTOR_DST_ALPHA:
+      return BLEND_FUNC_DST_ALPHA;
+   case PIPE_BLENDFACTOR_DST_COLOR:
+      return BLEND_FUNC_DST_COLOR;
+   case PIPE_BLENDFACTOR_SRC_ALPHA_SATURATE:
+      return BLEND_FUNC_SRC_ALPHA_SATURATE;
+   case PIPE_BLENDFACTOR_CONST_COLOR:
+      return BLEND_FUNC_CONSTANT_COLOR;
+   case PIPE_BLENDFACTOR_CONST_ALPHA:
+      return BLEND_FUNC_CONSTANT_ALPHA;
+   case PIPE_BLENDFACTOR_ZERO:
+      return BLEND_FUNC_ZERO;
+   case PIPE_BLENDFACTOR_INV_SRC_COLOR:
+      return BLEND_FUNC_ONE_MINUS_SRC_COLOR;
+   case PIPE_BLENDFACTOR_INV_SRC_ALPHA:
+      return BLEND_FUNC_ONE_MINUS_SRC_ALPHA;
+   case PIPE_BLENDFACTOR_INV_DST_ALPHA:
+      return BLEND_FUNC_ONE_MINUS_DST_ALPHA;
+   case PIPE_BLENDFACTOR_INV_DST_COLOR:
+      return BLEND_FUNC_ONE_MINUS_DST_COLOR;
+   case PIPE_BLENDFACTOR_INV_CONST_COLOR:
+      return BLEND_FUNC_ONE_MINUS_CONSTANT_COLOR;
+   case PIPE_BLENDFACTOR_INV_CONST_ALPHA:
+      return BLEND_FUNC_ONE_MINUS_CONSTANT_ALPHA;
+   case PIPE_BLENDFACTOR_SRC1_COLOR:
+   case PIPE_BLENDFACTOR_SRC1_ALPHA:
+   case PIPE_BLENDFACTOR_INV_SRC1_COLOR:
+   case PIPE_BLENDFACTOR_INV_SRC1_ALPHA:
+   default:
+      DBG("Unhandled blend factor: %i", blend_factor);
+      return ETNA_NO_MATCH;
+   }
+}
+
+static inline uint32_t
+translate_texture_wrapmode(unsigned wrap)
+{
+   switch (wrap) {
+   case PIPE_TEX_WRAP_REPEAT:
+      return TEXTURE_WRAPMODE_REPEAT;
+   case PIPE_TEX_WRAP_CLAMP:
+      return TEXTURE_WRAPMODE_CLAMP_TO_EDGE;
+   case PIPE_TEX_WRAP_CLAMP_TO_EDGE:
+      return TEXTURE_WRAPMODE_CLAMP_TO_EDGE;
+   case PIPE_TEX_WRAP_CLAMP_TO_BORDER:
+      return TEXTURE_WRAPMODE_CLAMP_TO_EDGE; /* XXX */
+   case PIPE_TEX_WRAP_MIRROR_REPEAT:
+      return TEXTURE_WRAPMODE_MIRRORED_REPEAT;
+   case PIPE_TEX_WRAP_MIRROR_CLAMP:
+      return TEXTURE_WRAPMODE_MIRRORED_REPEAT; /* XXX */
+   case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE:
+      return TEXTURE_WRAPMODE_MIRRORED_REPEAT; /* XXX */
+   case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER:
+      return TEXTURE_WRAPMODE_MIRRORED_REPEAT; /* XXX */
+   default:
+      DBG("Unhandled texture wrapmode: %i", wrap);
+      return ETNA_NO_MATCH;
+   }
+}
+
+static inline uint32_t
+translate_texture_mipfilter(unsigned filter)
+{
+   switch (filter) {
+   case PIPE_TEX_MIPFILTER_NEAREST:
+      return TEXTURE_FILTER_NEAREST;
+   case PIPE_TEX_MIPFILTER_LINEAR:
+      return TEXTURE_FILTER_LINEAR;
+   case PIPE_TEX_MIPFILTER_NONE:
+      return TEXTURE_FILTER_NONE;
+   default:
+      DBG("Unhandled texture mipfilter: %i", filter);
+      return ETNA_NO_MATCH;
+   }
+}
+
+static inline uint32_t
+translate_texture_filter(unsigned filter)
+{
+   switch (filter) {
+   case PIPE_TEX_FILTER_NEAREST:
+      return TEXTURE_FILTER_NEAREST;
+   case PIPE_TEX_FILTER_LINEAR:
+      return TEXTURE_FILTER_LINEAR;
+   /* What about anisotropic? */
+   default:
+      DBG("Unhandled texture filter: %i", filter);
+      return ETNA_NO_MATCH;
+   }
+}
+
+/* return a RS "compatible" format for use when copying */
+static inline enum pipe_format
+etna_compatible_rs_format(enum pipe_format fmt)
+{
+   /* YUYV and UYVY are blocksize 4, but 2 bytes per pixel */
+   if (fmt == PIPE_FORMAT_YUYV || fmt == PIPE_FORMAT_UYVY)
+      return PIPE_FORMAT_B4G4R4A4_UNORM;
+
+   switch (util_format_get_blocksize(fmt)) {
+   case 2:
+      return PIPE_FORMAT_B4G4R4A4_UNORM;
+   case 4:
+      return PIPE_FORMAT_B8G8R8A8_UNORM;
+   default:
+      return fmt;
+   }
+}
+
+static inline int
+translate_rb_src_dst_swap(enum pipe_format src, enum pipe_format dst)
+{
+   return translate_rs_format_rb_swap(src) ^ translate_rs_format_rb_swap(dst);
+}
+
+static inline uint32_t
+translate_depth_format(enum pipe_format fmt)
+{
+   /* Note: Pipe format convention is LSB to MSB, VIVS is MSB to LSB */
+   switch (fmt) {
+   case PIPE_FORMAT_Z16_UNORM:
+      return VIVS_PE_DEPTH_CONFIG_DEPTH_FORMAT_D16;
+   case PIPE_FORMAT_X8Z24_UNORM:
+      return VIVS_PE_DEPTH_CONFIG_DEPTH_FORMAT_D24S8;
+   case PIPE_FORMAT_S8_UINT_Z24_UNORM:
+      return VIVS_PE_DEPTH_CONFIG_DEPTH_FORMAT_D24S8;
+   default:
+      return ETNA_NO_MATCH;
+   }
+}
+
+/* render target format for MSAA */
+static inline uint32_t
+translate_msaa_format(enum pipe_format fmt)
+{
+   /* Note: Pipe format convention is LSB to MSB, VIVS is MSB to LSB */
+   switch (fmt) {
+   case PIPE_FORMAT_B4G4R4X4_UNORM:
+      return VIVS_TS_MEM_CONFIG_MSAA_FORMAT_A4R4G4B4;
+   case PIPE_FORMAT_B4G4R4A4_UNORM:
+      return VIVS_TS_MEM_CONFIG_MSAA_FORMAT_A4R4G4B4;
+   case PIPE_FORMAT_B5G5R5X1_UNORM:
+      return VIVS_TS_MEM_CONFIG_MSAA_FORMAT_A1R5G5B5;
+   case PIPE_FORMAT_B5G5R5A1_UNORM:
+      return VIVS_TS_MEM_CONFIG_MSAA_FORMAT_A1R5G5B5;
+   case PIPE_FORMAT_B5G6R5_UNORM:
+      return VIVS_TS_MEM_CONFIG_MSAA_FORMAT_R5G6B5;
+   case PIPE_FORMAT_B8G8R8X8_UNORM:
+      return VIVS_TS_MEM_CONFIG_MSAA_FORMAT_X8R8G8B8;
+   case PIPE_FORMAT_B8G8R8A8_UNORM:
+      return VIVS_TS_MEM_CONFIG_MSAA_FORMAT_A8R8G8B8;
+   /* MSAA with YUYV not supported */
+   default:
+      return ETNA_NO_MATCH;
+   }
+}
+
+/* Return normalization flag for vertex element format */
+static inline uint32_t
+translate_vertex_format_normalize(enum pipe_format fmt)
+{
+   const struct util_format_description *desc = util_format_description(fmt);
+   if (!desc)
+      return VIVS_FE_VERTEX_ELEMENT_CONFIG_NORMALIZE_OFF;
+
+   /* assumes that normalization of channel 0 holds for all channels;
+    * this holds for all vertex formats that we support */
+   return desc->channel[0].normalized
+             ? VIVS_FE_VERTEX_ELEMENT_CONFIG_NORMALIZE_ON
+             : VIVS_FE_VERTEX_ELEMENT_CONFIG_NORMALIZE_OFF;
+}
+
+static inline uint32_t
+translate_index_size(unsigned index_size)
+{
+   switch (index_size) {
+   case 1:
+      return VIVS_FE_INDEX_STREAM_CONTROL_TYPE_UNSIGNED_CHAR;
+   case 2:
+      return VIVS_FE_INDEX_STREAM_CONTROL_TYPE_UNSIGNED_SHORT;
+   case 4:
+      return VIVS_FE_INDEX_STREAM_CONTROL_TYPE_UNSIGNED_INT;
+   default:
+      DBG("Unhandled index size %i", index_size);
+      return ETNA_NO_MATCH;
+   }
+}
+
+static inline uint32_t
+translate_draw_mode(unsigned mode)
+{
+   switch (mode) {
+   case PIPE_PRIM_POINTS:
+      return PRIMITIVE_TYPE_POINTS;
+   case PIPE_PRIM_LINES:
+      return PRIMITIVE_TYPE_LINES;
+   case PIPE_PRIM_LINE_LOOP:
+      return PRIMITIVE_TYPE_LINE_LOOP;
+   case PIPE_PRIM_LINE_STRIP:
+      return PRIMITIVE_TYPE_LINE_STRIP;
+   case PIPE_PRIM_TRIANGLES:
+      return PRIMITIVE_TYPE_TRIANGLES;
+   case PIPE_PRIM_TRIANGLE_STRIP:
+      return PRIMITIVE_TYPE_TRIANGLE_STRIP;
+   case PIPE_PRIM_TRIANGLE_FAN:
+      return PRIMITIVE_TYPE_TRIANGLE_FAN;
+   case PIPE_PRIM_QUADS:
+      return PRIMITIVE_TYPE_QUADS;
+   default:
+      DBG("Unhandled draw mode primitive %i", mode);
+      return ETNA_NO_MATCH;
+   }
+}
+
+/* Get size multiple for size of texture/rendertarget with a certain layout
+ * This is affected by many different parameters:
+ *   - A horizontal multiple of 16 is used when possible as resolve can be used
+ *       at the cost of only a little bit extra memory usage.
+ *   - If the surface is to be used with the resolve engine, set rs_align true.
+ *       If set, a horizontal multiple of 16 will be used for tiled and linear,
+ *       otherwise one of 16.  However, such a surface will be incompatible
+ *       with the samplers if the GPU does hot support the HALIGN feature.
+ *   - If the surface is supertiled, horizontal and vertical multiple is always 64
+ *   - If the surface is multi tiled or supertiled, make sure that the vertical size
+ *     is a multiple of the number of pixel pipes as well.
+ * */
+static inline void
+etna_layout_multiple(unsigned layout, unsigned pixel_pipes, bool rs_align,
+                     unsigned *paddingX, unsigned *paddingY, unsigned *halign)
+{
+   switch (layout) {
+   case ETNA_LAYOUT_LINEAR:
+      *paddingX = rs_align ? 16 : 4;
+      *paddingY = 1;
+      *halign = rs_align ? TEXTURE_HALIGN_SIXTEEN : TEXTURE_HALIGN_FOUR;
+      break;
+   case ETNA_LAYOUT_TILED:
+      *paddingX = rs_align ? 16 : 4;
+      *paddingY = 4;
+      *halign = rs_align ? TEXTURE_HALIGN_SIXTEEN : TEXTURE_HALIGN_FOUR;
+      break;
+   case ETNA_LAYOUT_SUPER_TILED:
+      *paddingX = 64;
+      *paddingY = 64;
+      *halign = TEXTURE_HALIGN_SUPER_TILED;
+      break;
+   case ETNA_LAYOUT_MULTI_TILED:
+      *paddingX = 16;
+      *paddingY = 4 * pixel_pipes;
+      *halign = TEXTURE_HALIGN_SPLIT_TILED;
+      break;
+   case ETNA_LAYOUT_MULTI_SUPERTILED:
+      *paddingX = 64;
+      *paddingY = 64 * pixel_pipes;
+      *halign = TEXTURE_HALIGN_SPLIT_SUPER_TILED;
+      break;
+   default:
+      DBG("Unhandled layout %i", layout);
+   }
+}
+
+/* return 32-bit clear pattern for color */
+static inline uint32_t
+translate_clear_color(enum pipe_format format,
+                      const union pipe_color_union *color)
+{
+   uint32_t clear_value = 0;
+
+   // XXX util_pack_color
+   switch (format) {
+   case PIPE_FORMAT_B8G8R8A8_UNORM:
+   case PIPE_FORMAT_B8G8R8X8_UNORM:
+      clear_value = etna_cfloat_to_uintN(color->f[2], 8) |
+                    (etna_cfloat_to_uintN(color->f[1], 8) << 8) |
+                    (etna_cfloat_to_uintN(color->f[0], 8) << 16) |
+                    (etna_cfloat_to_uintN(color->f[3], 8) << 24);
+      break;
+   case PIPE_FORMAT_B4G4R4X4_UNORM:
+   case PIPE_FORMAT_B4G4R4A4_UNORM:
+      clear_value = etna_cfloat_to_uintN(color->f[2], 4) |
+                    (etna_cfloat_to_uintN(color->f[1], 4) << 4) |
+                    (etna_cfloat_to_uintN(color->f[0], 4) << 8) |
+                    (etna_cfloat_to_uintN(color->f[3], 4) << 12);
+      clear_value |= clear_value << 16;
+      break;
+   case PIPE_FORMAT_B5G5R5X1_UNORM:
+   case PIPE_FORMAT_B5G5R5A1_UNORM:
+      clear_value = etna_cfloat_to_uintN(color->f[2], 5) |
+                    (etna_cfloat_to_uintN(color->f[1], 5) << 5) |
+                    (etna_cfloat_to_uintN(color->f[0], 5) << 10) |
+                    (etna_cfloat_to_uintN(color->f[3], 1) << 15);
+      clear_value |= clear_value << 16;
+      break;
+   case PIPE_FORMAT_B5G6R5_UNORM:
+      clear_value = etna_cfloat_to_uintN(color->f[2], 5) |
+                    (etna_cfloat_to_uintN(color->f[1], 6) << 5) |
+                    (etna_cfloat_to_uintN(color->f[0], 5) << 11);
+      clear_value |= clear_value << 16;
+      break;
+   default:
+      DBG("Unhandled pipe format for color clear: %i", format);
+   }
+
+   return clear_value;
+}
+
+static inline uint32_t
+translate_clear_depth_stencil(enum pipe_format format, float depth,
+                              unsigned stencil)
+{
+   uint32_t clear_value = 0;
+
+   // XXX util_pack_color
+   switch (format) {
+   case PIPE_FORMAT_Z16_UNORM:
+      clear_value = etna_cfloat_to_uintN(depth, 16);
+      clear_value |= clear_value << 16;
+      break;
+   case PIPE_FORMAT_X8Z24_UNORM:
+   case PIPE_FORMAT_S8_UINT_Z24_UNORM:
+      clear_value = (etna_cfloat_to_uintN(depth, 24) << 8) | (stencil & 0xFF);
+      break;
+   default:
+      DBG("Unhandled pipe format for depth stencil clear: %i", format);
+   }
+   return clear_value;
+}
+
+/* Convert MSAA number of samples to x and y scaling factor and
+ * VIVS_GL_MULTI_SAMPLE_CONFIG value.
+ * Return true if supported and false otherwise. */
+static inline bool
+translate_samples_to_xyscale(int num_samples, int *xscale_out, int *yscale_out,
+                             uint32_t *config_out)
+{
+   int xscale, yscale;
+   uint32_t config;
+
+   switch (num_samples) {
+   case 0:
+   case 1:
+      xscale = 1;
+      yscale = 1;
+      config = VIVS_GL_MULTI_SAMPLE_CONFIG_MSAA_SAMPLES_NONE;
+      break;
+   case 2:
+      xscale = 2;
+      yscale = 1;
+      config = VIVS_GL_MULTI_SAMPLE_CONFIG_MSAA_SAMPLES_2X;
+      break;
+   case 4:
+      xscale = 2;
+      yscale = 2;
+      config = VIVS_GL_MULTI_SAMPLE_CONFIG_MSAA_SAMPLES_4X;
+      break;
+   default:
+      return false;
+   }
+
+   if (xscale_out)
+      *xscale_out = xscale;
+   if (yscale_out)
+      *yscale_out = yscale;
+   if (config_out)
+      *config_out = config;
+
+   return true;
+}
+
+#endif
diff --git a/src/gallium/drivers/etnaviv/etnaviv_uniforms.c b/src/gallium/drivers/etnaviv/etnaviv_uniforms.c
new file mode 100644
index 0000000..70e5d58
--- /dev/null
+++ b/src/gallium/drivers/etnaviv/etnaviv_uniforms.c
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2016 Etnaviv Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Christian Gmeiner <christian.gmeiner at gmail.com>
+ */
+
+#include "etnaviv_uniforms.h"
+
+#include "etnaviv_compiler.h"
+#include "etnaviv_context.h"
+#include "etnaviv_util.h"
+#include "pipe/p_defines.h"
+#include "util/u_math.h"
+
+static unsigned
+get_const_idx(const struct etna_context *ctx, bool frag, unsigned samp_id)
+{
+   if (frag)
+      return samp_id;
+
+   return samp_id + ctx->specs.vertex_sampler_offset;
+}
+
+static uint32_t
+get_texrect_scale(const struct etna_context *ctx, bool frag,
+                  enum etna_immediate_contents contents, uint32_t data)
+{
+   unsigned index = get_const_idx(ctx, frag, data);
+   struct pipe_sampler_view *texture = ctx->sampler_view[index];
+   uint32_t dim;
+
+   if (contents == ETNA_IMMEDIATE_TEXRECT_SCALE_X)
+      dim = texture->texture->width0;
+   else
+      dim = texture->texture->height0;
+
+   return fui(1.0f / dim);
+}
+
+void
+etna_uniforms_write(const struct etna_context *ctx,
+                    const struct etna_shader *sobj,
+                    struct pipe_constant_buffer *cb, uint32_t *uniforms,
+                    unsigned *size)
+{
+   const struct etna_shader_uniform_info *uinfo = &sobj->uniforms;
+   bool frag = false;
+
+   if (cb->user_buffer) {
+      unsigned size = MIN2(cb->buffer_size, uinfo->const_count * 4);
+
+      memcpy(uniforms, cb->user_buffer, size);
+   }
+
+   if (sobj == ctx->fs)
+      frag = true;
+
+   for (uint32_t i = 0; i < uinfo->imm_count; i++) {
+      switch (uinfo->imm_contents[i]) {
+      case ETNA_IMMEDIATE_CONSTANT:
+         uniforms[i + uinfo->const_count] = uinfo->imm_data[i];
+         break;
+
+      case ETNA_IMMEDIATE_TEXRECT_SCALE_X:
+      case ETNA_IMMEDIATE_TEXRECT_SCALE_Y:
+         uniforms[i + uinfo->const_count] =
+               get_texrect_scale(ctx, frag, uinfo->imm_contents[i], uinfo->imm_data[i]);
+         break;
+
+      case ETNA_IMMEDIATE_UNUSED:
+         /* nothing to do */
+         break;
+      }
+   }
+
+   *size = uinfo->const_count + uinfo->imm_count;
+}
+
+void
+etna_set_shader_uniforms_dirty_flags(struct etna_shader *sobj)
+{
+   uint32_t dirty = 0;
+
+   for (uint32_t i = 0; i < sobj->uniforms.imm_count; i++) {
+      switch (sobj->uniforms.imm_contents[i]) {
+      case ETNA_IMMEDIATE_UNUSED:
+      case ETNA_IMMEDIATE_CONSTANT:
+         break;
+
+      case ETNA_IMMEDIATE_TEXRECT_SCALE_X:
+      case ETNA_IMMEDIATE_TEXRECT_SCALE_Y:
+         dirty |= ETNA_DIRTY_SAMPLER_VIEWS;
+         break;
+      }
+   }
+
+   sobj->uniforms_dirty_bits = dirty;
+}
diff --git a/src/gallium/drivers/etnaviv/etnaviv_uniforms.h b/src/gallium/drivers/etnaviv/etnaviv_uniforms.h
new file mode 100644
index 0000000..83a3a49
--- /dev/null
+++ b/src/gallium/drivers/etnaviv/etnaviv_uniforms.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2016 Etnaviv Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Christian Gmeiner <christian.gmeiner at gmail.com>
+ */
+
+#ifndef ETNAVIV_UNIFORMS_H_
+#define ETNAVIV_UNIFORMS_H_
+
+#include <stdint.h>
+
+struct etna_context;
+struct etna_shader;
+struct pipe_constant_buffer;
+
+void
+etna_uniforms_write(const struct etna_context *ctx,
+                    const struct etna_shader *sobj,
+                    struct pipe_constant_buffer *cb, uint32_t *uniforms,
+                    unsigned *size);
+
+void
+etna_set_shader_uniforms_dirty_flags(struct etna_shader *sobj);
+
+#endif /* ETNAVIV_UNIFORMS_H_ */
diff --git a/src/gallium/drivers/etnaviv/etnaviv_util.h b/src/gallium/drivers/etnaviv/etnaviv_util.h
new file mode 100644
index 0000000..62f6254
--- /dev/null
+++ b/src/gallium/drivers/etnaviv/etnaviv_util.h
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2012-2015 Etnaviv Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+/* Misc util */
+#ifndef H_ETNA_UTIL
+#define H_ETNA_UTIL
+
+#include <math.h>
+
+/* for conditionally setting boolean flag(s): */
+#define COND(bool, val) ((bool) ? (val) : 0)
+
+/* align to a value divisable by granularity >= value, works only for powers of two */
+static inline uint32_t
+etna_align_up(uint32_t value, uint32_t granularity)
+{
+   return (value + (granularity - 1)) & (~(granularity - 1));
+}
+
+static inline uint32_t
+etna_bits_ones(unsigned num)
+{
+   return (1 << num) - 1;
+}
+
+/* clamped float [0.0 .. 1.0] -> [0 .. 255] */
+static inline uint8_t
+etna_cfloat_to_uint8(float f)
+{
+   if (f <= 0.0f)
+      return 0;
+
+   if (f >= (1.0f - 1.0f / 256.0f))
+      return 255;
+
+   return f * 256.0f;
+}
+
+/* clamped float [0.0 .. 1.0] -> [0 .. (1<<bits)-1] */
+static inline uint32_t
+etna_cfloat_to_uintN(float f, int bits)
+{
+   if (f <= 0.0f)
+      return 0;
+
+   if (f >= (1.0f - 1.0f / (1 << bits)))
+      return (1 << bits) - 1;
+
+   return f * (1 << bits);
+}
+
+/* 1/log10(2) */
+#define RCPLOG2 (1.4426950408889634f)
+
+/* float to fixp 5.5 */
+static inline uint32_t
+etna_float_to_fixp55(float f)
+{
+   if (f >= 15.953125f)
+      return 511;
+
+   if (f < -16.0f)
+      return 512;
+
+   return (int32_t)(f * 32.0f + 0.5f);
+}
+
+/* texture size to log2 in fixp 5.5 format */
+static inline uint32_t
+etna_log2_fixp55(unsigned width)
+{
+   return etna_float_to_fixp55(logf((float)width) * RCPLOG2);
+}
+
+/* float to fixp 16.16 */
+static inline uint32_t
+etna_f32_to_fixp16(float f)
+{
+   if (f >= (32768.0f - 1.0f / 65536.0f))
+      return 0x7fffffff;
+
+   if (f < -32768.0f)
+      return 0x80000000;
+
+   return (int32_t)(f * 65536.0f + 0.5f);
+}
+
+#endif
diff --git a/src/gallium/drivers/etnaviv/etnaviv_zsa.c b/src/gallium/drivers/etnaviv/etnaviv_zsa.c
new file mode 100644
index 0000000..7caba27
--- /dev/null
+++ b/src/gallium/drivers/etnaviv/etnaviv_zsa.c
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2012-2015 Etnaviv Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Wladimir J. van der Laan <laanwj at gmail.com>
+ */
+
+#include "etnaviv_zsa.h"
+
+#include "etnaviv_context.h"
+#include "etnaviv_translate.h"
+#include "util/u_memory.h"
+
+void *
+etna_zsa_state_create(struct pipe_context *pctx,
+                      const struct pipe_depth_stencil_alpha_state *so)
+{
+   struct etna_zsa_state *cs = CALLOC_STRUCT(etna_zsa_state);
+
+   if (!cs)
+      return NULL;
+
+   cs->base = *so;
+
+   /* XXX does stencil[0] / stencil[1] order depend on rs->front_ccw? */
+   bool early_z = true;
+   bool disable_zs =
+      (!so->depth.enabled || so->depth.func == PIPE_FUNC_ALWAYS) &&
+      !so->depth.writemask;
+
+/* Set operations to KEEP if write mask is 0.
+ * When we don't do this, the depth buffer is written for the entire primitive
+ * instead of just where the stencil condition holds (GC600 rev 0x0019, without
+ * feature CORRECT_STENCIL).
+ * Not sure if this is a hardware bug or just a strange edge case. */
+#if 0 /* TODO: It looks like a hardware bug */
+    for(int i=0; i<2; ++i)
+    {
+        if(so->stencil[i].writemask == 0)
+        {
+            so->stencil[i].fail_op = so->stencil[i].zfail_op = so->stencil[i].zpass_op = PIPE_STENCIL_OP_KEEP;
+        }
+    }
+#endif
+
+   /* Determine whether to enable early z reject. Don't enable it when any of
+    * the stencil-modifying functions is used. */
+   if (so->stencil[0].enabled) {
+      if (so->stencil[0].func != PIPE_FUNC_ALWAYS ||
+          (so->stencil[1].enabled && so->stencil[1].func != PIPE_FUNC_ALWAYS))
+         disable_zs = false;
+
+      if (so->stencil[0].fail_op != PIPE_STENCIL_OP_KEEP ||
+          so->stencil[0].zfail_op != PIPE_STENCIL_OP_KEEP ||
+          so->stencil[0].zpass_op != PIPE_STENCIL_OP_KEEP) {
+         disable_zs = early_z = false;
+      } else if (so->stencil[1].enabled) {
+         if (so->stencil[1].fail_op != PIPE_STENCIL_OP_KEEP ||
+             so->stencil[1].zfail_op != PIPE_STENCIL_OP_KEEP ||
+             so->stencil[1].zpass_op != PIPE_STENCIL_OP_KEEP) {
+            disable_zs = early_z = false;
+         }
+      }
+   }
+
+   /* Disable early z reject when no depth test is enabled.
+    * This avoids having to sample depth even though we know it's going to
+    * succeed. */
+   if (so->depth.enabled == false || so->depth.func == PIPE_FUNC_ALWAYS)
+      early_z = false;
+
+   if (DBG_ENABLED(ETNA_DBG_NO_EARLY_Z))
+      early_z = false;
+
+   /* compare funcs have 1 to 1 mapping */
+   cs->PE_DEPTH_CONFIG =
+      VIVS_PE_DEPTH_CONFIG_DEPTH_FUNC(so->depth.enabled ? so->depth.func
+                                                        : PIPE_FUNC_ALWAYS) |
+      COND(so->depth.writemask, VIVS_PE_DEPTH_CONFIG_WRITE_ENABLE) |
+      COND(early_z, VIVS_PE_DEPTH_CONFIG_EARLY_Z) |
+      COND(disable_zs, VIVS_PE_DEPTH_CONFIG_DISABLE_ZS);
+   cs->PE_ALPHA_OP =
+      COND(so->alpha.enabled, VIVS_PE_ALPHA_OP_ALPHA_TEST) |
+      VIVS_PE_ALPHA_OP_ALPHA_FUNC(so->alpha.func) |
+      VIVS_PE_ALPHA_OP_ALPHA_REF(etna_cfloat_to_uint8(so->alpha.ref_value));
+   cs->PE_STENCIL_OP =
+      VIVS_PE_STENCIL_OP_FUNC_FRONT(so->stencil[0].func) |
+      VIVS_PE_STENCIL_OP_FUNC_BACK(so->stencil[1].func) |
+      VIVS_PE_STENCIL_OP_FAIL_FRONT(translate_stencil_op(so->stencil[0].fail_op)) |
+      VIVS_PE_STENCIL_OP_FAIL_BACK(translate_stencil_op(so->stencil[1].fail_op)) |
+      VIVS_PE_STENCIL_OP_DEPTH_FAIL_FRONT(translate_stencil_op(so->stencil[0].zfail_op)) |
+      VIVS_PE_STENCIL_OP_DEPTH_FAIL_BACK(translate_stencil_op(so->stencil[1].zfail_op)) |
+      VIVS_PE_STENCIL_OP_PASS_FRONT(translate_stencil_op(so->stencil[0].zpass_op)) |
+      VIVS_PE_STENCIL_OP_PASS_BACK(translate_stencil_op(so->stencil[1].zpass_op));
+   cs->PE_STENCIL_CONFIG =
+      translate_stencil_mode(so->stencil[0].enabled, so->stencil[1].enabled) |
+      VIVS_PE_STENCIL_CONFIG_MASK_FRONT(so->stencil[0].valuemask) |
+      VIVS_PE_STENCIL_CONFIG_WRITE_MASK_FRONT(so->stencil[0].writemask);
+   /* XXX back masks in VIVS_PE_DEPTH_CONFIG_EXT? */
+   /* XXX VIVS_PE_STENCIL_CONFIG_REF_FRONT comes from pipe_stencil_ref */
+
+   /* XXX does alpha/stencil test affect PE_COLOR_FORMAT_OVERWRITE? */
+   return cs;
+}
diff --git a/src/gallium/drivers/etnaviv/etnaviv_zsa.h b/src/gallium/drivers/etnaviv/etnaviv_zsa.h
new file mode 100644
index 0000000..953a6a7
--- /dev/null
+++ b/src/gallium/drivers/etnaviv/etnaviv_zsa.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2012-2015 Etnaviv Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Wladimir J. van der Laan <laanwj at gmail.com>
+ */
+
+#ifndef H_ETNAVIV_ZSA
+#define H_ETNAVIV_ZSA
+
+#include "pipe/p_context.h"
+#include "pipe/p_state.h"
+
+struct etna_zsa_state {
+   struct pipe_depth_stencil_alpha_state base;
+
+   uint32_t PE_DEPTH_CONFIG;
+   uint32_t PE_ALPHA_OP;
+   uint32_t PE_STENCIL_OP;
+   uint32_t PE_STENCIL_CONFIG;
+};
+
+static inline struct etna_zsa_state *
+etna_zsa_state(struct pipe_depth_stencil_alpha_state *zsa)
+{
+   return (struct etna_zsa_state *)zsa;
+}
+
+void *
+etna_zsa_state_create(struct pipe_context *pctx,
+                      const struct pipe_depth_stencil_alpha_state *so);
+
+#endif
diff --git a/src/gallium/drivers/etnaviv/hw/cmdstream.xml.h b/src/gallium/drivers/etnaviv/hw/cmdstream.xml.h
new file mode 100644
index 0000000..c5275db
--- /dev/null
+++ b/src/gallium/drivers/etnaviv/hw/cmdstream.xml.h
@@ -0,0 +1,270 @@
+#ifndef CMDSTREAM_XML
+#define CMDSTREAM_XML
+
+/* Autogenerated file, DO NOT EDIT manually!
+
+This file was generated by the rules-ng-ng headergen tool in this git repository:
+http://0x04.net/cgit/index.cgi/rules-ng-ng
+git clone git://0x04.net/rules-ng-ng
+
+The rules-ng-ng source files this header was generated from are:
+- cmdstream.xml (  14094 bytes, from 2016-11-16 18:54:37)
+- copyright.xml (   1597 bytes, from 2016-10-02 14:26:13)
+- common.xml    (  23422 bytes, from 2016-11-16 18:54:37)
+
+Copyright (C) 2012-2016 by the following authors:
+- Wladimir J. van der Laan <laanwj at gmail.com>
+- Christian Gmeiner <christian.gmeiner at gmail.com>
+- Lucas Stach <l.stach at pengutronix.de>
+- Russell King <rmk at arm.linux.org.uk>
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sub license,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice (including the
+next paragraph) shall be included in all copies or substantial portions
+of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+*/
+
+
+#define FE_OPCODE_LOAD_STATE					0x00000001
+#define FE_OPCODE_END						0x00000002
+#define FE_OPCODE_NOP						0x00000003
+#define FE_OPCODE_DRAW_2D					0x00000004
+#define FE_OPCODE_DRAW_PRIMITIVES				0x00000005
+#define FE_OPCODE_DRAW_INDEXED_PRIMITIVES			0x00000006
+#define FE_OPCODE_WAIT						0x00000007
+#define FE_OPCODE_LINK						0x00000008
+#define FE_OPCODE_STALL						0x00000009
+#define FE_OPCODE_CALL						0x0000000a
+#define FE_OPCODE_RETURN					0x0000000b
+#define FE_OPCODE_DRAW_INSTANCED				0x0000000c
+#define FE_OPCODE_CHIP_SELECT					0x0000000d
+#define PRIMITIVE_TYPE_POINTS					0x00000001
+#define PRIMITIVE_TYPE_LINES					0x00000002
+#define PRIMITIVE_TYPE_LINE_STRIP				0x00000003
+#define PRIMITIVE_TYPE_TRIANGLES				0x00000004
+#define PRIMITIVE_TYPE_TRIANGLE_STRIP				0x00000005
+#define PRIMITIVE_TYPE_TRIANGLE_FAN				0x00000006
+#define PRIMITIVE_TYPE_LINE_LOOP				0x00000007
+#define PRIMITIVE_TYPE_QUADS					0x00000008
+#define VIV_FE_LOAD_STATE					0x00000000
+
+#define VIV_FE_LOAD_STATE_HEADER				0x00000000
+#define VIV_FE_LOAD_STATE_HEADER_OP__MASK			0xf8000000
+#define VIV_FE_LOAD_STATE_HEADER_OP__SHIFT			27
+#define VIV_FE_LOAD_STATE_HEADER_OP_LOAD_STATE			0x08000000
+#define VIV_FE_LOAD_STATE_HEADER_FIXP				0x04000000
+#define VIV_FE_LOAD_STATE_HEADER_COUNT__MASK			0x03ff0000
+#define VIV_FE_LOAD_STATE_HEADER_COUNT__SHIFT			16
+#define VIV_FE_LOAD_STATE_HEADER_COUNT(x)			(((x) << VIV_FE_LOAD_STATE_HEADER_COUNT__SHIFT) & VIV_FE_LOAD_STATE_HEADER_COUNT__MASK)
+#define VIV_FE_LOAD_STATE_HEADER_OFFSET__MASK			0x0000ffff
+#define VIV_FE_LOAD_STATE_HEADER_OFFSET__SHIFT			0
+#define VIV_FE_LOAD_STATE_HEADER_OFFSET(x)			(((x) << VIV_FE_LOAD_STATE_HEADER_OFFSET__SHIFT) & VIV_FE_LOAD_STATE_HEADER_OFFSET__MASK)
+#define VIV_FE_LOAD_STATE_HEADER_OFFSET__SHR			2
+
+#define VIV_FE_END						0x00000000
+
+#define VIV_FE_END_HEADER					0x00000000
+#define VIV_FE_END_HEADER_EVENT_ID__MASK			0x0000001f
+#define VIV_FE_END_HEADER_EVENT_ID__SHIFT			0
+#define VIV_FE_END_HEADER_EVENT_ID(x)				(((x) << VIV_FE_END_HEADER_EVENT_ID__SHIFT) & VIV_FE_END_HEADER_EVENT_ID__MASK)
+#define VIV_FE_END_HEADER_EVENT_ENABLE				0x00000100
+#define VIV_FE_END_HEADER_OP__MASK				0xf8000000
+#define VIV_FE_END_HEADER_OP__SHIFT				27
+#define VIV_FE_END_HEADER_OP_END				0x10000000
+
+#define VIV_FE_NOP						0x00000000
+
+#define VIV_FE_NOP_HEADER					0x00000000
+#define VIV_FE_NOP_HEADER_OP__MASK				0xf8000000
+#define VIV_FE_NOP_HEADER_OP__SHIFT				27
+#define VIV_FE_NOP_HEADER_OP_NOP				0x18000000
+
+#define VIV_FE_DRAW_2D						0x00000000
+
+#define VIV_FE_DRAW_2D_HEADER					0x00000000
+#define VIV_FE_DRAW_2D_HEADER_COUNT__MASK			0x0000ff00
+#define VIV_FE_DRAW_2D_HEADER_COUNT__SHIFT			8
+#define VIV_FE_DRAW_2D_HEADER_COUNT(x)				(((x) << VIV_FE_DRAW_2D_HEADER_COUNT__SHIFT) & VIV_FE_DRAW_2D_HEADER_COUNT__MASK)
+#define VIV_FE_DRAW_2D_HEADER_DATA_COUNT__MASK			0x07ff0000
+#define VIV_FE_DRAW_2D_HEADER_DATA_COUNT__SHIFT			16
+#define VIV_FE_DRAW_2D_HEADER_DATA_COUNT(x)			(((x) << VIV_FE_DRAW_2D_HEADER_DATA_COUNT__SHIFT) & VIV_FE_DRAW_2D_HEADER_DATA_COUNT__MASK)
+#define VIV_FE_DRAW_2D_HEADER_OP__MASK				0xf8000000
+#define VIV_FE_DRAW_2D_HEADER_OP__SHIFT				27
+#define VIV_FE_DRAW_2D_HEADER_OP_DRAW_2D			0x20000000
+
+#define VIV_FE_DRAW_2D_TOP_LEFT					0x00000008
+#define VIV_FE_DRAW_2D_TOP_LEFT_X__MASK				0x0000ffff
+#define VIV_FE_DRAW_2D_TOP_LEFT_X__SHIFT			0
+#define VIV_FE_DRAW_2D_TOP_LEFT_X(x)				(((x) << VIV_FE_DRAW_2D_TOP_LEFT_X__SHIFT) & VIV_FE_DRAW_2D_TOP_LEFT_X__MASK)
+#define VIV_FE_DRAW_2D_TOP_LEFT_Y__MASK				0xffff0000
+#define VIV_FE_DRAW_2D_TOP_LEFT_Y__SHIFT			16
+#define VIV_FE_DRAW_2D_TOP_LEFT_Y(x)				(((x) << VIV_FE_DRAW_2D_TOP_LEFT_Y__SHIFT) & VIV_FE_DRAW_2D_TOP_LEFT_Y__MASK)
+
+#define VIV_FE_DRAW_2D_BOTTOM_RIGHT				0x0000000c
+#define VIV_FE_DRAW_2D_BOTTOM_RIGHT_X__MASK			0x0000ffff
+#define VIV_FE_DRAW_2D_BOTTOM_RIGHT_X__SHIFT			0
+#define VIV_FE_DRAW_2D_BOTTOM_RIGHT_X(x)			(((x) << VIV_FE_DRAW_2D_BOTTOM_RIGHT_X__SHIFT) & VIV_FE_DRAW_2D_BOTTOM_RIGHT_X__MASK)
+#define VIV_FE_DRAW_2D_BOTTOM_RIGHT_Y__MASK			0xffff0000
+#define VIV_FE_DRAW_2D_BOTTOM_RIGHT_Y__SHIFT			16
+#define VIV_FE_DRAW_2D_BOTTOM_RIGHT_Y(x)			(((x) << VIV_FE_DRAW_2D_BOTTOM_RIGHT_Y__SHIFT) & VIV_FE_DRAW_2D_BOTTOM_RIGHT_Y__MASK)
+
+#define VIV_FE_DRAW_PRIMITIVES					0x00000000
+
+#define VIV_FE_DRAW_PRIMITIVES_HEADER				0x00000000
+#define VIV_FE_DRAW_PRIMITIVES_HEADER_OP__MASK			0xf8000000
+#define VIV_FE_DRAW_PRIMITIVES_HEADER_OP__SHIFT			27
+#define VIV_FE_DRAW_PRIMITIVES_HEADER_OP_DRAW_PRIMITIVES	0x28000000
+
+#define VIV_FE_DRAW_PRIMITIVES_COMMAND				0x00000004
+#define VIV_FE_DRAW_PRIMITIVES_COMMAND_TYPE__MASK		0x000000ff
+#define VIV_FE_DRAW_PRIMITIVES_COMMAND_TYPE__SHIFT		0
+#define VIV_FE_DRAW_PRIMITIVES_COMMAND_TYPE(x)			(((x) << VIV_FE_DRAW_PRIMITIVES_COMMAND_TYPE__SHIFT) & VIV_FE_DRAW_PRIMITIVES_COMMAND_TYPE__MASK)
+
+#define VIV_FE_DRAW_PRIMITIVES_START				0x00000008
+
+#define VIV_FE_DRAW_PRIMITIVES_COUNT				0x0000000c
+
+#define VIV_FE_DRAW_INDEXED_PRIMITIVES				0x00000000
+
+#define VIV_FE_DRAW_INDEXED_PRIMITIVES_HEADER			0x00000000
+#define VIV_FE_DRAW_INDEXED_PRIMITIVES_HEADER_OP__MASK		0xf8000000
+#define VIV_FE_DRAW_INDEXED_PRIMITIVES_HEADER_OP__SHIFT		27
+#define VIV_FE_DRAW_INDEXED_PRIMITIVES_HEADER_OP_DRAW_INDEXED_PRIMITIVES	0x30000000
+
+#define VIV_FE_DRAW_INDEXED_PRIMITIVES_COMMAND			0x00000004
+#define VIV_FE_DRAW_INDEXED_PRIMITIVES_COMMAND_TYPE__MASK	0x000000ff
+#define VIV_FE_DRAW_INDEXED_PRIMITIVES_COMMAND_TYPE__SHIFT	0
+#define VIV_FE_DRAW_INDEXED_PRIMITIVES_COMMAND_TYPE(x)		(((x) << VIV_FE_DRAW_INDEXED_PRIMITIVES_COMMAND_TYPE__SHIFT) & VIV_FE_DRAW_INDEXED_PRIMITIVES_COMMAND_TYPE__MASK)
+
+#define VIV_FE_DRAW_INDEXED_PRIMITIVES_START			0x00000008
+
+#define VIV_FE_DRAW_INDEXED_PRIMITIVES_COUNT			0x0000000c
+
+#define VIV_FE_DRAW_INDEXED_PRIMITIVES_OFFSET			0x00000010
+
+#define VIV_FE_WAIT						0x00000000
+
+#define VIV_FE_WAIT_HEADER					0x00000000
+#define VIV_FE_WAIT_HEADER_DELAY__MASK				0x0000ffff
+#define VIV_FE_WAIT_HEADER_DELAY__SHIFT				0
+#define VIV_FE_WAIT_HEADER_DELAY(x)				(((x) << VIV_FE_WAIT_HEADER_DELAY__SHIFT) & VIV_FE_WAIT_HEADER_DELAY__MASK)
+#define VIV_FE_WAIT_HEADER_OP__MASK				0xf8000000
+#define VIV_FE_WAIT_HEADER_OP__SHIFT				27
+#define VIV_FE_WAIT_HEADER_OP_WAIT				0x38000000
+
+#define VIV_FE_LINK						0x00000000
+
+#define VIV_FE_LINK_HEADER					0x00000000
+#define VIV_FE_LINK_HEADER_PREFETCH__MASK			0x0000ffff
+#define VIV_FE_LINK_HEADER_PREFETCH__SHIFT			0
+#define VIV_FE_LINK_HEADER_PREFETCH(x)				(((x) << VIV_FE_LINK_HEADER_PREFETCH__SHIFT) & VIV_FE_LINK_HEADER_PREFETCH__MASK)
+#define VIV_FE_LINK_HEADER_OP__MASK				0xf8000000
+#define VIV_FE_LINK_HEADER_OP__SHIFT				27
+#define VIV_FE_LINK_HEADER_OP_LINK				0x40000000
+
+#define VIV_FE_LINK_ADDRESS					0x00000004
+
+#define VIV_FE_STALL						0x00000000
+
+#define VIV_FE_STALL_HEADER					0x00000000
+#define VIV_FE_STALL_HEADER_OP__MASK				0xf8000000
+#define VIV_FE_STALL_HEADER_OP__SHIFT				27
+#define VIV_FE_STALL_HEADER_OP_STALL				0x48000000
+
+#define VIV_FE_STALL_TOKEN					0x00000004
+#define VIV_FE_STALL_TOKEN_FROM__MASK				0x0000001f
+#define VIV_FE_STALL_TOKEN_FROM__SHIFT				0
+#define VIV_FE_STALL_TOKEN_FROM(x)				(((x) << VIV_FE_STALL_TOKEN_FROM__SHIFT) & VIV_FE_STALL_TOKEN_FROM__MASK)
+#define VIV_FE_STALL_TOKEN_TO__MASK				0x00001f00
+#define VIV_FE_STALL_TOKEN_TO__SHIFT				8
+#define VIV_FE_STALL_TOKEN_TO(x)				(((x) << VIV_FE_STALL_TOKEN_TO__SHIFT) & VIV_FE_STALL_TOKEN_TO__MASK)
+
+#define VIV_FE_CALL						0x00000000
+
+#define VIV_FE_CALL_HEADER					0x00000000
+#define VIV_FE_CALL_HEADER_PREFETCH__MASK			0x0000ffff
+#define VIV_FE_CALL_HEADER_PREFETCH__SHIFT			0
+#define VIV_FE_CALL_HEADER_PREFETCH(x)				(((x) << VIV_FE_CALL_HEADER_PREFETCH__SHIFT) & VIV_FE_CALL_HEADER_PREFETCH__MASK)
+#define VIV_FE_CALL_HEADER_OP__MASK				0xf8000000
+#define VIV_FE_CALL_HEADER_OP__SHIFT				27
+#define VIV_FE_CALL_HEADER_OP_CALL				0x50000000
+
+#define VIV_FE_CALL_ADDRESS					0x00000004
+
+#define VIV_FE_CALL_RETURN_PREFETCH				0x00000008
+
+#define VIV_FE_CALL_RETURN_ADDRESS				0x0000000c
+
+#define VIV_FE_RETURN						0x00000000
+
+#define VIV_FE_RETURN_HEADER					0x00000000
+#define VIV_FE_RETURN_HEADER_OP__MASK				0xf8000000
+#define VIV_FE_RETURN_HEADER_OP__SHIFT				27
+#define VIV_FE_RETURN_HEADER_OP_RETURN				0x58000000
+
+#define VIV_FE_CHIP_SELECT					0x00000000
+
+#define VIV_FE_CHIP_SELECT_HEADER				0x00000000
+#define VIV_FE_CHIP_SELECT_HEADER_OP__MASK			0xf8000000
+#define VIV_FE_CHIP_SELECT_HEADER_OP__SHIFT			27
+#define VIV_FE_CHIP_SELECT_HEADER_OP_CHIP_SELECT		0x68000000
+#define VIV_FE_CHIP_SELECT_HEADER_ENABLE_CHIP15			0x00008000
+#define VIV_FE_CHIP_SELECT_HEADER_ENABLE_CHIP14			0x00004000
+#define VIV_FE_CHIP_SELECT_HEADER_ENABLE_CHIP13			0x00002000
+#define VIV_FE_CHIP_SELECT_HEADER_ENABLE_CHIP12			0x00001000
+#define VIV_FE_CHIP_SELECT_HEADER_ENABLE_CHIP11			0x00000800
+#define VIV_FE_CHIP_SELECT_HEADER_ENABLE_CHIP10			0x00000400
+#define VIV_FE_CHIP_SELECT_HEADER_ENABLE_CHIP9			0x00000200
+#define VIV_FE_CHIP_SELECT_HEADER_ENABLE_CHIP8			0x00000100
+#define VIV_FE_CHIP_SELECT_HEADER_ENABLE_CHIP7			0x00000080
+#define VIV_FE_CHIP_SELECT_HEADER_ENABLE_CHIP6			0x00000040
+#define VIV_FE_CHIP_SELECT_HEADER_ENABLE_CHIP5			0x00000020
+#define VIV_FE_CHIP_SELECT_HEADER_ENABLE_CHIP4			0x00000010
+#define VIV_FE_CHIP_SELECT_HEADER_ENABLE_CHIP3			0x00000008
+#define VIV_FE_CHIP_SELECT_HEADER_ENABLE_CHIP2			0x00000004
+#define VIV_FE_CHIP_SELECT_HEADER_ENABLE_CHIP1			0x00000002
+#define VIV_FE_CHIP_SELECT_HEADER_ENABLE_CHIP0			0x00000001
+
+#define VIV_FE_DRAW_INSTANCED					0x00000000
+
+#define VIV_FE_DRAW_INSTANCED_HEADER				0x00000000
+#define VIV_FE_DRAW_INSTANCED_HEADER_OP__MASK			0xf8000000
+#define VIV_FE_DRAW_INSTANCED_HEADER_OP__SHIFT			27
+#define VIV_FE_DRAW_INSTANCED_HEADER_OP_DRAW_INSTANCED		0x60000000
+#define VIV_FE_DRAW_INSTANCED_HEADER_INDEXED			0x00100000
+#define VIV_FE_DRAW_INSTANCED_HEADER_TYPE__MASK			0x000f0000
+#define VIV_FE_DRAW_INSTANCED_HEADER_TYPE__SHIFT		16
+#define VIV_FE_DRAW_INSTANCED_HEADER_TYPE(x)			(((x) << VIV_FE_DRAW_INSTANCED_HEADER_TYPE__SHIFT) & VIV_FE_DRAW_INSTANCED_HEADER_TYPE__MASK)
+#define VIV_FE_DRAW_INSTANCED_HEADER_INSTANCE_COUNT_LO__MASK	0x0000ffff
+#define VIV_FE_DRAW_INSTANCED_HEADER_INSTANCE_COUNT_LO__SHIFT	0
+#define VIV_FE_DRAW_INSTANCED_HEADER_INSTANCE_COUNT_LO(x)	(((x) << VIV_FE_DRAW_INSTANCED_HEADER_INSTANCE_COUNT_LO__SHIFT) & VIV_FE_DRAW_INSTANCED_HEADER_INSTANCE_COUNT_LO__MASK)
+
+#define VIV_FE_DRAW_INSTANCED_COUNT				0x00000004
+#define VIV_FE_DRAW_INSTANCED_COUNT_INSTANCE_COUNT_HI__MASK	0xff000000
+#define VIV_FE_DRAW_INSTANCED_COUNT_INSTANCE_COUNT_HI__SHIFT	24
+#define VIV_FE_DRAW_INSTANCED_COUNT_INSTANCE_COUNT_HI(x)	(((x) << VIV_FE_DRAW_INSTANCED_COUNT_INSTANCE_COUNT_HI__SHIFT) & VIV_FE_DRAW_INSTANCED_COUNT_INSTANCE_COUNT_HI__MASK)
+#define VIV_FE_DRAW_INSTANCED_COUNT_VERTEX_COUNT__MASK		0x00ffffff
+#define VIV_FE_DRAW_INSTANCED_COUNT_VERTEX_COUNT__SHIFT		0
+#define VIV_FE_DRAW_INSTANCED_COUNT_VERTEX_COUNT(x)		(((x) << VIV_FE_DRAW_INSTANCED_COUNT_VERTEX_COUNT__SHIFT) & VIV_FE_DRAW_INSTANCED_COUNT_VERTEX_COUNT__MASK)
+
+#define VIV_FE_DRAW_INSTANCED_START				0x00000008
+#define VIV_FE_DRAW_INSTANCED_START_INDEX__MASK			0xffffffff
+#define VIV_FE_DRAW_INSTANCED_START_INDEX__SHIFT		0
+#define VIV_FE_DRAW_INSTANCED_START_INDEX(x)			(((x) << VIV_FE_DRAW_INSTANCED_START_INDEX__SHIFT) & VIV_FE_DRAW_INSTANCED_START_INDEX__MASK)
+
+
+#endif /* CMDSTREAM_XML */
diff --git a/src/gallium/drivers/etnaviv/hw/common.xml.h b/src/gallium/drivers/etnaviv/hw/common.xml.h
new file mode 100644
index 0000000..8d8ef7d
--- /dev/null
+++ b/src/gallium/drivers/etnaviv/hw/common.xml.h
@@ -0,0 +1,320 @@
+#ifndef COMMON_XML
+#define COMMON_XML
+
+/* Autogenerated file, DO NOT EDIT manually!
+
+This file was generated by the rules-ng-ng headergen tool in this git repository:
+http://0x04.net/cgit/index.cgi/rules-ng-ng
+git clone git://0x04.net/rules-ng-ng
+
+The rules-ng-ng source files this header was generated from are:
+- state.xml     (  19792 bytes, from 2016-11-16 18:54:37)
+- common.xml    (  23422 bytes, from 2016-11-16 18:54:37)
+- state_hi.xml  (  25653 bytes, from 2016-10-02 14:26:13)
+- copyright.xml (   1597 bytes, from 2016-10-02 14:26:13)
+- state_2d.xml  (  51552 bytes, from 2016-10-02 14:26:13)
+- state_3d.xml  (  57579 bytes, from 2016-11-16 18:54:37)
+- state_vg.xml  (   5975 bytes, from 2016-10-02 14:26:13)
+
+Copyright (C) 2012-2016 by the following authors:
+- Wladimir J. van der Laan <laanwj at gmail.com>
+- Christian Gmeiner <christian.gmeiner at gmail.com>
+- Lucas Stach <l.stach at pengutronix.de>
+- Russell King <rmk at arm.linux.org.uk>
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sub license,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice (including the
+next paragraph) shall be included in all copies or substantial portions
+of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+*/
+
+
+#define PIPE_ID_PIPE_3D						0x00000000
+#define PIPE_ID_PIPE_2D						0x00000001
+#define SYNC_RECIPIENT_FE					0x00000001
+#define SYNC_RECIPIENT_RA					0x00000005
+#define SYNC_RECIPIENT_PE					0x00000007
+#define SYNC_RECIPIENT_DE					0x0000000b
+#define SYNC_RECIPIENT_VG					0x0000000f
+#define SYNC_RECIPIENT_TESSELATOR				0x00000010
+#define SYNC_RECIPIENT_VG2					0x00000011
+#define SYNC_RECIPIENT_TESSELATOR2				0x00000012
+#define SYNC_RECIPIENT_VG3					0x00000013
+#define SYNC_RECIPIENT_TESSELATOR3				0x00000014
+#define ENDIAN_MODE_NO_SWAP					0x00000000
+#define ENDIAN_MODE_SWAP_16					0x00000001
+#define ENDIAN_MODE_SWAP_32					0x00000002
+#define chipModel_GC200						0x00000200
+#define chipModel_GC300						0x00000300
+#define chipModel_GC320						0x00000320
+#define chipModel_GC328						0x00000328
+#define chipModel_GC350						0x00000350
+#define chipModel_GC355						0x00000355
+#define chipModel_GC400						0x00000400
+#define chipModel_GC410						0x00000410
+#define chipModel_GC420						0x00000420
+#define chipModel_GC428						0x00000428
+#define chipModel_GC450						0x00000450
+#define chipModel_GC500						0x00000500
+#define chipModel_GC520						0x00000520
+#define chipModel_GC530						0x00000530
+#define chipModel_GC600						0x00000600
+#define chipModel_GC700						0x00000700
+#define chipModel_GC800						0x00000800
+#define chipModel_GC860						0x00000860
+#define chipModel_GC880						0x00000880
+#define chipModel_GC1000					0x00001000
+#define chipModel_GC1500					0x00001500
+#define chipModel_GC2000					0x00002000
+#define chipModel_GC2100					0x00002100
+#define chipModel_GC2200					0x00002200
+#define chipModel_GC2500					0x00002500
+#define chipModel_GC3000					0x00003000
+#define chipModel_GC4000					0x00004000
+#define chipModel_GC5000					0x00005000
+#define chipModel_GC5200					0x00005200
+#define chipModel_GC6400					0x00006400
+#define RGBA_BITS_R						0x00000001
+#define RGBA_BITS_G						0x00000002
+#define RGBA_BITS_B						0x00000004
+#define RGBA_BITS_A						0x00000008
+#define chipFeatures_FAST_CLEAR					0x00000001
+#define chipFeatures_SPECIAL_ANTI_ALIASING			0x00000002
+#define chipFeatures_PIPE_3D					0x00000004
+#define chipFeatures_DXT_TEXTURE_COMPRESSION			0x00000008
+#define chipFeatures_DEBUG_MODE					0x00000010
+#define chipFeatures_Z_COMPRESSION				0x00000020
+#define chipFeatures_YUV420_SCALER				0x00000040
+#define chipFeatures_MSAA					0x00000080
+#define chipFeatures_DC						0x00000100
+#define chipFeatures_PIPE_2D					0x00000200
+#define chipFeatures_ETC1_TEXTURE_COMPRESSION			0x00000400
+#define chipFeatures_FAST_SCALER				0x00000800
+#define chipFeatures_HIGH_DYNAMIC_RANGE				0x00001000
+#define chipFeatures_YUV420_TILER				0x00002000
+#define chipFeatures_MODULE_CG					0x00004000
+#define chipFeatures_MIN_AREA					0x00008000
+#define chipFeatures_NO_EARLY_Z					0x00010000
+#define chipFeatures_NO_422_TEXTURE				0x00020000
+#define chipFeatures_BUFFER_INTERLEAVING			0x00040000
+#define chipFeatures_BYTE_WRITE_2D				0x00080000
+#define chipFeatures_NO_SCALER					0x00100000
+#define chipFeatures_YUY2_AVERAGING				0x00200000
+#define chipFeatures_HALF_PE_CACHE				0x00400000
+#define chipFeatures_HALF_TX_CACHE				0x00800000
+#define chipFeatures_YUY2_RENDER_TARGET				0x01000000
+#define chipFeatures_MEM32					0x02000000
+#define chipFeatures_PIPE_VG					0x04000000
+#define chipFeatures_VGTS					0x08000000
+#define chipFeatures_FE20					0x10000000
+#define chipFeatures_BYTE_WRITE_3D				0x20000000
+#define chipFeatures_RS_YUV_TARGET				0x40000000
+#define chipFeatures_32_BIT_INDICES				0x80000000
+#define chipMinorFeatures0_FLIP_Y				0x00000001
+#define chipMinorFeatures0_DUAL_RETURN_BUS			0x00000002
+#define chipMinorFeatures0_ENDIANNESS_CONFIG			0x00000004
+#define chipMinorFeatures0_TEXTURE_8K				0x00000008
+#define chipMinorFeatures0_CORRECT_TEXTURE_CONVERTER		0x00000010
+#define chipMinorFeatures0_SPECIAL_MSAA_LOD			0x00000020
+#define chipMinorFeatures0_FAST_CLEAR_FLUSH			0x00000040
+#define chipMinorFeatures0_2DPE20				0x00000080
+#define chipMinorFeatures0_CORRECT_AUTO_DISABLE			0x00000100
+#define chipMinorFeatures0_RENDERTARGET_8K			0x00000200
+#define chipMinorFeatures0_2BITPERTILE				0x00000400
+#define chipMinorFeatures0_SEPARATE_TILE_STATUS_WHEN_INTERLEAVED	0x00000800
+#define chipMinorFeatures0_SUPER_TILED				0x00001000
+#define chipMinorFeatures0_VG_20				0x00002000
+#define chipMinorFeatures0_TS_EXTENDED_COMMANDS			0x00004000
+#define chipMinorFeatures0_COMPRESSION_FIFO_FIXED		0x00008000
+#define chipMinorFeatures0_HAS_SIGN_FLOOR_CEIL			0x00010000
+#define chipMinorFeatures0_VG_FILTER				0x00020000
+#define chipMinorFeatures0_VG_21				0x00040000
+#define chipMinorFeatures0_SHADER_HAS_W				0x00080000
+#define chipMinorFeatures0_HAS_SQRT_TRIG			0x00100000
+#define chipMinorFeatures0_MORE_MINOR_FEATURES			0x00200000
+#define chipMinorFeatures0_MC20					0x00400000
+#define chipMinorFeatures0_MSAA_SIDEBAND			0x00800000
+#define chipMinorFeatures0_BUG_FIXES0				0x01000000
+#define chipMinorFeatures0_VAA					0x02000000
+#define chipMinorFeatures0_BYPASS_IN_MSAA			0x04000000
+#define chipMinorFeatures0_HZ					0x08000000
+#define chipMinorFeatures0_NEW_TEXTURE				0x10000000
+#define chipMinorFeatures0_2D_A8_TARGET				0x20000000
+#define chipMinorFeatures0_CORRECT_STENCIL			0x40000000
+#define chipMinorFeatures0_ENHANCE_VR				0x80000000
+#define chipMinorFeatures1_RSUV_SWIZZLE				0x00000001
+#define chipMinorFeatures1_V2_COMPRESSION			0x00000002
+#define chipMinorFeatures1_VG_DOUBLE_BUFFER			0x00000004
+#define chipMinorFeatures1_EXTRA_EVENT_STATES			0x00000008
+#define chipMinorFeatures1_NO_STRIPING_NEEDED			0x00000010
+#define chipMinorFeatures1_TEXTURE_STRIDE			0x00000020
+#define chipMinorFeatures1_BUG_FIXES3				0x00000040
+#define chipMinorFeatures1_AUTO_DISABLE				0x00000080
+#define chipMinorFeatures1_AUTO_RESTART_TS			0x00000100
+#define chipMinorFeatures1_DISABLE_PE_GATING			0x00000200
+#define chipMinorFeatures1_L2_WINDOWING				0x00000400
+#define chipMinorFeatures1_HALF_FLOAT				0x00000800
+#define chipMinorFeatures1_PIXEL_DITHER				0x00001000
+#define chipMinorFeatures1_TWO_STENCIL_REFERENCE		0x00002000
+#define chipMinorFeatures1_EXTENDED_PIXEL_FORMAT		0x00004000
+#define chipMinorFeatures1_CORRECT_MIN_MAX_DEPTH		0x00008000
+#define chipMinorFeatures1_2D_DITHER				0x00010000
+#define chipMinorFeatures1_BUG_FIXES5				0x00020000
+#define chipMinorFeatures1_NEW_2D				0x00040000
+#define chipMinorFeatures1_NEW_FP				0x00080000
+#define chipMinorFeatures1_TEXTURE_HALIGN			0x00100000
+#define chipMinorFeatures1_NON_POWER_OF_TWO			0x00200000
+#define chipMinorFeatures1_LINEAR_TEXTURE_SUPPORT		0x00400000
+#define chipMinorFeatures1_HALTI0				0x00800000
+#define chipMinorFeatures1_CORRECT_OVERFLOW_VG			0x01000000
+#define chipMinorFeatures1_NEGATIVE_LOG_FIX			0x02000000
+#define chipMinorFeatures1_RESOLVE_OFFSET			0x04000000
+#define chipMinorFeatures1_OK_TO_GATE_AXI_CLOCK			0x08000000
+#define chipMinorFeatures1_MMU_VERSION				0x10000000
+#define chipMinorFeatures1_WIDE_LINE				0x20000000
+#define chipMinorFeatures1_BUG_FIXES6				0x40000000
+#define chipMinorFeatures1_FC_FLUSH_STALL			0x80000000
+#define chipMinorFeatures2_LINE_LOOP				0x00000001
+#define chipMinorFeatures2_LOGIC_OP				0x00000002
+#define chipMinorFeatures2_SEAMLESS_CUBE_MAP			0x00000004
+#define chipMinorFeatures2_SUPERTILED_TEXTURE			0x00000008
+#define chipMinorFeatures2_LINEAR_PE				0x00000010
+#define chipMinorFeatures2_RECT_PRIMITIVE			0x00000020
+#define chipMinorFeatures2_COMPOSITION				0x00000040
+#define chipMinorFeatures2_CORRECT_AUTO_DISABLE_COUNT		0x00000080
+#define chipMinorFeatures2_PE_SWIZZLE				0x00000100
+#define chipMinorFeatures2_END_EVENT				0x00000200
+#define chipMinorFeatures2_S1S8					0x00000400
+#define chipMinorFeatures2_HALTI1				0x00000800
+#define chipMinorFeatures2_RGB888				0x00001000
+#define chipMinorFeatures2_TX__YUV_ASSEMBLER			0x00002000
+#define chipMinorFeatures2_DYNAMIC_FREQUENCY_SCALING		0x00004000
+#define chipMinorFeatures2_EXTRA_TEXTURE_STATE			0x00008000
+#define chipMinorFeatures2_FULL_DIRECTFB			0x00010000
+#define chipMinorFeatures2_2D_TILING				0x00020000
+#define chipMinorFeatures2_THREAD_WALKER_IN_PS			0x00040000
+#define chipMinorFeatures2_TILE_FILLER				0x00080000
+#define chipMinorFeatures2_YUV_STANDARD				0x00100000
+#define chipMinorFeatures2_2D_MULTI_SOURCE_BLIT			0x00200000
+#define chipMinorFeatures2_YUV_CONVERSION			0x00400000
+#define chipMinorFeatures2_FLUSH_FIXED_2D			0x00800000
+#define chipMinorFeatures2_INTERLEAVER				0x01000000
+#define chipMinorFeatures2_MIXED_STREAMS			0x02000000
+#define chipMinorFeatures2_2D_420_L2CACHE			0x04000000
+#define chipMinorFeatures2_BUG_FIXES7				0x08000000
+#define chipMinorFeatures2_2D_NO_INDEX8_BRUSH			0x10000000
+#define chipMinorFeatures2_TEXTURE_TILED_READ			0x20000000
+#define chipMinorFeatures2_DECOMPRESS_Z16			0x40000000
+#define chipMinorFeatures2_BUG_FIXES8				0x80000000
+#define chipMinorFeatures3_ROTATION_STALL_FIX			0x00000001
+#define chipMinorFeatures3_OCL_ONLY				0x00000002
+#define chipMinorFeatures3_2D_MULTI_SOURCE_BLT_EX		0x00000004
+#define chipMinorFeatures3_INSTRUCTION_CACHE			0x00000008
+#define chipMinorFeatures3_GEOMETRY_SHADER			0x00000010
+#define chipMinorFeatures3_TEX_COMPRESSION_SUPERTILED		0x00000020
+#define chipMinorFeatures3_GENERICS				0x00000040
+#define chipMinorFeatures3_BUG_FIXES9				0x00000080
+#define chipMinorFeatures3_FAST_MSAA				0x00000100
+#define chipMinorFeatures3_WCLIP				0x00000200
+#define chipMinorFeatures3_BUG_FIXES10				0x00000400
+#define chipMinorFeatures3_UNIFIED_SAMPLERS			0x00000800
+#define chipMinorFeatures3_BUG_FIXES11				0x00001000
+#define chipMinorFeatures3_PERFORMANCE_COUNTERS			0x00002000
+#define chipMinorFeatures3_HAS_FAST_TRANSCENDENTALS		0x00004000
+#define chipMinorFeatures3_BUG_FIXES12				0x00008000
+#define chipMinorFeatures3_BUG_FIXES13				0x00010000
+#define chipMinorFeatures3_DE_ENHANCEMENTS1			0x00020000
+#define chipMinorFeatures3_ACE					0x00040000
+#define chipMinorFeatures3_TX_ENHANCEMENTS1			0x00080000
+#define chipMinorFeatures3_SH_ENHANCEMENTS1			0x00100000
+#define chipMinorFeatures3_SH_ENHANCEMENTS2			0x00200000
+#define chipMinorFeatures3_UNK22				0x00400000
+#define chipMinorFeatures3_2D_FC_SOURCE				0x00800000
+#define chipMinorFeatures3_UNK24				0x01000000
+#define chipMinorFeatures3_UNK25				0x02000000
+#define chipMinorFeatures3_NEW_HZ				0x04000000
+#define chipMinorFeatures3_UNK27				0x08000000
+#define chipMinorFeatures3_UNK28				0x10000000
+#define chipMinorFeatures3_SH_ENHANCEMENTS3			0x20000000
+#define chipMinorFeatures3_UNK30				0x40000000
+#define chipMinorFeatures3_UNK31				0x80000000
+#define chipMinorFeatures4_UNK0					0x00000001
+#define chipMinorFeatures4_PE_ENHANCEMENTS2			0x00000002
+#define chipMinorFeatures4_FRUSTUM_CLIP_FIX			0x00000004
+#define chipMinorFeatures4_UNK3					0x00000008
+#define chipMinorFeatures4_UNK4					0x00000010
+#define chipMinorFeatures4_2D_GAMMA				0x00000020
+#define chipMinorFeatures4_SINGLE_BUFFER			0x00000040
+#define chipMinorFeatures4_UNK7					0x00000080
+#define chipMinorFeatures4_UNK8					0x00000100
+#define chipMinorFeatures4_UNK9					0x00000200
+#define chipMinorFeatures4_UNK10				0x00000400
+#define chipMinorFeatures4_TX_LERP_PRECISION_FIX		0x00000800
+#define chipMinorFeatures4_2D_COLOR_SPACE_CONVERSION		0x00001000
+#define chipMinorFeatures4_TEXTURE_ASTC				0x00002000
+#define chipMinorFeatures4_UNK14				0x00004000
+#define chipMinorFeatures4_UNK15				0x00008000
+#define chipMinorFeatures4_HALTI2				0x00010000
+#define chipMinorFeatures4_UNK17				0x00020000
+#define chipMinorFeatures4_SMALL_MSAA				0x00040000
+#define chipMinorFeatures4_UNK19				0x00080000
+#define chipMinorFeatures4_NEW_RA				0x00100000
+#define chipMinorFeatures4_2D_OPF_YUV_OUTPUT			0x00200000
+#define chipMinorFeatures4_2D_MULTI_SOURCE_BLT_EX2		0x00400000
+#define chipMinorFeatures4_NO_USER_CSC				0x00800000
+#define chipMinorFeatures4_ZFIXES				0x01000000
+#define chipMinorFeatures4_BUG_FIXES18				0x02000000
+#define chipMinorFeatures4_2D_COMPRESSION			0x04000000
+#define chipMinorFeatures4_PROBE				0x08000000
+#define chipMinorFeatures4_UNK28				0x10000000
+#define chipMinorFeatures4_2D_SUPER_TILE_VERSION		0x20000000
+#define chipMinorFeatures4_UNK30				0x40000000
+#define chipMinorFeatures4_UNK31				0x80000000
+#define chipMinorFeatures5_UNK0					0x00000001
+#define chipMinorFeatures5_UNK1					0x00000002
+#define chipMinorFeatures5_UNK2					0x00000004
+#define chipMinorFeatures5_UNK3					0x00000008
+#define chipMinorFeatures5_EEZ					0x00000010
+#define chipMinorFeatures5_UNK5					0x00000020
+#define chipMinorFeatures5_UNK6					0x00000040
+#define chipMinorFeatures5_UNK7					0x00000080
+#define chipMinorFeatures5_UNK8					0x00000100
+#define chipMinorFeatures5_HALTI3				0x00000200
+#define chipMinorFeatures5_UNK10				0x00000400
+#define chipMinorFeatures5_2D_ONE_PASS_FILTER_TAP		0x00000800
+#define chipMinorFeatures5_UNK12				0x00001000
+#define chipMinorFeatures5_SEPARATE_SRC_DST			0x00002000
+#define chipMinorFeatures5_HALTI4				0x00004000
+#define chipMinorFeatures5_UNK15				0x00008000
+#define chipMinorFeatures5_ANDROID_ONLY				0x00010000
+#define chipMinorFeatures5_HAS_PRODUCTID			0x00020000
+#define chipMinorFeatures5_UNK18				0x00040000
+#define chipMinorFeatures5_UNK19				0x00080000
+#define chipMinorFeatures5_PE_DITHER_FIX2			0x00100000
+#define chipMinorFeatures5_UNK21				0x00200000
+#define chipMinorFeatures5_UNK22				0x00400000
+#define chipMinorFeatures5_UNK23				0x00800000
+#define chipMinorFeatures5_UNK24				0x01000000
+#define chipMinorFeatures5_UNK25				0x02000000
+#define chipMinorFeatures5_UNK26				0x04000000
+#define chipMinorFeatures5_RS_DEPTHSTENCIL_NATIVE_SUPPORT	0x08000000
+#define chipMinorFeatures5_V2_MSAA_COMP_FIX			0x10000000
+#define chipMinorFeatures5_UNK29				0x20000000
+#define chipMinorFeatures5_UNK30				0x40000000
+#define chipMinorFeatures5_UNK31				0x80000000
+
+#endif /* COMMON_XML */
diff --git a/src/gallium/drivers/etnaviv/hw/isa.xml.h b/src/gallium/drivers/etnaviv/hw/isa.xml.h
new file mode 100644
index 0000000..70cc74a
--- /dev/null
+++ b/src/gallium/drivers/etnaviv/hw/isa.xml.h
@@ -0,0 +1,239 @@
+#ifndef ISA_XML
+#define ISA_XML
+
+/* Autogenerated file, DO NOT EDIT manually!
+
+This file was generated by the rules-ng-ng headergen tool in this git repository:
+http://0x04.net/cgit/index.cgi/rules-ng-ng
+git clone git://0x04.net/rules-ng-ng
+
+The rules-ng-ng source files this header was generated from are:
+- isa.xml       (  24392 bytes, from 2016-11-16 18:54:37)
+- copyright.xml (   1597 bytes, from 2016-10-02 14:26:13)
+
+Copyright (C) 2012-2016 by the following authors:
+- Wladimir J. van der Laan <laanwj at gmail.com>
+- Christian Gmeiner <christian.gmeiner at gmail.com>
+- Lucas Stach <l.stach at pengutronix.de>
+- Russell King <rmk at arm.linux.org.uk>
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sub license,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice (including the
+next paragraph) shall be included in all copies or substantial portions
+of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+*/
+
+
+#define INST_OPCODE_NOP						0x00000000
+#define INST_OPCODE_ADD						0x00000001
+#define INST_OPCODE_MAD						0x00000002
+#define INST_OPCODE_MUL						0x00000003
+#define INST_OPCODE_DST						0x00000004
+#define INST_OPCODE_DP3						0x00000005
+#define INST_OPCODE_DP4						0x00000006
+#define INST_OPCODE_DSX						0x00000007
+#define INST_OPCODE_DSY						0x00000008
+#define INST_OPCODE_MOV						0x00000009
+#define INST_OPCODE_MOVAR					0x0000000a
+#define INST_OPCODE_MOVAF					0x0000000b
+#define INST_OPCODE_RCP						0x0000000c
+#define INST_OPCODE_RSQ						0x0000000d
+#define INST_OPCODE_LITP					0x0000000e
+#define INST_OPCODE_SELECT					0x0000000f
+#define INST_OPCODE_SET						0x00000010
+#define INST_OPCODE_EXP						0x00000011
+#define INST_OPCODE_LOG						0x00000012
+#define INST_OPCODE_FRC						0x00000013
+#define INST_OPCODE_CALL					0x00000014
+#define INST_OPCODE_RET						0x00000015
+#define INST_OPCODE_BRANCH					0x00000016
+#define INST_OPCODE_TEXKILL					0x00000017
+#define INST_OPCODE_TEXLD					0x00000018
+#define INST_OPCODE_TEXLDB					0x00000019
+#define INST_OPCODE_TEXLDD					0x0000001a
+#define INST_OPCODE_TEXLDL					0x0000001b
+#define INST_OPCODE_TEXLDPCF					0x0000001c
+#define INST_OPCODE_REP						0x0000001d
+#define INST_OPCODE_ENDREP					0x0000001e
+#define INST_OPCODE_LOOP					0x0000001f
+#define INST_OPCODE_ENDLOOP					0x00000020
+#define INST_OPCODE_SQRT					0x00000021
+#define INST_OPCODE_SIN						0x00000022
+#define INST_OPCODE_COS						0x00000023
+#define INST_OPCODE_FLOOR					0x00000025
+#define INST_OPCODE_CEIL					0x00000026
+#define INST_OPCODE_SIGN					0x00000027
+#define INST_OPCODE_I2F						0x0000002d
+#define INST_OPCODE_CMP						0x00000031
+#define INST_OPCODE_LOAD					0x00000032
+#define INST_OPCODE_STORE					0x00000033
+#define INST_OPCODE_IMULLO0					0x0000003c
+#define INST_OPCODE_IMULHI0					0x00000040
+#define INST_OPCODE_IMADLO0					0x0000004c
+#define INST_OPCODE_LEADZERO					0x00000058
+#define INST_OPCODE_LSHIFT					0x00000059
+#define INST_OPCODE_RSHIFT					0x0000005a
+#define INST_OPCODE_ROTATE					0x0000005b
+#define INST_OPCODE_OR						0x0000005c
+#define INST_OPCODE_AND						0x0000005d
+#define INST_OPCODE_XOR						0x0000005e
+#define INST_OPCODE_NOT						0x0000005f
+#define INST_CONDITION_TRUE					0x00000000
+#define INST_CONDITION_GT					0x00000001
+#define INST_CONDITION_LT					0x00000002
+#define INST_CONDITION_GE					0x00000003
+#define INST_CONDITION_LE					0x00000004
+#define INST_CONDITION_EQ					0x00000005
+#define INST_CONDITION_NE					0x00000006
+#define INST_CONDITION_AND					0x00000007
+#define INST_CONDITION_OR					0x00000008
+#define INST_CONDITION_XOR					0x00000009
+#define INST_CONDITION_NOT					0x0000000a
+#define INST_CONDITION_NZ					0x0000000b
+#define INST_CONDITION_GEZ					0x0000000c
+#define INST_CONDITION_GZ					0x0000000d
+#define INST_CONDITION_LEZ					0x0000000e
+#define INST_CONDITION_LZ					0x0000000f
+#define INST_RGROUP_TEMP					0x00000000
+#define INST_RGROUP_INTERNAL					0x00000001
+#define INST_RGROUP_UNIFORM_0					0x00000002
+#define INST_RGROUP_UNIFORM_1					0x00000003
+#define INST_AMODE_DIRECT					0x00000000
+#define INST_AMODE_ADD_A_X					0x00000001
+#define INST_AMODE_ADD_A_Y					0x00000002
+#define INST_AMODE_ADD_A_Z					0x00000003
+#define INST_AMODE_ADD_A_W					0x00000004
+#define INST_SWIZ_COMP_X					0x00000000
+#define INST_SWIZ_COMP_Y					0x00000001
+#define INST_SWIZ_COMP_Z					0x00000002
+#define INST_SWIZ_COMP_W					0x00000003
+#define INST_TYPE_F32						0x00000000
+#define INST_TYPE_S32						0x00000001
+#define INST_TYPE_S8						0x00000002
+#define INST_TYPE_U16						0x00000003
+#define INST_TYPE_F16						0x00000004
+#define INST_TYPE_S16						0x00000005
+#define INST_TYPE_U32						0x00000006
+#define INST_TYPE_U8						0x00000007
+#define INST_COMPS_X						0x00000001
+#define INST_COMPS_Y						0x00000002
+#define INST_COMPS_Z						0x00000004
+#define INST_COMPS_W						0x00000008
+#define INST_SWIZ_X__MASK					0x00000003
+#define INST_SWIZ_X__SHIFT					0
+#define INST_SWIZ_X(x)						(((x) << INST_SWIZ_X__SHIFT) & INST_SWIZ_X__MASK)
+#define INST_SWIZ_Y__MASK					0x0000000c
+#define INST_SWIZ_Y__SHIFT					2
+#define INST_SWIZ_Y(x)						(((x) << INST_SWIZ_Y__SHIFT) & INST_SWIZ_Y__MASK)
+#define INST_SWIZ_Z__MASK					0x00000030
+#define INST_SWIZ_Z__SHIFT					4
+#define INST_SWIZ_Z(x)						(((x) << INST_SWIZ_Z__SHIFT) & INST_SWIZ_Z__MASK)
+#define INST_SWIZ_W__MASK					0x000000c0
+#define INST_SWIZ_W__SHIFT					6
+#define INST_SWIZ_W(x)						(((x) << INST_SWIZ_W__SHIFT) & INST_SWIZ_W__MASK)
+#define VIV_ISA_WORD_0						0x00000000
+#define VIV_ISA_WORD_0_OPCODE__MASK				0x0000003f
+#define VIV_ISA_WORD_0_OPCODE__SHIFT				0
+#define VIV_ISA_WORD_0_OPCODE(x)				(((x) << VIV_ISA_WORD_0_OPCODE__SHIFT) & VIV_ISA_WORD_0_OPCODE__MASK)
+#define VIV_ISA_WORD_0_COND__MASK				0x000007c0
+#define VIV_ISA_WORD_0_COND__SHIFT				6
+#define VIV_ISA_WORD_0_COND(x)					(((x) << VIV_ISA_WORD_0_COND__SHIFT) & VIV_ISA_WORD_0_COND__MASK)
+#define VIV_ISA_WORD_0_SAT					0x00000800
+#define VIV_ISA_WORD_0_DST_USE					0x00001000
+#define VIV_ISA_WORD_0_DST_AMODE__MASK				0x0000e000
+#define VIV_ISA_WORD_0_DST_AMODE__SHIFT				13
+#define VIV_ISA_WORD_0_DST_AMODE(x)				(((x) << VIV_ISA_WORD_0_DST_AMODE__SHIFT) & VIV_ISA_WORD_0_DST_AMODE__MASK)
+#define VIV_ISA_WORD_0_DST_REG__MASK				0x007f0000
+#define VIV_ISA_WORD_0_DST_REG__SHIFT				16
+#define VIV_ISA_WORD_0_DST_REG(x)				(((x) << VIV_ISA_WORD_0_DST_REG__SHIFT) & VIV_ISA_WORD_0_DST_REG__MASK)
+#define VIV_ISA_WORD_0_DST_COMPS__MASK				0x07800000
+#define VIV_ISA_WORD_0_DST_COMPS__SHIFT				23
+#define VIV_ISA_WORD_0_DST_COMPS(x)				(((x) << VIV_ISA_WORD_0_DST_COMPS__SHIFT) & VIV_ISA_WORD_0_DST_COMPS__MASK)
+#define VIV_ISA_WORD_0_TEX_ID__MASK				0xf8000000
+#define VIV_ISA_WORD_0_TEX_ID__SHIFT				27
+#define VIV_ISA_WORD_0_TEX_ID(x)				(((x) << VIV_ISA_WORD_0_TEX_ID__SHIFT) & VIV_ISA_WORD_0_TEX_ID__MASK)
+
+#define VIV_ISA_WORD_1						0x00000004
+#define VIV_ISA_WORD_1_TEX_AMODE__MASK				0x00000007
+#define VIV_ISA_WORD_1_TEX_AMODE__SHIFT				0
+#define VIV_ISA_WORD_1_TEX_AMODE(x)				(((x) << VIV_ISA_WORD_1_TEX_AMODE__SHIFT) & VIV_ISA_WORD_1_TEX_AMODE__MASK)
+#define VIV_ISA_WORD_1_TEX_SWIZ__MASK				0x000007f8
+#define VIV_ISA_WORD_1_TEX_SWIZ__SHIFT				3
+#define VIV_ISA_WORD_1_TEX_SWIZ(x)				(((x) << VIV_ISA_WORD_1_TEX_SWIZ__SHIFT) & VIV_ISA_WORD_1_TEX_SWIZ__MASK)
+#define VIV_ISA_WORD_1_SRC0_USE					0x00000800
+#define VIV_ISA_WORD_1_SRC0_REG__MASK				0x001ff000
+#define VIV_ISA_WORD_1_SRC0_REG__SHIFT				12
+#define VIV_ISA_WORD_1_SRC0_REG(x)				(((x) << VIV_ISA_WORD_1_SRC0_REG__SHIFT) & VIV_ISA_WORD_1_SRC0_REG__MASK)
+#define VIV_ISA_WORD_1_TYPE_BIT2				0x00200000
+#define VIV_ISA_WORD_1_SRC0_SWIZ__MASK				0x3fc00000
+#define VIV_ISA_WORD_1_SRC0_SWIZ__SHIFT				22
+#define VIV_ISA_WORD_1_SRC0_SWIZ(x)				(((x) << VIV_ISA_WORD_1_SRC0_SWIZ__SHIFT) & VIV_ISA_WORD_1_SRC0_SWIZ__MASK)
+#define VIV_ISA_WORD_1_SRC0_NEG					0x40000000
+#define VIV_ISA_WORD_1_SRC0_ABS					0x80000000
+
+#define VIV_ISA_WORD_2						0x00000008
+#define VIV_ISA_WORD_2_SRC0_AMODE__MASK				0x00000007
+#define VIV_ISA_WORD_2_SRC0_AMODE__SHIFT			0
+#define VIV_ISA_WORD_2_SRC0_AMODE(x)				(((x) << VIV_ISA_WORD_2_SRC0_AMODE__SHIFT) & VIV_ISA_WORD_2_SRC0_AMODE__MASK)
+#define VIV_ISA_WORD_2_SRC0_RGROUP__MASK			0x00000038
+#define VIV_ISA_WORD_2_SRC0_RGROUP__SHIFT			3
+#define VIV_ISA_WORD_2_SRC0_RGROUP(x)				(((x) << VIV_ISA_WORD_2_SRC0_RGROUP__SHIFT) & VIV_ISA_WORD_2_SRC0_RGROUP__MASK)
+#define VIV_ISA_WORD_2_SRC1_USE					0x00000040
+#define VIV_ISA_WORD_2_SRC1_REG__MASK				0x0000ff80
+#define VIV_ISA_WORD_2_SRC1_REG__SHIFT				7
+#define VIV_ISA_WORD_2_SRC1_REG(x)				(((x) << VIV_ISA_WORD_2_SRC1_REG__SHIFT) & VIV_ISA_WORD_2_SRC1_REG__MASK)
+#define VIV_ISA_WORD_2_OPCODE_BIT6				0x00010000
+#define VIV_ISA_WORD_2_SRC1_SWIZ__MASK				0x01fe0000
+#define VIV_ISA_WORD_2_SRC1_SWIZ__SHIFT				17
+#define VIV_ISA_WORD_2_SRC1_SWIZ(x)				(((x) << VIV_ISA_WORD_2_SRC1_SWIZ__SHIFT) & VIV_ISA_WORD_2_SRC1_SWIZ__MASK)
+#define VIV_ISA_WORD_2_SRC1_NEG					0x02000000
+#define VIV_ISA_WORD_2_SRC1_ABS					0x04000000
+#define VIV_ISA_WORD_2_SRC1_AMODE__MASK				0x38000000
+#define VIV_ISA_WORD_2_SRC1_AMODE__SHIFT			27
+#define VIV_ISA_WORD_2_SRC1_AMODE(x)				(((x) << VIV_ISA_WORD_2_SRC1_AMODE__SHIFT) & VIV_ISA_WORD_2_SRC1_AMODE__MASK)
+#define VIV_ISA_WORD_2_TYPE_BIT01__MASK				0xc0000000
+#define VIV_ISA_WORD_2_TYPE_BIT01__SHIFT			30
+#define VIV_ISA_WORD_2_TYPE_BIT01(x)				(((x) << VIV_ISA_WORD_2_TYPE_BIT01__SHIFT) & VIV_ISA_WORD_2_TYPE_BIT01__MASK)
+
+#define VIV_ISA_WORD_3						0x0000000c
+#define VIV_ISA_WORD_3_SRC1_RGROUP__MASK			0x00000007
+#define VIV_ISA_WORD_3_SRC1_RGROUP__SHIFT			0
+#define VIV_ISA_WORD_3_SRC1_RGROUP(x)				(((x) << VIV_ISA_WORD_3_SRC1_RGROUP__SHIFT) & VIV_ISA_WORD_3_SRC1_RGROUP__MASK)
+#define VIV_ISA_WORD_3_SRC2_IMM__MASK				0x003fff80
+#define VIV_ISA_WORD_3_SRC2_IMM__SHIFT				7
+#define VIV_ISA_WORD_3_SRC2_IMM(x)				(((x) << VIV_ISA_WORD_3_SRC2_IMM__SHIFT) & VIV_ISA_WORD_3_SRC2_IMM__MASK)
+#define VIV_ISA_WORD_3_SRC2_USE					0x00000008
+#define VIV_ISA_WORD_3_SRC2_REG__MASK				0x00001ff0
+#define VIV_ISA_WORD_3_SRC2_REG__SHIFT				4
+#define VIV_ISA_WORD_3_SRC2_REG(x)				(((x) << VIV_ISA_WORD_3_SRC2_REG__SHIFT) & VIV_ISA_WORD_3_SRC2_REG__MASK)
+#define VIV_ISA_WORD_3_UNK3_13					0x00002000
+#define VIV_ISA_WORD_3_SRC2_SWIZ__MASK				0x003fc000
+#define VIV_ISA_WORD_3_SRC2_SWIZ__SHIFT				14
+#define VIV_ISA_WORD_3_SRC2_SWIZ(x)				(((x) << VIV_ISA_WORD_3_SRC2_SWIZ__SHIFT) & VIV_ISA_WORD_3_SRC2_SWIZ__MASK)
+#define VIV_ISA_WORD_3_SRC2_NEG					0x00400000
+#define VIV_ISA_WORD_3_SRC2_ABS					0x00800000
+#define VIV_ISA_WORD_3_UNK3_24					0x01000000
+#define VIV_ISA_WORD_3_SRC2_AMODE__MASK				0x0e000000
+#define VIV_ISA_WORD_3_SRC2_AMODE__SHIFT			25
+#define VIV_ISA_WORD_3_SRC2_AMODE(x)				(((x) << VIV_ISA_WORD_3_SRC2_AMODE__SHIFT) & VIV_ISA_WORD_3_SRC2_AMODE__MASK)
+#define VIV_ISA_WORD_3_SRC2_RGROUP__MASK			0x70000000
+#define VIV_ISA_WORD_3_SRC2_RGROUP__SHIFT			28
+#define VIV_ISA_WORD_3_SRC2_RGROUP(x)				(((x) << VIV_ISA_WORD_3_SRC2_RGROUP__SHIFT) & VIV_ISA_WORD_3_SRC2_RGROUP__MASK)
+#define VIV_ISA_WORD_3_UNK3_31					0x80000000
+
+
+#endif /* ISA_XML */
diff --git a/src/gallium/drivers/etnaviv/hw/state.xml.h b/src/gallium/drivers/etnaviv/hw/state.xml.h
new file mode 100644
index 0000000..d9bb9c4
--- /dev/null
+++ b/src/gallium/drivers/etnaviv/hw/state.xml.h
@@ -0,0 +1,397 @@
+#ifndef STATE_XML
+#define STATE_XML
+
+/* Autogenerated file, DO NOT EDIT manually!
+
+This file was generated by the rules-ng-ng headergen tool in this git repository:
+http://0x04.net/cgit/index.cgi/rules-ng-ng
+git clone git://0x04.net/rules-ng-ng
+
+The rules-ng-ng source files this header was generated from are:
+- state.xml     (  19792 bytes, from 2016-11-16 18:54:37)
+- common.xml    (  23422 bytes, from 2016-11-16 18:54:37)
+- state_hi.xml  (  25653 bytes, from 2016-10-02 14:26:13)
+- copyright.xml (   1597 bytes, from 2016-10-02 14:26:13)
+- state_2d.xml  (  51552 bytes, from 2016-10-02 14:26:13)
+- state_3d.xml  (  57579 bytes, from 2016-11-16 18:54:37)
+- state_vg.xml  (   5975 bytes, from 2016-10-02 14:26:13)
+
+Copyright (C) 2012-2016 by the following authors:
+- Wladimir J. van der Laan <laanwj at gmail.com>
+- Christian Gmeiner <christian.gmeiner at gmail.com>
+- Lucas Stach <l.stach at pengutronix.de>
+- Russell King <rmk at arm.linux.org.uk>
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sub license,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice (including the
+next paragraph) shall be included in all copies or substantial portions
+of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+*/
+
+
+#define VARYING_COMPONENT_USE_UNUSED				0x00000000
+#define VARYING_COMPONENT_USE_USED				0x00000001
+#define VARYING_COMPONENT_USE_POINTCOORD_X			0x00000002
+#define VARYING_COMPONENT_USE_POINTCOORD_Y			0x00000003
+#define FE_VERTEX_STREAM_CONTROL_VERTEX_STRIDE__MASK		0x000000ff
+#define FE_VERTEX_STREAM_CONTROL_VERTEX_STRIDE__SHIFT		0
+#define FE_VERTEX_STREAM_CONTROL_VERTEX_STRIDE(x)		(((x) << FE_VERTEX_STREAM_CONTROL_VERTEX_STRIDE__SHIFT) & FE_VERTEX_STREAM_CONTROL_VERTEX_STRIDE__MASK)
+#define FE_VERTEX_STREAM_CONTROL_VERTEX_DIVISOR__MASK		0x00ff0000
+#define FE_VERTEX_STREAM_CONTROL_VERTEX_DIVISOR__SHIFT		16
+#define FE_VERTEX_STREAM_CONTROL_VERTEX_DIVISOR(x)		(((x) << FE_VERTEX_STREAM_CONTROL_VERTEX_DIVISOR__SHIFT) & FE_VERTEX_STREAM_CONTROL_VERTEX_DIVISOR__MASK)
+#define VIVS_FE							0x00000000
+
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG(i0)		       (0x00000600 + 0x4*(i0))
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG__ESIZE			0x00000004
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG__LEN			0x00000010
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE__MASK		0x0000000f
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE__SHIFT		0
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE_BYTE			0x00000000
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE_UNSIGNED_BYTE	0x00000001
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE_SHORT		0x00000002
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE_UNSIGNED_SHORT	0x00000003
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE_INT			0x00000004
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE_UNSIGNED_INT		0x00000005
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE_FLOAT		0x00000008
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE_HALF_FLOAT		0x00000009
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE_FIXED		0x0000000b
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE_INT_10_10_10_2	0x0000000c
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE_UNSIGNED_INT_10_10_10_2	0x0000000d
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_ENDIAN__MASK		0x00000030
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_ENDIAN__SHIFT		4
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_ENDIAN(x)			(((x) << VIVS_FE_VERTEX_ELEMENT_CONFIG_ENDIAN__SHIFT) & VIVS_FE_VERTEX_ELEMENT_CONFIG_ENDIAN__MASK)
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_NONCONSECUTIVE		0x00000080
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_STREAM__MASK		0x00000700
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_STREAM__SHIFT		8
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_STREAM(x)			(((x) << VIVS_FE_VERTEX_ELEMENT_CONFIG_STREAM__SHIFT) & VIVS_FE_VERTEX_ELEMENT_CONFIG_STREAM__MASK)
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_NUM__MASK			0x00003000
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_NUM__SHIFT		12
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_NUM(x)			(((x) << VIVS_FE_VERTEX_ELEMENT_CONFIG_NUM__SHIFT) & VIVS_FE_VERTEX_ELEMENT_CONFIG_NUM__MASK)
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_NORMALIZE__MASK		0x0000c000
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_NORMALIZE__SHIFT		14
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_NORMALIZE_OFF		0x00000000
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_NORMALIZE_ON		0x00008000
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_START__MASK		0x00ff0000
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_START__SHIFT		16
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_START(x)			(((x) << VIVS_FE_VERTEX_ELEMENT_CONFIG_START__SHIFT) & VIVS_FE_VERTEX_ELEMENT_CONFIG_START__MASK)
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_END__MASK			0xff000000
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_END__SHIFT		24
+#define VIVS_FE_VERTEX_ELEMENT_CONFIG_END(x)			(((x) << VIVS_FE_VERTEX_ELEMENT_CONFIG_END__SHIFT) & VIVS_FE_VERTEX_ELEMENT_CONFIG_END__MASK)
+
+#define VIVS_FE_CMD_STREAM_BASE_ADDR				0x00000640
+
+#define VIVS_FE_INDEX_STREAM_BASE_ADDR				0x00000644
+
+#define VIVS_FE_INDEX_STREAM_CONTROL				0x00000648
+#define VIVS_FE_INDEX_STREAM_CONTROL_TYPE__MASK			0x00000003
+#define VIVS_FE_INDEX_STREAM_CONTROL_TYPE__SHIFT		0
+#define VIVS_FE_INDEX_STREAM_CONTROL_TYPE_UNSIGNED_CHAR		0x00000000
+#define VIVS_FE_INDEX_STREAM_CONTROL_TYPE_UNSIGNED_SHORT	0x00000001
+#define VIVS_FE_INDEX_STREAM_CONTROL_TYPE_UNSIGNED_INT		0x00000002
+#define VIVS_FE_INDEX_STREAM_CONTROL_PRIMITIVE_RESTART		0x00000100
+
+#define VIVS_FE_VERTEX_STREAM_BASE_ADDR				0x0000064c
+
+#define VIVS_FE_VERTEX_STREAM_CONTROL				0x00000650
+
+#define VIVS_FE_COMMAND_ADDRESS					0x00000654
+
+#define VIVS_FE_COMMAND_CONTROL					0x00000658
+#define VIVS_FE_COMMAND_CONTROL_PREFETCH__MASK			0x0000ffff
+#define VIVS_FE_COMMAND_CONTROL_PREFETCH__SHIFT			0
+#define VIVS_FE_COMMAND_CONTROL_PREFETCH(x)			(((x) << VIVS_FE_COMMAND_CONTROL_PREFETCH__SHIFT) & VIVS_FE_COMMAND_CONTROL_PREFETCH__MASK)
+#define VIVS_FE_COMMAND_CONTROL_ENABLE				0x00010000
+
+#define VIVS_FE_DMA_STATUS					0x0000065c
+
+#define VIVS_FE_DMA_DEBUG_STATE					0x00000660
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE__MASK			0x0000001f
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE__SHIFT		0
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_IDLE			0x00000000
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_DEC			0x00000001
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_ADR0			0x00000002
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_LOAD0			0x00000003
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_ADR1			0x00000004
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_LOAD1			0x00000005
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_3DADR			0x00000006
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_3DCMD			0x00000007
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_3DCNTL		0x00000008
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_3DIDXCNTL		0x00000009
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_INITREQDMA		0x0000000a
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_DRAWIDX		0x0000000b
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_DRAW			0x0000000c
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_2DRECT0		0x0000000d
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_2DRECT1		0x0000000e
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_2DDATA0		0x0000000f
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_2DDATA1		0x00000010
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_WAITFIFO		0x00000011
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_WAIT			0x00000012
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_LINK			0x00000013
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_END			0x00000014
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_STALL			0x00000015
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_DMA_STATE__MASK		0x00000300
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_DMA_STATE__SHIFT		8
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_DMA_STATE_IDLE		0x00000000
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_DMA_STATE_START		0x00000100
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_DMA_STATE_REQ		0x00000200
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_DMA_STATE_END		0x00000300
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_FETCH_STATE__MASK		0x00000c00
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_FETCH_STATE__SHIFT		10
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_FETCH_STATE_IDLE		0x00000000
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_FETCH_STATE_RAMVALID	0x00000400
+#define VIVS_FE_DMA_DEBUG_STATE_CMD_FETCH_STATE_VALID		0x00000800
+#define VIVS_FE_DMA_DEBUG_STATE_REQ_DMA_STATE__MASK		0x00003000
+#define VIVS_FE_DMA_DEBUG_STATE_REQ_DMA_STATE__SHIFT		12
+#define VIVS_FE_DMA_DEBUG_STATE_REQ_DMA_STATE_IDLE		0x00000000
+#define VIVS_FE_DMA_DEBUG_STATE_REQ_DMA_STATE_WAITIDX		0x00001000
+#define VIVS_FE_DMA_DEBUG_STATE_REQ_DMA_STATE_CAL		0x00002000
+#define VIVS_FE_DMA_DEBUG_STATE_CAL_STATE__MASK			0x0000c000
+#define VIVS_FE_DMA_DEBUG_STATE_CAL_STATE__SHIFT		14
+#define VIVS_FE_DMA_DEBUG_STATE_CAL_STATE_IDLE			0x00000000
+#define VIVS_FE_DMA_DEBUG_STATE_CAL_STATE_LDADR			0x00004000
+#define VIVS_FE_DMA_DEBUG_STATE_CAL_STATE_IDXCALC		0x00008000
+#define VIVS_FE_DMA_DEBUG_STATE_VE_REQ_STATE__MASK		0x00030000
+#define VIVS_FE_DMA_DEBUG_STATE_VE_REQ_STATE__SHIFT		16
+#define VIVS_FE_DMA_DEBUG_STATE_VE_REQ_STATE_IDLE		0x00000000
+#define VIVS_FE_DMA_DEBUG_STATE_VE_REQ_STATE_CKCACHE		0x00010000
+#define VIVS_FE_DMA_DEBUG_STATE_VE_REQ_STATE_MISS		0x00020000
+
+#define VIVS_FE_DMA_ADDRESS					0x00000664
+
+#define VIVS_FE_DMA_LOW						0x00000668
+
+#define VIVS_FE_DMA_HIGH					0x0000066c
+
+#define VIVS_FE_AUTO_FLUSH					0x00000670
+
+#define VIVS_FE_PRIMITIVE_RESTART_INDEX				0x00000674
+
+#define VIVS_FE_UNK00678					0x00000678
+
+#define VIVS_FE_UNK0067C					0x0000067c
+
+#define VIVS_FE_VERTEX_STREAMS(i0)			       (0x00000000 + 0x4*(i0))
+#define VIVS_FE_VERTEX_STREAMS__ESIZE				0x00000004
+#define VIVS_FE_VERTEX_STREAMS__LEN				0x00000008
+
+#define VIVS_FE_VERTEX_STREAMS_BASE_ADDR(i0)		       (0x00000680 + 0x4*(i0))
+
+#define VIVS_FE_VERTEX_STREAMS_CONTROL(i0)		       (0x000006a0 + 0x4*(i0))
+
+#define VIVS_FE_UNK00700(i0)				       (0x00000700 + 0x4*(i0))
+#define VIVS_FE_UNK00700__ESIZE					0x00000004
+#define VIVS_FE_UNK00700__LEN					0x00000010
+
+#define VIVS_FE_UNK00740(i0)				       (0x00000740 + 0x4*(i0))
+#define VIVS_FE_UNK00740__ESIZE					0x00000004
+#define VIVS_FE_UNK00740__LEN					0x00000010
+
+#define VIVS_FE_UNK00780(i0)				       (0x00000780 + 0x4*(i0))
+#define VIVS_FE_UNK00780__ESIZE					0x00000004
+#define VIVS_FE_UNK00780__LEN					0x00000010
+
+#define VIVS_GL							0x00000000
+
+#define VIVS_GL_PIPE_SELECT					0x00003800
+#define VIVS_GL_PIPE_SELECT_PIPE__MASK				0x00000001
+#define VIVS_GL_PIPE_SELECT_PIPE__SHIFT				0
+#define VIVS_GL_PIPE_SELECT_PIPE(x)				(((x) << VIVS_GL_PIPE_SELECT_PIPE__SHIFT) & VIVS_GL_PIPE_SELECT_PIPE__MASK)
+
+#define VIVS_GL_EVENT						0x00003804
+#define VIVS_GL_EVENT_EVENT_ID__MASK				0x0000001f
+#define VIVS_GL_EVENT_EVENT_ID__SHIFT				0
+#define VIVS_GL_EVENT_EVENT_ID(x)				(((x) << VIVS_GL_EVENT_EVENT_ID__SHIFT) & VIVS_GL_EVENT_EVENT_ID__MASK)
+#define VIVS_GL_EVENT_FROM_FE					0x00000020
+#define VIVS_GL_EVENT_FROM_PE					0x00000040
+#define VIVS_GL_EVENT_SOURCE__MASK				0x00001f00
+#define VIVS_GL_EVENT_SOURCE__SHIFT				8
+#define VIVS_GL_EVENT_SOURCE(x)					(((x) << VIVS_GL_EVENT_SOURCE__SHIFT) & VIVS_GL_EVENT_SOURCE__MASK)
+
+#define VIVS_GL_SEMAPHORE_TOKEN					0x00003808
+#define VIVS_GL_SEMAPHORE_TOKEN_FROM__MASK			0x0000001f
+#define VIVS_GL_SEMAPHORE_TOKEN_FROM__SHIFT			0
+#define VIVS_GL_SEMAPHORE_TOKEN_FROM(x)				(((x) << VIVS_GL_SEMAPHORE_TOKEN_FROM__SHIFT) & VIVS_GL_SEMAPHORE_TOKEN_FROM__MASK)
+#define VIVS_GL_SEMAPHORE_TOKEN_TO__MASK			0x00001f00
+#define VIVS_GL_SEMAPHORE_TOKEN_TO__SHIFT			8
+#define VIVS_GL_SEMAPHORE_TOKEN_TO(x)				(((x) << VIVS_GL_SEMAPHORE_TOKEN_TO__SHIFT) & VIVS_GL_SEMAPHORE_TOKEN_TO__MASK)
+
+#define VIVS_GL_FLUSH_CACHE					0x0000380c
+#define VIVS_GL_FLUSH_CACHE_DEPTH				0x00000001
+#define VIVS_GL_FLUSH_CACHE_COLOR				0x00000002
+#define VIVS_GL_FLUSH_CACHE_TEXTURE				0x00000004
+#define VIVS_GL_FLUSH_CACHE_PE2D				0x00000008
+#define VIVS_GL_FLUSH_CACHE_TEXTUREVS				0x00000010
+#define VIVS_GL_FLUSH_CACHE_SHADER_L1				0x00000020
+#define VIVS_GL_FLUSH_CACHE_SHADER_L2				0x00000040
+
+#define VIVS_GL_FLUSH_MMU					0x00003810
+#define VIVS_GL_FLUSH_MMU_FLUSH_FEMMU				0x00000001
+#define VIVS_GL_FLUSH_MMU_FLUSH_UNK1				0x00000002
+#define VIVS_GL_FLUSH_MMU_FLUSH_UNK2				0x00000004
+#define VIVS_GL_FLUSH_MMU_FLUSH_PEMMU				0x00000008
+#define VIVS_GL_FLUSH_MMU_FLUSH_UNK4				0x00000010
+
+#define VIVS_GL_VERTEX_ELEMENT_CONFIG				0x00003814
+
+#define VIVS_GL_MULTI_SAMPLE_CONFIG				0x00003818
+#define VIVS_GL_MULTI_SAMPLE_CONFIG_MSAA_SAMPLES__MASK		0x00000003
+#define VIVS_GL_MULTI_SAMPLE_CONFIG_MSAA_SAMPLES__SHIFT		0
+#define VIVS_GL_MULTI_SAMPLE_CONFIG_MSAA_SAMPLES_NONE		0x00000000
+#define VIVS_GL_MULTI_SAMPLE_CONFIG_MSAA_SAMPLES_2X		0x00000001
+#define VIVS_GL_MULTI_SAMPLE_CONFIG_MSAA_SAMPLES_4X		0x00000002
+#define VIVS_GL_MULTI_SAMPLE_CONFIG_MSAA_SAMPLES_MASK		0x00000008
+#define VIVS_GL_MULTI_SAMPLE_CONFIG_MSAA_ENABLES__MASK		0x000000f0
+#define VIVS_GL_MULTI_SAMPLE_CONFIG_MSAA_ENABLES__SHIFT		4
+#define VIVS_GL_MULTI_SAMPLE_CONFIG_MSAA_ENABLES(x)		(((x) << VIVS_GL_MULTI_SAMPLE_CONFIG_MSAA_ENABLES__SHIFT) & VIVS_GL_MULTI_SAMPLE_CONFIG_MSAA_ENABLES__MASK)
+#define VIVS_GL_MULTI_SAMPLE_CONFIG_MSAA_ENABLES_MASK		0x00000100
+#define VIVS_GL_MULTI_SAMPLE_CONFIG_UNK12__MASK			0x00007000
+#define VIVS_GL_MULTI_SAMPLE_CONFIG_UNK12__SHIFT		12
+#define VIVS_GL_MULTI_SAMPLE_CONFIG_UNK12(x)			(((x) << VIVS_GL_MULTI_SAMPLE_CONFIG_UNK12__SHIFT) & VIVS_GL_MULTI_SAMPLE_CONFIG_UNK12__MASK)
+#define VIVS_GL_MULTI_SAMPLE_CONFIG_UNK12_MASK			0x00008000
+#define VIVS_GL_MULTI_SAMPLE_CONFIG_UNK16__MASK			0x00030000
+#define VIVS_GL_MULTI_SAMPLE_CONFIG_UNK16__SHIFT		16
+#define VIVS_GL_MULTI_SAMPLE_CONFIG_UNK16(x)			(((x) << VIVS_GL_MULTI_SAMPLE_CONFIG_UNK16__SHIFT) & VIVS_GL_MULTI_SAMPLE_CONFIG_UNK16__MASK)
+#define VIVS_GL_MULTI_SAMPLE_CONFIG_UNK16_MASK			0x00080000
+
+#define VIVS_GL_VARYING_TOTAL_COMPONENTS			0x0000381c
+#define VIVS_GL_VARYING_TOTAL_COMPONENTS_NUM__MASK		0x000000ff
+#define VIVS_GL_VARYING_TOTAL_COMPONENTS_NUM__SHIFT		0
+#define VIVS_GL_VARYING_TOTAL_COMPONENTS_NUM(x)			(((x) << VIVS_GL_VARYING_TOTAL_COMPONENTS_NUM__SHIFT) & VIVS_GL_VARYING_TOTAL_COMPONENTS_NUM__MASK)
+
+#define VIVS_GL_VARYING_NUM_COMPONENTS				0x00003820
+#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR0__MASK		0x00000007
+#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR0__SHIFT		0
+#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR0(x)			(((x) << VIVS_GL_VARYING_NUM_COMPONENTS_VAR0__SHIFT) & VIVS_GL_VARYING_NUM_COMPONENTS_VAR0__MASK)
+#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR1__MASK		0x00000070
+#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR1__SHIFT		4
+#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR1(x)			(((x) << VIVS_GL_VARYING_NUM_COMPONENTS_VAR1__SHIFT) & VIVS_GL_VARYING_NUM_COMPONENTS_VAR1__MASK)
+#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR2__MASK		0x00000700
+#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR2__SHIFT		8
+#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR2(x)			(((x) << VIVS_GL_VARYING_NUM_COMPONENTS_VAR2__SHIFT) & VIVS_GL_VARYING_NUM_COMPONENTS_VAR2__MASK)
+#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR3__MASK		0x00007000
+#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR3__SHIFT		12
+#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR3(x)			(((x) << VIVS_GL_VARYING_NUM_COMPONENTS_VAR3__SHIFT) & VIVS_GL_VARYING_NUM_COMPONENTS_VAR3__MASK)
+#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR4__MASK		0x00070000
+#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR4__SHIFT		16
+#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR4(x)			(((x) << VIVS_GL_VARYING_NUM_COMPONENTS_VAR4__SHIFT) & VIVS_GL_VARYING_NUM_COMPONENTS_VAR4__MASK)
+#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR5__MASK		0x00700000
+#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR5__SHIFT		20
+#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR5(x)			(((x) << VIVS_GL_VARYING_NUM_COMPONENTS_VAR5__SHIFT) & VIVS_GL_VARYING_NUM_COMPONENTS_VAR5__MASK)
+#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR6__MASK		0x07000000
+#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR6__SHIFT		24
+#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR6(x)			(((x) << VIVS_GL_VARYING_NUM_COMPONENTS_VAR6__SHIFT) & VIVS_GL_VARYING_NUM_COMPONENTS_VAR6__MASK)
+#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR7__MASK		0x70000000
+#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR7__SHIFT		28
+#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR7(x)			(((x) << VIVS_GL_VARYING_NUM_COMPONENTS_VAR7__SHIFT) & VIVS_GL_VARYING_NUM_COMPONENTS_VAR7__MASK)
+
+#define VIVS_GL_VARYING_COMPONENT_USE(i0)		       (0x00003828 + 0x4*(i0))
+#define VIVS_GL_VARYING_COMPONENT_USE__ESIZE			0x00000004
+#define VIVS_GL_VARYING_COMPONENT_USE__LEN			0x00000002
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP0__MASK		0x00000003
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP0__SHIFT		0
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP0(x)			(((x) << VIVS_GL_VARYING_COMPONENT_USE_COMP0__SHIFT) & VIVS_GL_VARYING_COMPONENT_USE_COMP0__MASK)
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP1__MASK		0x0000000c
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP1__SHIFT		2
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP1(x)			(((x) << VIVS_GL_VARYING_COMPONENT_USE_COMP1__SHIFT) & VIVS_GL_VARYING_COMPONENT_USE_COMP1__MASK)
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP2__MASK		0x00000030
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP2__SHIFT		4
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP2(x)			(((x) << VIVS_GL_VARYING_COMPONENT_USE_COMP2__SHIFT) & VIVS_GL_VARYING_COMPONENT_USE_COMP2__MASK)
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP3__MASK		0x000000c0
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP3__SHIFT		6
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP3(x)			(((x) << VIVS_GL_VARYING_COMPONENT_USE_COMP3__SHIFT) & VIVS_GL_VARYING_COMPONENT_USE_COMP3__MASK)
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP4__MASK		0x00000300
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP4__SHIFT		8
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP4(x)			(((x) << VIVS_GL_VARYING_COMPONENT_USE_COMP4__SHIFT) & VIVS_GL_VARYING_COMPONENT_USE_COMP4__MASK)
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP5__MASK		0x00000c00
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP5__SHIFT		10
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP5(x)			(((x) << VIVS_GL_VARYING_COMPONENT_USE_COMP5__SHIFT) & VIVS_GL_VARYING_COMPONENT_USE_COMP5__MASK)
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP6__MASK		0x00003000
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP6__SHIFT		12
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP6(x)			(((x) << VIVS_GL_VARYING_COMPONENT_USE_COMP6__SHIFT) & VIVS_GL_VARYING_COMPONENT_USE_COMP6__MASK)
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP7__MASK		0x0000c000
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP7__SHIFT		14
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP7(x)			(((x) << VIVS_GL_VARYING_COMPONENT_USE_COMP7__SHIFT) & VIVS_GL_VARYING_COMPONENT_USE_COMP7__MASK)
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP8__MASK		0x00030000
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP8__SHIFT		16
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP8(x)			(((x) << VIVS_GL_VARYING_COMPONENT_USE_COMP8__SHIFT) & VIVS_GL_VARYING_COMPONENT_USE_COMP8__MASK)
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP9__MASK		0x000c0000
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP9__SHIFT		18
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP9(x)			(((x) << VIVS_GL_VARYING_COMPONENT_USE_COMP9__SHIFT) & VIVS_GL_VARYING_COMPONENT_USE_COMP9__MASK)
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP10__MASK		0x00300000
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP10__SHIFT		20
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP10(x)			(((x) << VIVS_GL_VARYING_COMPONENT_USE_COMP10__SHIFT) & VIVS_GL_VARYING_COMPONENT_USE_COMP10__MASK)
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP11__MASK		0x00c00000
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP11__SHIFT		22
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP11(x)			(((x) << VIVS_GL_VARYING_COMPONENT_USE_COMP11__SHIFT) & VIVS_GL_VARYING_COMPONENT_USE_COMP11__MASK)
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP12__MASK		0x03000000
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP12__SHIFT		24
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP12(x)			(((x) << VIVS_GL_VARYING_COMPONENT_USE_COMP12__SHIFT) & VIVS_GL_VARYING_COMPONENT_USE_COMP12__MASK)
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP13__MASK		0x0c000000
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP13__SHIFT		26
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP13(x)			(((x) << VIVS_GL_VARYING_COMPONENT_USE_COMP13__SHIFT) & VIVS_GL_VARYING_COMPONENT_USE_COMP13__MASK)
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP14__MASK		0x30000000
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP14__SHIFT		28
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP14(x)			(((x) << VIVS_GL_VARYING_COMPONENT_USE_COMP14__SHIFT) & VIVS_GL_VARYING_COMPONENT_USE_COMP14__MASK)
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP15__MASK		0xc0000000
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP15__SHIFT		30
+#define VIVS_GL_VARYING_COMPONENT_USE_COMP15(x)			(((x) << VIVS_GL_VARYING_COMPONENT_USE_COMP15__SHIFT) & VIVS_GL_VARYING_COMPONENT_USE_COMP15__MASK)
+
+#define VIVS_GL_UNK03834					0x00003834
+
+#define VIVS_GL_UNK03838					0x00003838
+
+#define VIVS_GL_API_MODE					0x0000384c
+#define VIVS_GL_API_MODE_OPENGL					0x00000000
+#define VIVS_GL_API_MODE_OPENVG					0x00000001
+#define VIVS_GL_API_MODE_OPENCL					0x00000002
+
+#define VIVS_GL_CONTEXT_POINTER					0x00003850
+
+#define VIVS_GL_UNK03854					0x00003854
+
+#define VIVS_GL_UNK03A00					0x00003a00
+
+#define VIVS_GL_STALL_TOKEN					0x00003c00
+#define VIVS_GL_STALL_TOKEN_FROM__MASK				0x0000001f
+#define VIVS_GL_STALL_TOKEN_FROM__SHIFT				0
+#define VIVS_GL_STALL_TOKEN_FROM(x)				(((x) << VIVS_GL_STALL_TOKEN_FROM__SHIFT) & VIVS_GL_STALL_TOKEN_FROM__MASK)
+#define VIVS_GL_STALL_TOKEN_TO__MASK				0x00001f00
+#define VIVS_GL_STALL_TOKEN_TO__SHIFT				8
+#define VIVS_GL_STALL_TOKEN_TO(x)				(((x) << VIVS_GL_STALL_TOKEN_TO__SHIFT) & VIVS_GL_STALL_TOKEN_TO__MASK)
+#define VIVS_GL_STALL_TOKEN_FLIP0				0x40000000
+#define VIVS_GL_STALL_TOKEN_FLIP1				0x80000000
+
+#define VIVS_NFE						0x00000000
+
+#define VIVS_NFE_UNK14600(i0)				       (0x00014600 + 0x4*(i0))
+#define VIVS_NFE_UNK14600__ESIZE				0x00000004
+#define VIVS_NFE_UNK14600__LEN					0x00000010
+
+#define VIVS_NFE_UNK14640(i0)				       (0x00014640 + 0x4*(i0))
+#define VIVS_NFE_UNK14640__ESIZE				0x00000004
+#define VIVS_NFE_UNK14640__LEN					0x00000010
+
+#define VIVS_NFE_UNK14680(i0)				       (0x00014680 + 0x4*(i0))
+#define VIVS_NFE_UNK14680__ESIZE				0x00000004
+#define VIVS_NFE_UNK14680__LEN					0x00000010
+
+#define VIVS_DUMMY						0x00000000
+
+#define VIVS_DUMMY_DUMMY					0x0003fffc
+
+
+#endif /* STATE_XML */
diff --git a/src/gallium/drivers/etnaviv/hw/state_3d.xml.h b/src/gallium/drivers/etnaviv/hw/state_3d.xml.h
new file mode 100644
index 0000000..41bbd0c
--- /dev/null
+++ b/src/gallium/drivers/etnaviv/hw/state_3d.xml.h
@@ -0,0 +1,1231 @@
+#ifndef STATE_3D_XML
+#define STATE_3D_XML
+
+/* Autogenerated file, DO NOT EDIT manually!
+
+This file was generated by the rules-ng-ng headergen tool in this git repository:
+http://0x04.net/cgit/index.cgi/rules-ng-ng
+git clone git://0x04.net/rules-ng-ng
+
+The rules-ng-ng source files this header was generated from are:
+- state.xml     (  19792 bytes, from 2016-11-16 18:54:37)
+- common.xml    (  23422 bytes, from 2016-11-16 18:54:37)
+- state_hi.xml  (  25653 bytes, from 2016-10-02 14:26:13)
+- copyright.xml (   1597 bytes, from 2016-10-02 14:26:13)
+- state_2d.xml  (  51552 bytes, from 2016-10-02 14:26:13)
+- state_3d.xml  (  57579 bytes, from 2016-11-16 18:54:37)
+- state_vg.xml  (   5975 bytes, from 2016-10-02 14:26:13)
+
+Copyright (C) 2012-2016 by the following authors:
+- Wladimir J. van der Laan <laanwj at gmail.com>
+- Christian Gmeiner <christian.gmeiner at gmail.com>
+- Lucas Stach <l.stach at pengutronix.de>
+- Russell King <rmk at arm.linux.org.uk>
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sub license,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice (including the
+next paragraph) shall be included in all copies or substantial portions
+of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+*/
+
+
+#define COMPARE_FUNC_NEVER					0x00000000
+#define COMPARE_FUNC_LESS					0x00000001
+#define COMPARE_FUNC_EQUAL					0x00000002
+#define COMPARE_FUNC_LEQUAL					0x00000003
+#define COMPARE_FUNC_GREATER					0x00000004
+#define COMPARE_FUNC_NOTEQUAL					0x00000005
+#define COMPARE_FUNC_GEQUAL					0x00000006
+#define COMPARE_FUNC_ALWAYS					0x00000007
+#define STENCIL_OP_KEEP						0x00000000
+#define STENCIL_OP_ZERO						0x00000001
+#define STENCIL_OP_REPLACE					0x00000002
+#define STENCIL_OP_INCR						0x00000003
+#define STENCIL_OP_DECR						0x00000004
+#define STENCIL_OP_INVERT					0x00000005
+#define STENCIL_OP_INCR_WRAP					0x00000006
+#define STENCIL_OP_DECR_WRAP					0x00000007
+#define BLEND_EQ_ADD						0x00000000
+#define BLEND_EQ_SUBTRACT					0x00000001
+#define BLEND_EQ_REVERSE_SUBTRACT				0x00000002
+#define BLEND_EQ_MIN						0x00000003
+#define BLEND_EQ_MAX						0x00000004
+#define BLEND_FUNC_ZERO						0x00000000
+#define BLEND_FUNC_ONE						0x00000001
+#define BLEND_FUNC_SRC_COLOR					0x00000002
+#define BLEND_FUNC_ONE_MINUS_SRC_COLOR				0x00000003
+#define BLEND_FUNC_SRC_ALPHA					0x00000004
+#define BLEND_FUNC_ONE_MINUS_SRC_ALPHA				0x00000005
+#define BLEND_FUNC_DST_ALPHA					0x00000006
+#define BLEND_FUNC_ONE_MINUS_DST_ALPHA				0x00000007
+#define BLEND_FUNC_DST_COLOR					0x00000008
+#define BLEND_FUNC_ONE_MINUS_DST_COLOR				0x00000009
+#define BLEND_FUNC_SRC_ALPHA_SATURATE				0x0000000a
+#define BLEND_FUNC_CONSTANT_ALPHA				0x0000000b
+#define BLEND_FUNC_ONE_MINUS_CONSTANT_ALPHA			0x0000000c
+#define BLEND_FUNC_CONSTANT_COLOR				0x0000000d
+#define BLEND_FUNC_ONE_MINUS_CONSTANT_COLOR			0x0000000e
+#define RS_FORMAT_X4R4G4B4					0x00000000
+#define RS_FORMAT_A4R4G4B4					0x00000001
+#define RS_FORMAT_X1R5G5B5					0x00000002
+#define RS_FORMAT_A1R5G5B5					0x00000003
+#define RS_FORMAT_R5G6B5					0x00000004
+#define RS_FORMAT_X8R8G8B8					0x00000005
+#define RS_FORMAT_A8R8G8B8					0x00000006
+#define RS_FORMAT_YUY2						0x00000007
+#define TEXTURE_FORMAT_NONE					0x00000000
+#define TEXTURE_FORMAT_A8					0x00000001
+#define TEXTURE_FORMAT_L8					0x00000002
+#define TEXTURE_FORMAT_I8					0x00000003
+#define TEXTURE_FORMAT_A8L8					0x00000004
+#define TEXTURE_FORMAT_A4R4G4B4					0x00000005
+#define TEXTURE_FORMAT_X4R4G4B4					0x00000006
+#define TEXTURE_FORMAT_A8R8G8B8					0x00000007
+#define TEXTURE_FORMAT_X8R8G8B8					0x00000008
+#define TEXTURE_FORMAT_A8B8G8R8					0x00000009
+#define TEXTURE_FORMAT_X8B8G8R8					0x0000000a
+#define TEXTURE_FORMAT_R5G6B5					0x0000000b
+#define TEXTURE_FORMAT_A1R5G5B5					0x0000000c
+#define TEXTURE_FORMAT_X1R5G5B5					0x0000000d
+#define TEXTURE_FORMAT_YUY2					0x0000000e
+#define TEXTURE_FORMAT_UYVY					0x0000000f
+#define TEXTURE_FORMAT_D16					0x00000010
+#define TEXTURE_FORMAT_D24S8					0x00000011
+#define TEXTURE_FORMAT_DXT1					0x00000013
+#define TEXTURE_FORMAT_DXT2_DXT3				0x00000014
+#define TEXTURE_FORMAT_DXT4_DXT5				0x00000015
+#define TEXTURE_FORMAT_ETC1					0x0000001e
+#define TEXTURE_FORMAT_EXT_NONE					0x00000000
+#define TEXTURE_FORMAT_EXT_A16F					0x00000007
+#define TEXTURE_FORMAT_EXT_A16L16F				0x00000008
+#define TEXTURE_FORMAT_EXT_A16B16G16R16F			0x00000009
+#define TEXTURE_FORMAT_EXT_A32F					0x0000000a
+#define TEXTURE_FORMAT_EXT_A32L32F				0x0000000b
+#define TEXTURE_FORMAT_EXT_A2B10G10R10				0x0000000c
+#define TEXTURE_FILTER_NONE					0x00000000
+#define TEXTURE_FILTER_NEAREST					0x00000001
+#define TEXTURE_FILTER_LINEAR					0x00000002
+#define TEXTURE_FILTER_ANISOTROPIC				0x00000003
+#define TEXTURE_TYPE_NONE					0x00000000
+#define TEXTURE_TYPE_2D						0x00000002
+#define TEXTURE_TYPE_CUBE_MAP					0x00000005
+#define TEXTURE_WRAPMODE_REPEAT					0x00000000
+#define TEXTURE_WRAPMODE_MIRRORED_REPEAT			0x00000001
+#define TEXTURE_WRAPMODE_CLAMP_TO_EDGE				0x00000002
+#define TEXTURE_FACE_POS_X					0x00000000
+#define TEXTURE_FACE_NEG_X					0x00000001
+#define TEXTURE_FACE_POS_Y					0x00000002
+#define TEXTURE_FACE_NEG_Y					0x00000003
+#define TEXTURE_FACE_POS_Z					0x00000004
+#define TEXTURE_FACE_NEG_Z					0x00000005
+#define TEXTURE_SWIZZLE_RED					0x00000000
+#define TEXTURE_SWIZZLE_GREEN					0x00000001
+#define TEXTURE_SWIZZLE_BLUE					0x00000002
+#define TEXTURE_SWIZZLE_ALPHA					0x00000003
+#define TEXTURE_SWIZZLE_ZERO					0x00000004
+#define TEXTURE_SWIZZLE_ONE					0x00000005
+#define TEXTURE_HALIGN_FOUR					0x00000000
+#define TEXTURE_HALIGN_SIXTEEN					0x00000001
+#define TEXTURE_HALIGN_SUPER_TILED				0x00000002
+#define TEXTURE_HALIGN_SPLIT_TILED				0x00000003
+#define TEXTURE_HALIGN_SPLIT_SUPER_TILED			0x00000004
+#define LOGIC_OP_CLEAR						0x00000000
+#define LOGIC_OP_NOR						0x00000001
+#define LOGIC_OP_AND_INVERTED					0x00000002
+#define LOGIC_OP_COPY_INVERTED					0x00000003
+#define LOGIC_OP_AND_REVERSE					0x00000004
+#define LOGIC_OP_INVERT						0x00000005
+#define LOGIC_OP_XOR						0x00000006
+#define LOGIC_OP_NAND						0x00000007
+#define LOGIC_OP_AND						0x00000008
+#define LOGIC_OP_EQUIV						0x00000009
+#define LOGIC_OP_NOOP						0x0000000a
+#define LOGIC_OP_OR_INVERTED					0x0000000b
+#define LOGIC_OP_COPY						0x0000000c
+#define LOGIC_OP_OR_REVERSE					0x0000000d
+#define LOGIC_OP_OR						0x0000000e
+#define LOGIC_OP_SET						0x0000000f
+#define VIVS_VS							0x00000000
+
+#define VIVS_VS_END_PC						0x00000800
+
+#define VIVS_VS_OUTPUT_COUNT					0x00000804
+
+#define VIVS_VS_INPUT_COUNT					0x00000808
+#define VIVS_VS_INPUT_COUNT_COUNT__MASK				0x0000000f
+#define VIVS_VS_INPUT_COUNT_COUNT__SHIFT			0
+#define VIVS_VS_INPUT_COUNT_COUNT(x)				(((x) << VIVS_VS_INPUT_COUNT_COUNT__SHIFT) & VIVS_VS_INPUT_COUNT_COUNT__MASK)
+#define VIVS_VS_INPUT_COUNT_UNK8__MASK				0x00001f00
+#define VIVS_VS_INPUT_COUNT_UNK8__SHIFT				8
+#define VIVS_VS_INPUT_COUNT_UNK8(x)				(((x) << VIVS_VS_INPUT_COUNT_UNK8__SHIFT) & VIVS_VS_INPUT_COUNT_UNK8__MASK)
+
+#define VIVS_VS_TEMP_REGISTER_CONTROL				0x0000080c
+#define VIVS_VS_TEMP_REGISTER_CONTROL_NUM_TEMPS__MASK		0x0000003f
+#define VIVS_VS_TEMP_REGISTER_CONTROL_NUM_TEMPS__SHIFT		0
+#define VIVS_VS_TEMP_REGISTER_CONTROL_NUM_TEMPS(x)		(((x) << VIVS_VS_TEMP_REGISTER_CONTROL_NUM_TEMPS__SHIFT) & VIVS_VS_TEMP_REGISTER_CONTROL_NUM_TEMPS__MASK)
+
+#define VIVS_VS_OUTPUT(i0)				       (0x00000810 + 0x4*(i0))
+#define VIVS_VS_OUTPUT__ESIZE					0x00000004
+#define VIVS_VS_OUTPUT__LEN					0x00000004
+#define VIVS_VS_OUTPUT_O0__MASK					0x000000ff
+#define VIVS_VS_OUTPUT_O0__SHIFT				0
+#define VIVS_VS_OUTPUT_O0(x)					(((x) << VIVS_VS_OUTPUT_O0__SHIFT) & VIVS_VS_OUTPUT_O0__MASK)
+#define VIVS_VS_OUTPUT_O1__MASK					0x0000ff00
+#define VIVS_VS_OUTPUT_O1__SHIFT				8
+#define VIVS_VS_OUTPUT_O1(x)					(((x) << VIVS_VS_OUTPUT_O1__SHIFT) & VIVS_VS_OUTPUT_O1__MASK)
+#define VIVS_VS_OUTPUT_O2__MASK					0x00ff0000
+#define VIVS_VS_OUTPUT_O2__SHIFT				16
+#define VIVS_VS_OUTPUT_O2(x)					(((x) << VIVS_VS_OUTPUT_O2__SHIFT) & VIVS_VS_OUTPUT_O2__MASK)
+#define VIVS_VS_OUTPUT_O3__MASK					0xff000000
+#define VIVS_VS_OUTPUT_O3__SHIFT				24
+#define VIVS_VS_OUTPUT_O3(x)					(((x) << VIVS_VS_OUTPUT_O3__SHIFT) & VIVS_VS_OUTPUT_O3__MASK)
+
+#define VIVS_VS_INPUT(i0)				       (0x00000820 + 0x4*(i0))
+#define VIVS_VS_INPUT__ESIZE					0x00000004
+#define VIVS_VS_INPUT__LEN					0x00000004
+#define VIVS_VS_INPUT_I0__MASK					0x000000ff
+#define VIVS_VS_INPUT_I0__SHIFT					0
+#define VIVS_VS_INPUT_I0(x)					(((x) << VIVS_VS_INPUT_I0__SHIFT) & VIVS_VS_INPUT_I0__MASK)
+#define VIVS_VS_INPUT_I1__MASK					0x0000ff00
+#define VIVS_VS_INPUT_I1__SHIFT					8
+#define VIVS_VS_INPUT_I1(x)					(((x) << VIVS_VS_INPUT_I1__SHIFT) & VIVS_VS_INPUT_I1__MASK)
+#define VIVS_VS_INPUT_I2__MASK					0x00ff0000
+#define VIVS_VS_INPUT_I2__SHIFT					16
+#define VIVS_VS_INPUT_I2(x)					(((x) << VIVS_VS_INPUT_I2__SHIFT) & VIVS_VS_INPUT_I2__MASK)
+#define VIVS_VS_INPUT_I3__MASK					0xff000000
+#define VIVS_VS_INPUT_I3__SHIFT					24
+#define VIVS_VS_INPUT_I3(x)					(((x) << VIVS_VS_INPUT_I3__SHIFT) & VIVS_VS_INPUT_I3__MASK)
+
+#define VIVS_VS_LOAD_BALANCING					0x00000830
+#define VIVS_VS_LOAD_BALANCING_A__MASK				0x000000ff
+#define VIVS_VS_LOAD_BALANCING_A__SHIFT				0
+#define VIVS_VS_LOAD_BALANCING_A(x)				(((x) << VIVS_VS_LOAD_BALANCING_A__SHIFT) & VIVS_VS_LOAD_BALANCING_A__MASK)
+#define VIVS_VS_LOAD_BALANCING_B__MASK				0x0000ff00
+#define VIVS_VS_LOAD_BALANCING_B__SHIFT				8
+#define VIVS_VS_LOAD_BALANCING_B(x)				(((x) << VIVS_VS_LOAD_BALANCING_B__SHIFT) & VIVS_VS_LOAD_BALANCING_B__MASK)
+#define VIVS_VS_LOAD_BALANCING_C__MASK				0x00ff0000
+#define VIVS_VS_LOAD_BALANCING_C__SHIFT				16
+#define VIVS_VS_LOAD_BALANCING_C(x)				(((x) << VIVS_VS_LOAD_BALANCING_C__SHIFT) & VIVS_VS_LOAD_BALANCING_C__MASK)
+#define VIVS_VS_LOAD_BALANCING_D__MASK				0xff000000
+#define VIVS_VS_LOAD_BALANCING_D__SHIFT				24
+#define VIVS_VS_LOAD_BALANCING_D(x)				(((x) << VIVS_VS_LOAD_BALANCING_D__SHIFT) & VIVS_VS_LOAD_BALANCING_D__MASK)
+
+#define VIVS_VS_PERF_COUNTER					0x00000834
+
+#define VIVS_VS_START_PC					0x00000838
+
+#define VIVS_VS_UNK00850					0x00000850
+
+#define VIVS_VS_UNK00854					0x00000854
+
+#define VIVS_VS_UNK00858					0x00000858
+
+#define VIVS_VS_RANGE						0x0000085c
+#define VIVS_VS_RANGE_LOW__MASK					0x0000ffff
+#define VIVS_VS_RANGE_LOW__SHIFT				0
+#define VIVS_VS_RANGE_LOW(x)					(((x) << VIVS_VS_RANGE_LOW__SHIFT) & VIVS_VS_RANGE_LOW__MASK)
+#define VIVS_VS_RANGE_HIGH__MASK				0xffff0000
+#define VIVS_VS_RANGE_HIGH__SHIFT				16
+#define VIVS_VS_RANGE_HIGH(x)					(((x) << VIVS_VS_RANGE_HIGH__SHIFT) & VIVS_VS_RANGE_HIGH__MASK)
+
+#define VIVS_VS_NEW_UNK00860					0x00000860
+
+#define VIVS_VS_UNK00864					0x00000864
+
+#define VIVS_VS_UNK00868					0x00000868
+
+#define VIVS_VS_UNK0086C					0x0000086c
+
+#define VIVS_VS_INST_MEM(i0)				       (0x00004000 + 0x4*(i0))
+#define VIVS_VS_INST_MEM__ESIZE					0x00000004
+#define VIVS_VS_INST_MEM__LEN					0x00000400
+
+#define VIVS_VS_UNIFORMS(i0)				       (0x00005000 + 0x4*(i0))
+#define VIVS_VS_UNIFORMS__ESIZE					0x00000004
+#define VIVS_VS_UNIFORMS__LEN					0x00000400
+
+#define VIVS_CL							0x00000000
+
+#define VIVS_CL_CONFIG						0x00000900
+#define VIVS_CL_CONFIG_DIMENSIONS__MASK				0x00000003
+#define VIVS_CL_CONFIG_DIMENSIONS__SHIFT			0
+#define VIVS_CL_CONFIG_DIMENSIONS(x)				(((x) << VIVS_CL_CONFIG_DIMENSIONS__SHIFT) & VIVS_CL_CONFIG_DIMENSIONS__MASK)
+#define VIVS_CL_CONFIG_TRAVERSE_ORDER__MASK			0x00000070
+#define VIVS_CL_CONFIG_TRAVERSE_ORDER__SHIFT			4
+#define VIVS_CL_CONFIG_TRAVERSE_ORDER(x)			(((x) << VIVS_CL_CONFIG_TRAVERSE_ORDER__SHIFT) & VIVS_CL_CONFIG_TRAVERSE_ORDER__MASK)
+#define VIVS_CL_CONFIG_ENABLE_SWATH_X				0x00000100
+#define VIVS_CL_CONFIG_ENABLE_SWATH_Y				0x00000200
+#define VIVS_CL_CONFIG_ENABLE_SWATH_Z				0x00000400
+#define VIVS_CL_CONFIG_SWATH_SIZE_X__MASK			0x0000f000
+#define VIVS_CL_CONFIG_SWATH_SIZE_X__SHIFT			12
+#define VIVS_CL_CONFIG_SWATH_SIZE_X(x)				(((x) << VIVS_CL_CONFIG_SWATH_SIZE_X__SHIFT) & VIVS_CL_CONFIG_SWATH_SIZE_X__MASK)
+#define VIVS_CL_CONFIG_SWATH_SIZE_Y__MASK			0x000f0000
+#define VIVS_CL_CONFIG_SWATH_SIZE_Y__SHIFT			16
+#define VIVS_CL_CONFIG_SWATH_SIZE_Y(x)				(((x) << VIVS_CL_CONFIG_SWATH_SIZE_Y__SHIFT) & VIVS_CL_CONFIG_SWATH_SIZE_Y__MASK)
+#define VIVS_CL_CONFIG_SWATH_SIZE_Z__MASK			0x00f00000
+#define VIVS_CL_CONFIG_SWATH_SIZE_Z__SHIFT			20
+#define VIVS_CL_CONFIG_SWATH_SIZE_Z(x)				(((x) << VIVS_CL_CONFIG_SWATH_SIZE_Z__SHIFT) & VIVS_CL_CONFIG_SWATH_SIZE_Z__MASK)
+#define VIVS_CL_CONFIG_VALUE_ORDER__MASK			0x07000000
+#define VIVS_CL_CONFIG_VALUE_ORDER__SHIFT			24
+#define VIVS_CL_CONFIG_VALUE_ORDER(x)				(((x) << VIVS_CL_CONFIG_VALUE_ORDER__SHIFT) & VIVS_CL_CONFIG_VALUE_ORDER__MASK)
+
+#define VIVS_CL_GLOBAL_X					0x00000904
+#define VIVS_CL_GLOBAL_X_SIZE__MASK				0x0000ffff
+#define VIVS_CL_GLOBAL_X_SIZE__SHIFT				0
+#define VIVS_CL_GLOBAL_X_SIZE(x)				(((x) << VIVS_CL_GLOBAL_X_SIZE__SHIFT) & VIVS_CL_GLOBAL_X_SIZE__MASK)
+#define VIVS_CL_GLOBAL_X_OFFSET__MASK				0xffff0000
+#define VIVS_CL_GLOBAL_X_OFFSET__SHIFT				16
+#define VIVS_CL_GLOBAL_X_OFFSET(x)				(((x) << VIVS_CL_GLOBAL_X_OFFSET__SHIFT) & VIVS_CL_GLOBAL_X_OFFSET__MASK)
+
+#define VIVS_CL_GLOBAL_Y					0x00000908
+#define VIVS_CL_GLOBAL_Y_SIZE__MASK				0x0000ffff
+#define VIVS_CL_GLOBAL_Y_SIZE__SHIFT				0
+#define VIVS_CL_GLOBAL_Y_SIZE(x)				(((x) << VIVS_CL_GLOBAL_Y_SIZE__SHIFT) & VIVS_CL_GLOBAL_Y_SIZE__MASK)
+#define VIVS_CL_GLOBAL_Y_OFFSET__MASK				0xffff0000
+#define VIVS_CL_GLOBAL_Y_OFFSET__SHIFT				16
+#define VIVS_CL_GLOBAL_Y_OFFSET(x)				(((x) << VIVS_CL_GLOBAL_Y_OFFSET__SHIFT) & VIVS_CL_GLOBAL_Y_OFFSET__MASK)
+
+#define VIVS_CL_GLOBAL_Z					0x0000090c
+#define VIVS_CL_GLOBAL_Z_SIZE__MASK				0x0000ffff
+#define VIVS_CL_GLOBAL_Z_SIZE__SHIFT				0
+#define VIVS_CL_GLOBAL_Z_SIZE(x)				(((x) << VIVS_CL_GLOBAL_Z_SIZE__SHIFT) & VIVS_CL_GLOBAL_Z_SIZE__MASK)
+#define VIVS_CL_GLOBAL_Z_OFFSET__MASK				0xffff0000
+#define VIVS_CL_GLOBAL_Z_OFFSET__SHIFT				16
+#define VIVS_CL_GLOBAL_Z_OFFSET(x)				(((x) << VIVS_CL_GLOBAL_Z_OFFSET__SHIFT) & VIVS_CL_GLOBAL_Z_OFFSET__MASK)
+
+#define VIVS_CL_WORKGROUP_X					0x00000910
+#define VIVS_CL_WORKGROUP_X_SIZE__MASK				0x000003ff
+#define VIVS_CL_WORKGROUP_X_SIZE__SHIFT				0
+#define VIVS_CL_WORKGROUP_X_SIZE(x)				(((x) << VIVS_CL_WORKGROUP_X_SIZE__SHIFT) & VIVS_CL_WORKGROUP_X_SIZE__MASK)
+#define VIVS_CL_WORKGROUP_X_COUNT__MASK				0xffff0000
+#define VIVS_CL_WORKGROUP_X_COUNT__SHIFT			16
+#define VIVS_CL_WORKGROUP_X_COUNT(x)				(((x) << VIVS_CL_WORKGROUP_X_COUNT__SHIFT) & VIVS_CL_WORKGROUP_X_COUNT__MASK)
+
+#define VIVS_CL_WORKGROUP_Y					0x00000914
+#define VIVS_CL_WORKGROUP_Y_SIZE__MASK				0x000003ff
+#define VIVS_CL_WORKGROUP_Y_SIZE__SHIFT				0
+#define VIVS_CL_WORKGROUP_Y_SIZE(x)				(((x) << VIVS_CL_WORKGROUP_Y_SIZE__SHIFT) & VIVS_CL_WORKGROUP_Y_SIZE__MASK)
+#define VIVS_CL_WORKGROUP_Y_COUNT__MASK				0xffff0000
+#define VIVS_CL_WORKGROUP_Y_COUNT__SHIFT			16
+#define VIVS_CL_WORKGROUP_Y_COUNT(x)				(((x) << VIVS_CL_WORKGROUP_Y_COUNT__SHIFT) & VIVS_CL_WORKGROUP_Y_COUNT__MASK)
+
+#define VIVS_CL_WORKGROUP_Z					0x00000918
+#define VIVS_CL_WORKGROUP_Z_SIZE__MASK				0x000003ff
+#define VIVS_CL_WORKGROUP_Z_SIZE__SHIFT				0
+#define VIVS_CL_WORKGROUP_Z_SIZE(x)				(((x) << VIVS_CL_WORKGROUP_Z_SIZE__SHIFT) & VIVS_CL_WORKGROUP_Z_SIZE__MASK)
+#define VIVS_CL_WORKGROUP_Z_COUNT__MASK				0xffff0000
+#define VIVS_CL_WORKGROUP_Z_COUNT__SHIFT			16
+#define VIVS_CL_WORKGROUP_Z_COUNT(x)				(((x) << VIVS_CL_WORKGROUP_Z_COUNT__SHIFT) & VIVS_CL_WORKGROUP_Z_COUNT__MASK)
+
+#define VIVS_CL_THREAD_ALLOCATION				0x0000091c
+
+#define VIVS_CL_KICKER						0x00000920
+
+#define VIVS_CL_UNK00924					0x00000924
+
+#define VIVS_PA							0x00000000
+
+#define VIVS_PA_VIEWPORT_SCALE_X				0x00000a00
+
+#define VIVS_PA_VIEWPORT_SCALE_Y				0x00000a04
+
+#define VIVS_PA_VIEWPORT_SCALE_Z				0x00000a08
+
+#define VIVS_PA_VIEWPORT_OFFSET_X				0x00000a0c
+
+#define VIVS_PA_VIEWPORT_OFFSET_Y				0x00000a10
+
+#define VIVS_PA_VIEWPORT_OFFSET_Z				0x00000a14
+
+#define VIVS_PA_LINE_WIDTH					0x00000a18
+
+#define VIVS_PA_POINT_SIZE					0x00000a1c
+
+#define VIVS_PA_SYSTEM_MODE					0x00000a28
+#define VIVS_PA_SYSTEM_MODE_UNK0				0x00000001
+#define VIVS_PA_SYSTEM_MODE_UNK4				0x00000010
+
+#define VIVS_PA_W_CLIP_LIMIT					0x00000a2c
+
+#define VIVS_PA_ATTRIBUTE_ELEMENT_COUNT				0x00000a30
+#define VIVS_PA_ATTRIBUTE_ELEMENT_COUNT_UNK0__MASK		0x000000ff
+#define VIVS_PA_ATTRIBUTE_ELEMENT_COUNT_UNK0__SHIFT		0
+#define VIVS_PA_ATTRIBUTE_ELEMENT_COUNT_UNK0(x)			(((x) << VIVS_PA_ATTRIBUTE_ELEMENT_COUNT_UNK0__SHIFT) & VIVS_PA_ATTRIBUTE_ELEMENT_COUNT_UNK0__MASK)
+#define VIVS_PA_ATTRIBUTE_ELEMENT_COUNT_COUNT__MASK		0x0000ff00
+#define VIVS_PA_ATTRIBUTE_ELEMENT_COUNT_COUNT__SHIFT		8
+#define VIVS_PA_ATTRIBUTE_ELEMENT_COUNT_COUNT(x)		(((x) << VIVS_PA_ATTRIBUTE_ELEMENT_COUNT_COUNT__SHIFT) & VIVS_PA_ATTRIBUTE_ELEMENT_COUNT_COUNT__MASK)
+
+#define VIVS_PA_CONFIG						0x00000a34
+#define VIVS_PA_CONFIG_POINT_SIZE_ENABLE			0x00000004
+#define VIVS_PA_CONFIG_POINT_SIZE_ENABLE_MASK			0x00000008
+#define VIVS_PA_CONFIG_POINT_SPRITE_ENABLE			0x00000010
+#define VIVS_PA_CONFIG_POINT_SPRITE_ENABLE_MASK			0x00000020
+#define VIVS_PA_CONFIG_CULL_FACE_MODE__MASK			0x00000300
+#define VIVS_PA_CONFIG_CULL_FACE_MODE__SHIFT			8
+#define VIVS_PA_CONFIG_CULL_FACE_MODE_OFF			0x00000000
+#define VIVS_PA_CONFIG_CULL_FACE_MODE_CW			0x00000100
+#define VIVS_PA_CONFIG_CULL_FACE_MODE_CCW			0x00000200
+#define VIVS_PA_CONFIG_CULL_FACE_MODE_MASK			0x00000400
+#define VIVS_PA_CONFIG_FILL_MODE__MASK				0x00003000
+#define VIVS_PA_CONFIG_FILL_MODE__SHIFT				12
+#define VIVS_PA_CONFIG_FILL_MODE_POINT				0x00000000
+#define VIVS_PA_CONFIG_FILL_MODE_WIREFRAME			0x00001000
+#define VIVS_PA_CONFIG_FILL_MODE_SOLID				0x00002000
+#define VIVS_PA_CONFIG_FILL_MODE_MASK				0x00004000
+#define VIVS_PA_CONFIG_SHADE_MODEL__MASK			0x00030000
+#define VIVS_PA_CONFIG_SHADE_MODEL__SHIFT			16
+#define VIVS_PA_CONFIG_SHADE_MODEL_FLAT				0x00000000
+#define VIVS_PA_CONFIG_SHADE_MODEL_SMOOTH			0x00010000
+#define VIVS_PA_CONFIG_SHADE_MODEL_MASK				0x00040000
+#define VIVS_PA_CONFIG_WIDE_LINE				0x00400000
+#define VIVS_PA_CONFIG_WIDE_LINE_MASK				0x00800000
+
+#define VIVS_PA_WIDE_LINE_WIDTH0				0x00000a38
+
+#define VIVS_PA_WIDE_LINE_WIDTH1				0x00000a3c
+
+#define VIVS_PA_SHADER_ATTRIBUTES(i0)			       (0x00000a40 + 0x4*(i0))
+#define VIVS_PA_SHADER_ATTRIBUTES__ESIZE			0x00000004
+#define VIVS_PA_SHADER_ATTRIBUTES__LEN				0x0000000a
+#define VIVS_PA_SHADER_ATTRIBUTES_BYPASS_FLAT			0x00000001
+#define VIVS_PA_SHADER_ATTRIBUTES_UNK4__MASK			0x000000f0
+#define VIVS_PA_SHADER_ATTRIBUTES_UNK4__SHIFT			4
+#define VIVS_PA_SHADER_ATTRIBUTES_UNK4(x)			(((x) << VIVS_PA_SHADER_ATTRIBUTES_UNK4__SHIFT) & VIVS_PA_SHADER_ATTRIBUTES_UNK4__MASK)
+#define VIVS_PA_SHADER_ATTRIBUTES_UNK8__MASK			0x00000f00
+#define VIVS_PA_SHADER_ATTRIBUTES_UNK8__SHIFT			8
+#define VIVS_PA_SHADER_ATTRIBUTES_UNK8(x)			(((x) << VIVS_PA_SHADER_ATTRIBUTES_UNK8__SHIFT) & VIVS_PA_SHADER_ATTRIBUTES_UNK8__MASK)
+
+#define VIVS_PA_VIEWPORT_UNK00A80				0x00000a80
+
+#define VIVS_PA_VIEWPORT_UNK00A84				0x00000a84
+
+#define VIVS_PA_FLAGS						0x00000a88
+#define VIVS_PA_FLAGS_UNK24					0x01000000
+#define VIVS_PA_FLAGS_ZCONVERT_BYPASS				0x40000000
+
+#define VIVS_PA_ZFARCLIPPING					0x00000a8c
+
+#define VIVS_SE							0x00000000
+
+#define VIVS_SE_SCISSOR_LEFT					0x00000c00
+
+#define VIVS_SE_SCISSOR_TOP					0x00000c04
+
+#define VIVS_SE_SCISSOR_RIGHT					0x00000c08
+
+#define VIVS_SE_SCISSOR_BOTTOM					0x00000c0c
+
+#define VIVS_SE_DEPTH_SCALE					0x00000c10
+
+#define VIVS_SE_DEPTH_BIAS					0x00000c14
+
+#define VIVS_SE_CONFIG						0x00000c18
+#define VIVS_SE_CONFIG_LAST_PIXEL_ENABLE			0x00000001
+
+#define VIVS_SE_UNK00C1C					0x00000c1c
+
+#define VIVS_SE_CLIP_RIGHT					0x00000c20
+
+#define VIVS_SE_CLIP_BOTTOM					0x00000c24
+
+#define VIVS_RA							0x00000000
+
+#define VIVS_RA_CONTROL						0x00000e00
+#define VIVS_RA_CONTROL_UNK0					0x00000001
+#define VIVS_RA_CONTROL_LAST_VARYING_2X				0x00000002
+
+#define VIVS_RA_MULTISAMPLE_UNK00E04				0x00000e04
+
+#define VIVS_RA_EARLY_DEPTH					0x00000e08
+
+#define VIVS_RA_UNK00E0C					0x00000e0c
+
+#define VIVS_RA_MULTISAMPLE_UNK00E10(i0)		       (0x00000e10 + 0x4*(i0))
+#define VIVS_RA_MULTISAMPLE_UNK00E10__ESIZE			0x00000004
+#define VIVS_RA_MULTISAMPLE_UNK00E10__LEN			0x00000004
+
+#define VIVS_RA_HDEPTH_CONTROL					0x00000e20
+#define VIVS_RA_HDEPTH_CONTROL_UNK0				0x00000001
+#define VIVS_RA_HDEPTH_CONTROL_COMPARE__MASK			0x00007000
+#define VIVS_RA_HDEPTH_CONTROL_COMPARE__SHIFT			12
+#define VIVS_RA_HDEPTH_CONTROL_COMPARE(x)			(((x) << VIVS_RA_HDEPTH_CONTROL_COMPARE__SHIFT) & VIVS_RA_HDEPTH_CONTROL_COMPARE__MASK)
+
+#define VIVS_RA_CENTROID_TABLE(i0)			       (0x00000e40 + 0x4*(i0))
+#define VIVS_RA_CENTROID_TABLE__ESIZE				0x00000004
+#define VIVS_RA_CENTROID_TABLE__LEN				0x00000010
+
+#define VIVS_PS							0x00000000
+
+#define VIVS_PS_END_PC						0x00001000
+
+#define VIVS_PS_OUTPUT_REG					0x00001004
+
+#define VIVS_PS_INPUT_COUNT					0x00001008
+#define VIVS_PS_INPUT_COUNT_COUNT__MASK				0x0000000f
+#define VIVS_PS_INPUT_COUNT_COUNT__SHIFT			0
+#define VIVS_PS_INPUT_COUNT_COUNT(x)				(((x) << VIVS_PS_INPUT_COUNT_COUNT__SHIFT) & VIVS_PS_INPUT_COUNT_COUNT__MASK)
+#define VIVS_PS_INPUT_COUNT_UNK8__MASK				0x00001f00
+#define VIVS_PS_INPUT_COUNT_UNK8__SHIFT				8
+#define VIVS_PS_INPUT_COUNT_UNK8(x)				(((x) << VIVS_PS_INPUT_COUNT_UNK8__SHIFT) & VIVS_PS_INPUT_COUNT_UNK8__MASK)
+
+#define VIVS_PS_TEMP_REGISTER_CONTROL				0x0000100c
+#define VIVS_PS_TEMP_REGISTER_CONTROL_NUM_TEMPS__MASK		0x0000003f
+#define VIVS_PS_TEMP_REGISTER_CONTROL_NUM_TEMPS__SHIFT		0
+#define VIVS_PS_TEMP_REGISTER_CONTROL_NUM_TEMPS(x)		(((x) << VIVS_PS_TEMP_REGISTER_CONTROL_NUM_TEMPS__SHIFT) & VIVS_PS_TEMP_REGISTER_CONTROL_NUM_TEMPS__MASK)
+
+#define VIVS_PS_CONTROL						0x00001010
+#define VIVS_PS_CONTROL_BYPASS					0x00000001
+#define VIVS_PS_CONTROL_UNK1					0x00000002
+
+#define VIVS_PS_PERF_COUNTER					0x00001014
+
+#define VIVS_PS_START_PC					0x00001018
+
+#define VIVS_PS_RANGE						0x0000101c
+#define VIVS_PS_RANGE_LOW__MASK					0x0000ffff
+#define VIVS_PS_RANGE_LOW__SHIFT				0
+#define VIVS_PS_RANGE_LOW(x)					(((x) << VIVS_PS_RANGE_LOW__SHIFT) & VIVS_PS_RANGE_LOW__MASK)
+#define VIVS_PS_RANGE_HIGH__MASK				0xffff0000
+#define VIVS_PS_RANGE_HIGH__SHIFT				16
+#define VIVS_PS_RANGE_HIGH(x)					(((x) << VIVS_PS_RANGE_HIGH__SHIFT) & VIVS_PS_RANGE_HIGH__MASK)
+
+#define VIVS_PS_UNK01024					0x00001024
+
+#define VIVS_PS_UNK01028					0x00001028
+
+#define VIVS_PS_UNK01030					0x00001030
+
+#define VIVS_PS_INST_MEM(i0)				       (0x00006000 + 0x4*(i0))
+#define VIVS_PS_INST_MEM__ESIZE					0x00000004
+#define VIVS_PS_INST_MEM__LEN					0x00000400
+
+#define VIVS_PS_UNIFORMS(i0)				       (0x00007000 + 0x4*(i0))
+#define VIVS_PS_UNIFORMS__ESIZE					0x00000004
+#define VIVS_PS_UNIFORMS__LEN					0x00000400
+
+#define VIVS_PE							0x00000000
+
+#define VIVS_PE_DEPTH_CONFIG					0x00001400
+#define VIVS_PE_DEPTH_CONFIG_DEPTH_MODE__MASK			0x00000003
+#define VIVS_PE_DEPTH_CONFIG_DEPTH_MODE__SHIFT			0
+#define VIVS_PE_DEPTH_CONFIG_DEPTH_MODE_NONE			0x00000000
+#define VIVS_PE_DEPTH_CONFIG_DEPTH_MODE_Z			0x00000001
+#define VIVS_PE_DEPTH_CONFIG_DEPTH_MODE_W			0x00000002
+#define VIVS_PE_DEPTH_CONFIG_DEPTH_MODE_MASK			0x00000008
+#define VIVS_PE_DEPTH_CONFIG_DEPTH_FORMAT__MASK			0x00000010
+#define VIVS_PE_DEPTH_CONFIG_DEPTH_FORMAT__SHIFT		4
+#define VIVS_PE_DEPTH_CONFIG_DEPTH_FORMAT_D16			0x00000000
+#define VIVS_PE_DEPTH_CONFIG_DEPTH_FORMAT_D24S8			0x00000010
+#define VIVS_PE_DEPTH_CONFIG_DEPTH_FORMAT_MASK			0x00000020
+#define VIVS_PE_DEPTH_CONFIG_DEPTH_FUNC__MASK			0x00000700
+#define VIVS_PE_DEPTH_CONFIG_DEPTH_FUNC__SHIFT			8
+#define VIVS_PE_DEPTH_CONFIG_DEPTH_FUNC(x)			(((x) << VIVS_PE_DEPTH_CONFIG_DEPTH_FUNC__SHIFT) & VIVS_PE_DEPTH_CONFIG_DEPTH_FUNC__MASK)
+#define VIVS_PE_DEPTH_CONFIG_DEPTH_FUNC_MASK			0x00000800
+#define VIVS_PE_DEPTH_CONFIG_WRITE_ENABLE			0x00001000
+#define VIVS_PE_DEPTH_CONFIG_WRITE_ENABLE_MASK			0x00002000
+#define VIVS_PE_DEPTH_CONFIG_EARLY_Z				0x00010000
+#define VIVS_PE_DEPTH_CONFIG_EARLY_Z_MASK			0x00020000
+#define VIVS_PE_DEPTH_CONFIG_UNK18				0x00040000
+#define VIVS_PE_DEPTH_CONFIG_ONLY_DEPTH				0x00100000
+#define VIVS_PE_DEPTH_CONFIG_ONLY_DEPTH_MASK			0x00200000
+#define VIVS_PE_DEPTH_CONFIG_DISABLE_ZS				0x01000000
+#define VIVS_PE_DEPTH_CONFIG_DISABLE_ZS_MASK			0x02000000
+#define VIVS_PE_DEPTH_CONFIG_SUPER_TILED			0x04000000
+#define VIVS_PE_DEPTH_CONFIG_SUPER_TILED_MASK			0x08000000
+
+#define VIVS_PE_DEPTH_NEAR					0x00001404
+
+#define VIVS_PE_DEPTH_FAR					0x00001408
+
+#define VIVS_PE_DEPTH_NORMALIZE					0x0000140c
+
+#define VIVS_PE_DEPTH_ADDR					0x00001410
+
+#define VIVS_PE_DEPTH_STRIDE					0x00001414
+
+#define VIVS_PE_STENCIL_OP					0x00001418
+#define VIVS_PE_STENCIL_OP_FUNC_FRONT__MASK			0x00000007
+#define VIVS_PE_STENCIL_OP_FUNC_FRONT__SHIFT			0
+#define VIVS_PE_STENCIL_OP_FUNC_FRONT(x)			(((x) << VIVS_PE_STENCIL_OP_FUNC_FRONT__SHIFT) & VIVS_PE_STENCIL_OP_FUNC_FRONT__MASK)
+#define VIVS_PE_STENCIL_OP_FUNC_FRONT_MASK			0x00000008
+#define VIVS_PE_STENCIL_OP_PASS_FRONT__MASK			0x00000070
+#define VIVS_PE_STENCIL_OP_PASS_FRONT__SHIFT			4
+#define VIVS_PE_STENCIL_OP_PASS_FRONT(x)			(((x) << VIVS_PE_STENCIL_OP_PASS_FRONT__SHIFT) & VIVS_PE_STENCIL_OP_PASS_FRONT__MASK)
+#define VIVS_PE_STENCIL_OP_PASS_FRONT_MASK			0x00000080
+#define VIVS_PE_STENCIL_OP_FAIL_FRONT__MASK			0x00000700
+#define VIVS_PE_STENCIL_OP_FAIL_FRONT__SHIFT			8
+#define VIVS_PE_STENCIL_OP_FAIL_FRONT(x)			(((x) << VIVS_PE_STENCIL_OP_FAIL_FRONT__SHIFT) & VIVS_PE_STENCIL_OP_FAIL_FRONT__MASK)
+#define VIVS_PE_STENCIL_OP_FAIL_FRONT_MASK			0x00000800
+#define VIVS_PE_STENCIL_OP_DEPTH_FAIL_FRONT__MASK		0x00007000
+#define VIVS_PE_STENCIL_OP_DEPTH_FAIL_FRONT__SHIFT		12
+#define VIVS_PE_STENCIL_OP_DEPTH_FAIL_FRONT(x)			(((x) << VIVS_PE_STENCIL_OP_DEPTH_FAIL_FRONT__SHIFT) & VIVS_PE_STENCIL_OP_DEPTH_FAIL_FRONT__MASK)
+#define VIVS_PE_STENCIL_OP_DEPTH_FAIL_FRONT_MASK		0x00008000
+#define VIVS_PE_STENCIL_OP_FUNC_BACK__MASK			0x00070000
+#define VIVS_PE_STENCIL_OP_FUNC_BACK__SHIFT			16
+#define VIVS_PE_STENCIL_OP_FUNC_BACK(x)				(((x) << VIVS_PE_STENCIL_OP_FUNC_BACK__SHIFT) & VIVS_PE_STENCIL_OP_FUNC_BACK__MASK)
+#define VIVS_PE_STENCIL_OP_FUNC_BACK_MASK			0x00080000
+#define VIVS_PE_STENCIL_OP_PASS_BACK__MASK			0x00700000
+#define VIVS_PE_STENCIL_OP_PASS_BACK__SHIFT			20
+#define VIVS_PE_STENCIL_OP_PASS_BACK(x)				(((x) << VIVS_PE_STENCIL_OP_PASS_BACK__SHIFT) & VIVS_PE_STENCIL_OP_PASS_BACK__MASK)
+#define VIVS_PE_STENCIL_OP_PASS_BACK_MASK			0x00800000
+#define VIVS_PE_STENCIL_OP_FAIL_BACK__MASK			0x07000000
+#define VIVS_PE_STENCIL_OP_FAIL_BACK__SHIFT			24
+#define VIVS_PE_STENCIL_OP_FAIL_BACK(x)				(((x) << VIVS_PE_STENCIL_OP_FAIL_BACK__SHIFT) & VIVS_PE_STENCIL_OP_FAIL_BACK__MASK)
+#define VIVS_PE_STENCIL_OP_FAIL_BACK_MASK			0x08000000
+#define VIVS_PE_STENCIL_OP_DEPTH_FAIL_BACK__MASK		0x70000000
+#define VIVS_PE_STENCIL_OP_DEPTH_FAIL_BACK__SHIFT		28
+#define VIVS_PE_STENCIL_OP_DEPTH_FAIL_BACK(x)			(((x) << VIVS_PE_STENCIL_OP_DEPTH_FAIL_BACK__SHIFT) & VIVS_PE_STENCIL_OP_DEPTH_FAIL_BACK__MASK)
+#define VIVS_PE_STENCIL_OP_DEPTH_FAIL_BACK_MASK			0x80000000
+
+#define VIVS_PE_STENCIL_CONFIG					0x0000141c
+#define VIVS_PE_STENCIL_CONFIG_MODE__MASK			0x00000003
+#define VIVS_PE_STENCIL_CONFIG_MODE__SHIFT			0
+#define VIVS_PE_STENCIL_CONFIG_MODE_DISABLED			0x00000000
+#define VIVS_PE_STENCIL_CONFIG_MODE_ONE_SIDED			0x00000001
+#define VIVS_PE_STENCIL_CONFIG_MODE_TWO_SIDED			0x00000002
+#define VIVS_PE_STENCIL_CONFIG_MODE_MASK			0x00000010
+#define VIVS_PE_STENCIL_CONFIG_REF_FRONT_MASK			0x00000020
+#define VIVS_PE_STENCIL_CONFIG_MASK_FRONT_MASK			0x00000040
+#define VIVS_PE_STENCIL_CONFIG_WRITE_MASK_MASK			0x00000080
+#define VIVS_PE_STENCIL_CONFIG_REF_FRONT__MASK			0x0000ff00
+#define VIVS_PE_STENCIL_CONFIG_REF_FRONT__SHIFT			8
+#define VIVS_PE_STENCIL_CONFIG_REF_FRONT(x)			(((x) << VIVS_PE_STENCIL_CONFIG_REF_FRONT__SHIFT) & VIVS_PE_STENCIL_CONFIG_REF_FRONT__MASK)
+#define VIVS_PE_STENCIL_CONFIG_MASK_FRONT__MASK			0x00ff0000
+#define VIVS_PE_STENCIL_CONFIG_MASK_FRONT__SHIFT		16
+#define VIVS_PE_STENCIL_CONFIG_MASK_FRONT(x)			(((x) << VIVS_PE_STENCIL_CONFIG_MASK_FRONT__SHIFT) & VIVS_PE_STENCIL_CONFIG_MASK_FRONT__MASK)
+#define VIVS_PE_STENCIL_CONFIG_WRITE_MASK_FRONT__MASK		0xff000000
+#define VIVS_PE_STENCIL_CONFIG_WRITE_MASK_FRONT__SHIFT		24
+#define VIVS_PE_STENCIL_CONFIG_WRITE_MASK_FRONT(x)		(((x) << VIVS_PE_STENCIL_CONFIG_WRITE_MASK_FRONT__SHIFT) & VIVS_PE_STENCIL_CONFIG_WRITE_MASK_FRONT__MASK)
+
+#define VIVS_PE_ALPHA_OP					0x00001420
+#define VIVS_PE_ALPHA_OP_ALPHA_TEST				0x00000001
+#define VIVS_PE_ALPHA_OP_ALPHA_TEST_MASK			0x00000002
+#define VIVS_PE_ALPHA_OP_ALPHA_FUNC__MASK			0x00000070
+#define VIVS_PE_ALPHA_OP_ALPHA_FUNC__SHIFT			4
+#define VIVS_PE_ALPHA_OP_ALPHA_FUNC(x)				(((x) << VIVS_PE_ALPHA_OP_ALPHA_FUNC__SHIFT) & VIVS_PE_ALPHA_OP_ALPHA_FUNC__MASK)
+#define VIVS_PE_ALPHA_OP_ALPHA_FUNC_MASK			0x00000080
+#define VIVS_PE_ALPHA_OP_ALPHA_REF__MASK			0x0000ff00
+#define VIVS_PE_ALPHA_OP_ALPHA_REF__SHIFT			8
+#define VIVS_PE_ALPHA_OP_ALPHA_REF(x)				(((x) << VIVS_PE_ALPHA_OP_ALPHA_REF__SHIFT) & VIVS_PE_ALPHA_OP_ALPHA_REF__MASK)
+#define VIVS_PE_ALPHA_OP_ALPHA_REF_MASKFUNC_MASK		0x00010000
+
+#define VIVS_PE_ALPHA_BLEND_COLOR				0x00001424
+#define VIVS_PE_ALPHA_BLEND_COLOR_B__MASK			0x000000ff
+#define VIVS_PE_ALPHA_BLEND_COLOR_B__SHIFT			0
+#define VIVS_PE_ALPHA_BLEND_COLOR_B(x)				(((x) << VIVS_PE_ALPHA_BLEND_COLOR_B__SHIFT) & VIVS_PE_ALPHA_BLEND_COLOR_B__MASK)
+#define VIVS_PE_ALPHA_BLEND_COLOR_G__MASK			0x0000ff00
+#define VIVS_PE_ALPHA_BLEND_COLOR_G__SHIFT			8
+#define VIVS_PE_ALPHA_BLEND_COLOR_G(x)				(((x) << VIVS_PE_ALPHA_BLEND_COLOR_G__SHIFT) & VIVS_PE_ALPHA_BLEND_COLOR_G__MASK)
+#define VIVS_PE_ALPHA_BLEND_COLOR_R__MASK			0x00ff0000
+#define VIVS_PE_ALPHA_BLEND_COLOR_R__SHIFT			16
+#define VIVS_PE_ALPHA_BLEND_COLOR_R(x)				(((x) << VIVS_PE_ALPHA_BLEND_COLOR_R__SHIFT) & VIVS_PE_ALPHA_BLEND_COLOR_R__MASK)
+#define VIVS_PE_ALPHA_BLEND_COLOR_A__MASK			0xff000000
+#define VIVS_PE_ALPHA_BLEND_COLOR_A__SHIFT			24
+#define VIVS_PE_ALPHA_BLEND_COLOR_A(x)				(((x) << VIVS_PE_ALPHA_BLEND_COLOR_A__SHIFT) & VIVS_PE_ALPHA_BLEND_COLOR_A__MASK)
+
+#define VIVS_PE_ALPHA_CONFIG					0x00001428
+#define VIVS_PE_ALPHA_CONFIG_BLEND_ENABLE_COLOR			0x00000001
+#define VIVS_PE_ALPHA_CONFIG_BLEND_ENABLE_COLOR_MASK		0x00000002
+#define VIVS_PE_ALPHA_CONFIG_SRC_FUNC_COLOR_MASK		0x00000004
+#define VIVS_PE_ALPHA_CONFIG_DST_FUNC_COLOR_MASK		0x00000008
+#define VIVS_PE_ALPHA_CONFIG_SRC_FUNC_COLOR__MASK		0x000000f0
+#define VIVS_PE_ALPHA_CONFIG_SRC_FUNC_COLOR__SHIFT		4
+#define VIVS_PE_ALPHA_CONFIG_SRC_FUNC_COLOR(x)			(((x) << VIVS_PE_ALPHA_CONFIG_SRC_FUNC_COLOR__SHIFT) & VIVS_PE_ALPHA_CONFIG_SRC_FUNC_COLOR__MASK)
+#define VIVS_PE_ALPHA_CONFIG_DST_FUNC_COLOR__MASK		0x00000f00
+#define VIVS_PE_ALPHA_CONFIG_DST_FUNC_COLOR__SHIFT		8
+#define VIVS_PE_ALPHA_CONFIG_DST_FUNC_COLOR(x)			(((x) << VIVS_PE_ALPHA_CONFIG_DST_FUNC_COLOR__SHIFT) & VIVS_PE_ALPHA_CONFIG_DST_FUNC_COLOR__MASK)
+#define VIVS_PE_ALPHA_CONFIG_EQ_COLOR__MASK			0x00007000
+#define VIVS_PE_ALPHA_CONFIG_EQ_COLOR__SHIFT			12
+#define VIVS_PE_ALPHA_CONFIG_EQ_COLOR(x)			(((x) << VIVS_PE_ALPHA_CONFIG_EQ_COLOR__SHIFT) & VIVS_PE_ALPHA_CONFIG_EQ_COLOR__MASK)
+#define VIVS_PE_ALPHA_CONFIG_EQ_COLOR_MASK			0x00008000
+#define VIVS_PE_ALPHA_CONFIG_BLEND_SEPARATE_ALPHA		0x00010000
+#define VIVS_PE_ALPHA_CONFIG_BLEND_SEPARATE_ALPHA_MASK		0x00020000
+#define VIVS_PE_ALPHA_CONFIG_SRC_FUNC_ALPHA_MASK		0x00040000
+#define VIVS_PE_ALPHA_CONFIG_DST_FUNC_ALPHA_MASK		0x00080000
+#define VIVS_PE_ALPHA_CONFIG_SRC_FUNC_ALPHA__MASK		0x00f00000
+#define VIVS_PE_ALPHA_CONFIG_SRC_FUNC_ALPHA__SHIFT		20
+#define VIVS_PE_ALPHA_CONFIG_SRC_FUNC_ALPHA(x)			(((x) << VIVS_PE_ALPHA_CONFIG_SRC_FUNC_ALPHA__SHIFT) & VIVS_PE_ALPHA_CONFIG_SRC_FUNC_ALPHA__MASK)
+#define VIVS_PE_ALPHA_CONFIG_DST_FUNC_ALPHA__MASK		0x0f000000
+#define VIVS_PE_ALPHA_CONFIG_DST_FUNC_ALPHA__SHIFT		24
+#define VIVS_PE_ALPHA_CONFIG_DST_FUNC_ALPHA(x)			(((x) << VIVS_PE_ALPHA_CONFIG_DST_FUNC_ALPHA__SHIFT) & VIVS_PE_ALPHA_CONFIG_DST_FUNC_ALPHA__MASK)
+#define VIVS_PE_ALPHA_CONFIG_EQ_ALPHA__MASK			0x70000000
+#define VIVS_PE_ALPHA_CONFIG_EQ_ALPHA__SHIFT			28
+#define VIVS_PE_ALPHA_CONFIG_EQ_ALPHA(x)			(((x) << VIVS_PE_ALPHA_CONFIG_EQ_ALPHA__SHIFT) & VIVS_PE_ALPHA_CONFIG_EQ_ALPHA__MASK)
+#define VIVS_PE_ALPHA_CONFIG_EQ_ALPHA_MASK			0x80000000
+
+#define VIVS_PE_COLOR_FORMAT					0x0000142c
+#define VIVS_PE_COLOR_FORMAT_FORMAT__MASK			0x0000000f
+#define VIVS_PE_COLOR_FORMAT_FORMAT__SHIFT			0
+#define VIVS_PE_COLOR_FORMAT_FORMAT(x)				(((x) << VIVS_PE_COLOR_FORMAT_FORMAT__SHIFT) & VIVS_PE_COLOR_FORMAT_FORMAT__MASK)
+#define VIVS_PE_COLOR_FORMAT_FORMAT_MASK			0x00000010
+#define VIVS_PE_COLOR_FORMAT_COMPONENTS__MASK			0x00000f00
+#define VIVS_PE_COLOR_FORMAT_COMPONENTS__SHIFT			8
+#define VIVS_PE_COLOR_FORMAT_COMPONENTS(x)			(((x) << VIVS_PE_COLOR_FORMAT_COMPONENTS__SHIFT) & VIVS_PE_COLOR_FORMAT_COMPONENTS__MASK)
+#define VIVS_PE_COLOR_FORMAT_COMPONENTS_MASK			0x00001000
+#define VIVS_PE_COLOR_FORMAT_OVERWRITE				0x00010000
+#define VIVS_PE_COLOR_FORMAT_OVERWRITE_MASK			0x00020000
+#define VIVS_PE_COLOR_FORMAT_SUPER_TILED			0x00100000
+#define VIVS_PE_COLOR_FORMAT_SUPER_TILED_MASK			0x00200000
+#define VIVS_PE_COLOR_FORMAT_UNK25				0x02000000
+#define VIVS_PE_COLOR_FORMAT_UNK26				0x04000000
+
+#define VIVS_PE_COLOR_ADDR					0x00001430
+
+#define VIVS_PE_COLOR_STRIDE					0x00001434
+
+#define VIVS_PE_HDEPTH_CONTROL					0x00001454
+#define VIVS_PE_HDEPTH_CONTROL_FORMAT__MASK			0x0000000f
+#define VIVS_PE_HDEPTH_CONTROL_FORMAT__SHIFT			0
+#define VIVS_PE_HDEPTH_CONTROL_FORMAT_DISABLED			0x00000000
+#define VIVS_PE_HDEPTH_CONTROL_FORMAT_D16			0x00000005
+#define VIVS_PE_HDEPTH_CONTROL_FORMAT_D24S8			0x00000008
+
+#define VIVS_PE_HDEPTH_ADDR					0x00001458
+
+#define VIVS_PE_UNK0145C					0x0000145c
+
+#define VIVS_PE_PIPE(i0)				       (0x00000000 + 0x4*(i0))
+#define VIVS_PE_PIPE__ESIZE					0x00000004
+#define VIVS_PE_PIPE__LEN					0x00000008
+
+#define VIVS_PE_PIPE_COLOR_ADDR(i0)			       (0x00001460 + 0x4*(i0))
+
+#define VIVS_PE_PIPE_DEPTH_ADDR(i0)			       (0x00001480 + 0x4*(i0))
+
+#define VIVS_PE_PIPE_ADDR_UNK01500(i0)			       (0x00001500 + 0x4*(i0))
+
+#define VIVS_PE_PIPE_ADDR_UNK01520(i0)			       (0x00001520 + 0x4*(i0))
+
+#define VIVS_PE_STENCIL_CONFIG_EXT				0x000014a0
+#define VIVS_PE_STENCIL_CONFIG_EXT_REF_BACK__MASK		0x000000ff
+#define VIVS_PE_STENCIL_CONFIG_EXT_REF_BACK__SHIFT		0
+#define VIVS_PE_STENCIL_CONFIG_EXT_REF_BACK(x)			(((x) << VIVS_PE_STENCIL_CONFIG_EXT_REF_BACK__SHIFT) & VIVS_PE_STENCIL_CONFIG_EXT_REF_BACK__MASK)
+#define VIVS_PE_STENCIL_CONFIG_EXT_REF_BACK_MASK		0x00000100
+#define VIVS_PE_STENCIL_CONFIG_EXT_UNK16_MASK			0x00000200
+#define VIVS_PE_STENCIL_CONFIG_EXT_UNK16__MASK			0xffff0000
+#define VIVS_PE_STENCIL_CONFIG_EXT_UNK16__SHIFT			16
+#define VIVS_PE_STENCIL_CONFIG_EXT_UNK16(x)			(((x) << VIVS_PE_STENCIL_CONFIG_EXT_UNK16__SHIFT) & VIVS_PE_STENCIL_CONFIG_EXT_UNK16__MASK)
+
+#define VIVS_PE_LOGIC_OP					0x000014a4
+#define VIVS_PE_LOGIC_OP_OP__MASK				0x0000000f
+#define VIVS_PE_LOGIC_OP_OP__SHIFT				0
+#define VIVS_PE_LOGIC_OP_OP(x)					(((x) << VIVS_PE_LOGIC_OP_OP__SHIFT) & VIVS_PE_LOGIC_OP_OP__MASK)
+#define VIVS_PE_LOGIC_OP_OP_MASK				0x00000010
+
+#define VIVS_PE_DITHER(i0)				       (0x000014a8 + 0x4*(i0))
+#define VIVS_PE_DITHER__ESIZE					0x00000004
+#define VIVS_PE_DITHER__LEN					0x00000002
+
+#define VIVS_PE_ALPHA_COLOR_EXT0				0x000014b0
+#define VIVS_PE_ALPHA_COLOR_EXT0_B__MASK			0x0000ffff
+#define VIVS_PE_ALPHA_COLOR_EXT0_B__SHIFT			0
+#define VIVS_PE_ALPHA_COLOR_EXT0_B(x)				(((x) << VIVS_PE_ALPHA_COLOR_EXT0_B__SHIFT) & VIVS_PE_ALPHA_COLOR_EXT0_B__MASK)
+#define VIVS_PE_ALPHA_COLOR_EXT0_G__MASK			0xffff0000
+#define VIVS_PE_ALPHA_COLOR_EXT0_G__SHIFT			16
+#define VIVS_PE_ALPHA_COLOR_EXT0_G(x)				(((x) << VIVS_PE_ALPHA_COLOR_EXT0_G__SHIFT) & VIVS_PE_ALPHA_COLOR_EXT0_G__MASK)
+
+#define VIVS_PE_ALPHA_COLOR_EXT1				0x000014b4
+#define VIVS_PE_ALPHA_COLOR_EXT1_R__MASK			0x0000ffff
+#define VIVS_PE_ALPHA_COLOR_EXT1_R__SHIFT			0
+#define VIVS_PE_ALPHA_COLOR_EXT1_R(x)				(((x) << VIVS_PE_ALPHA_COLOR_EXT1_R__SHIFT) & VIVS_PE_ALPHA_COLOR_EXT1_R__MASK)
+#define VIVS_PE_ALPHA_COLOR_EXT1_A__MASK			0xffff0000
+#define VIVS_PE_ALPHA_COLOR_EXT1_A__SHIFT			16
+#define VIVS_PE_ALPHA_COLOR_EXT1_A(x)				(((x) << VIVS_PE_ALPHA_COLOR_EXT1_A__SHIFT) & VIVS_PE_ALPHA_COLOR_EXT1_A__MASK)
+
+#define VIVS_PE_STENCIL_CONFIG_EXT2				0x000014b8
+#define VIVS_PE_STENCIL_CONFIG_EXT2_MASK_BACK__MASK		0x000000ff
+#define VIVS_PE_STENCIL_CONFIG_EXT2_MASK_BACK__SHIFT		0
+#define VIVS_PE_STENCIL_CONFIG_EXT2_MASK_BACK(x)		(((x) << VIVS_PE_STENCIL_CONFIG_EXT2_MASK_BACK__SHIFT) & VIVS_PE_STENCIL_CONFIG_EXT2_MASK_BACK__MASK)
+#define VIVS_PE_STENCIL_CONFIG_EXT2_WRITE_MASK_BACK__MASK	0x0000ff00
+#define VIVS_PE_STENCIL_CONFIG_EXT2_WRITE_MASK_BACK__SHIFT	8
+#define VIVS_PE_STENCIL_CONFIG_EXT2_WRITE_MASK_BACK(x)		(((x) << VIVS_PE_STENCIL_CONFIG_EXT2_WRITE_MASK_BACK__SHIFT) & VIVS_PE_STENCIL_CONFIG_EXT2_WRITE_MASK_BACK__MASK)
+
+#define VIVS_PE_UNK01580(i0)				       (0x00001580 + 0x4*(i0))
+#define VIVS_PE_UNK01580__ESIZE					0x00000004
+#define VIVS_PE_UNK01580__LEN					0x00000003
+
+#define VIVS_CO							0x00000000
+
+#define VIVS_CO_UNK03008					0x00003008
+
+#define VIVS_CO_KICKER						0x0000300c
+
+#define VIVS_CO_UNK03010					0x00003010
+
+#define VIVS_CO_UNK03014					0x00003014
+
+#define VIVS_CO_UNK03018					0x00003018
+
+#define VIVS_CO_UNK0301C					0x0000301c
+
+#define VIVS_CO_UNK03020					0x00003020
+
+#define VIVS_CO_UNK03024					0x00003024
+
+#define VIVS_CO_UNK03040					0x00003040
+
+#define VIVS_CO_UNK03044					0x00003044
+
+#define VIVS_CO_UNK03048					0x00003048
+
+#define VIVS_CO_SAMPLER(i0)				       (0x00000000 + 0x4*(i0))
+#define VIVS_CO_SAMPLER__ESIZE					0x00000004
+#define VIVS_CO_SAMPLER__LEN					0x00000008
+
+#define VIVS_CO_SAMPLER_UNK03060(i0)			       (0x00003060 + 0x4*(i0))
+
+#define VIVS_CO_SAMPLER_UNK03080(i0)			       (0x00003080 + 0x4*(i0))
+
+#define VIVS_CO_SAMPLER_UNK030A0(i0)			       (0x000030a0 + 0x4*(i0))
+
+#define VIVS_CO_SAMPLER_UNK030C0(i0)			       (0x000030c0 + 0x4*(i0))
+
+#define VIVS_CO_SAMPLER_UNK030E0(i0)			       (0x000030e0 + 0x4*(i0))
+
+#define VIVS_CO_SAMPLER_UNK03100(i0)			       (0x00003100 + 0x4*(i0))
+
+#define VIVS_CO_SAMPLER_UNK03120(i0)			       (0x00003120 + 0x4*(i0))
+
+#define VIVS_CO_SAMPLER_UNK03140(i0)			       (0x00003140 + 0x4*(i0))
+
+#define VIVS_CO_SAMPLER_UNK03160(i0)			       (0x00003160 + 0x4*(i0))
+
+#define VIVS_CO_SAMPLER_UNK03180(i0)			       (0x00003180 + 0x4*(i0))
+
+#define VIVS_CO_SAMPLER_UNK031A0(i0)			       (0x000031a0 + 0x4*(i0))
+
+#define VIVS_CO_SAMPLER_UNK031C0(i0)			       (0x000031c0 + 0x4*(i0))
+
+#define VIVS_CO_SAMPLER_UNK031E0(i0)			       (0x000031e0 + 0x4*(i0))
+
+#define VIVS_CO_ADDR_UNK03200(i0)			       (0x00003200 + 0x20*(i0))
+#define VIVS_CO_ADDR_UNK03200__ESIZE				0x00000020
+#define VIVS_CO_ADDR_UNK03200__LEN				0x00000008
+
+#define VIVS_CO_ADDR_UNK03200_PPIPE(i0, i1)		       (0x00003200 + 0x20*(i0) + 0x4*(i1))
+#define VIVS_CO_ADDR_UNK03200_PPIPE__ESIZE			0x00000004
+#define VIVS_CO_ADDR_UNK03200_PPIPE__LEN			0x00000008
+
+#define VIVS_RS							0x00000000
+
+#define VIVS_RS_KICKER						0x00001600
+
+#define VIVS_RS_CONFIG						0x00001604
+#define VIVS_RS_CONFIG_SOURCE_FORMAT__MASK			0x0000001f
+#define VIVS_RS_CONFIG_SOURCE_FORMAT__SHIFT			0
+#define VIVS_RS_CONFIG_SOURCE_FORMAT(x)				(((x) << VIVS_RS_CONFIG_SOURCE_FORMAT__SHIFT) & VIVS_RS_CONFIG_SOURCE_FORMAT__MASK)
+#define VIVS_RS_CONFIG_DOWNSAMPLE_X				0x00000020
+#define VIVS_RS_CONFIG_DOWNSAMPLE_Y				0x00000040
+#define VIVS_RS_CONFIG_SOURCE_TILED				0x00000080
+#define VIVS_RS_CONFIG_DEST_FORMAT__MASK			0x00001f00
+#define VIVS_RS_CONFIG_DEST_FORMAT__SHIFT			8
+#define VIVS_RS_CONFIG_DEST_FORMAT(x)				(((x) << VIVS_RS_CONFIG_DEST_FORMAT__SHIFT) & VIVS_RS_CONFIG_DEST_FORMAT__MASK)
+#define VIVS_RS_CONFIG_DEST_TILED				0x00004000
+#define VIVS_RS_CONFIG_SWAP_RB					0x20000000
+#define VIVS_RS_CONFIG_FLIP					0x40000000
+
+#define VIVS_RS_SOURCE_ADDR					0x00001608
+
+#define VIVS_RS_SOURCE_STRIDE					0x0000160c
+#define VIVS_RS_SOURCE_STRIDE_STRIDE__MASK			0x0003ffff
+#define VIVS_RS_SOURCE_STRIDE_STRIDE__SHIFT			0
+#define VIVS_RS_SOURCE_STRIDE_STRIDE(x)				(((x) << VIVS_RS_SOURCE_STRIDE_STRIDE__SHIFT) & VIVS_RS_SOURCE_STRIDE_STRIDE__MASK)
+#define VIVS_RS_SOURCE_STRIDE_MULTI				0x40000000
+#define VIVS_RS_SOURCE_STRIDE_TILING				0x80000000
+
+#define VIVS_RS_DEST_ADDR					0x00001610
+
+#define VIVS_RS_DEST_STRIDE					0x00001614
+#define VIVS_RS_DEST_STRIDE_STRIDE__MASK			0x0003ffff
+#define VIVS_RS_DEST_STRIDE_STRIDE__SHIFT			0
+#define VIVS_RS_DEST_STRIDE_STRIDE(x)				(((x) << VIVS_RS_DEST_STRIDE_STRIDE__SHIFT) & VIVS_RS_DEST_STRIDE_STRIDE__MASK)
+#define VIVS_RS_DEST_STRIDE_MULTI				0x40000000
+#define VIVS_RS_DEST_STRIDE_TILING				0x80000000
+
+#define VIVS_RS_WINDOW_SIZE					0x00001620
+#define VIVS_RS_WINDOW_SIZE_HEIGHT__MASK			0xffff0000
+#define VIVS_RS_WINDOW_SIZE_HEIGHT__SHIFT			16
+#define VIVS_RS_WINDOW_SIZE_HEIGHT(x)				(((x) << VIVS_RS_WINDOW_SIZE_HEIGHT__SHIFT) & VIVS_RS_WINDOW_SIZE_HEIGHT__MASK)
+#define VIVS_RS_WINDOW_SIZE_WIDTH__MASK				0x0000ffff
+#define VIVS_RS_WINDOW_SIZE_WIDTH__SHIFT			0
+#define VIVS_RS_WINDOW_SIZE_WIDTH(x)				(((x) << VIVS_RS_WINDOW_SIZE_WIDTH__SHIFT) & VIVS_RS_WINDOW_SIZE_WIDTH__MASK)
+
+#define VIVS_RS_DITHER(i0)				       (0x00001630 + 0x4*(i0))
+#define VIVS_RS_DITHER__ESIZE					0x00000004
+#define VIVS_RS_DITHER__LEN					0x00000002
+
+#define VIVS_RS_CLEAR_CONTROL					0x0000163c
+#define VIVS_RS_CLEAR_CONTROL_BITS__MASK			0x0000ffff
+#define VIVS_RS_CLEAR_CONTROL_BITS__SHIFT			0
+#define VIVS_RS_CLEAR_CONTROL_BITS(x)				(((x) << VIVS_RS_CLEAR_CONTROL_BITS__SHIFT) & VIVS_RS_CLEAR_CONTROL_BITS__MASK)
+#define VIVS_RS_CLEAR_CONTROL_MODE__MASK			0x00030000
+#define VIVS_RS_CLEAR_CONTROL_MODE__SHIFT			16
+#define VIVS_RS_CLEAR_CONTROL_MODE_DISABLED			0x00000000
+#define VIVS_RS_CLEAR_CONTROL_MODE_ENABLED1			0x00010000
+#define VIVS_RS_CLEAR_CONTROL_MODE_ENABLED4			0x00020000
+#define VIVS_RS_CLEAR_CONTROL_MODE_ENABLED4_2			0x00030000
+
+#define VIVS_RS_FILL_VALUE(i0)				       (0x00001640 + 0x4*(i0))
+#define VIVS_RS_FILL_VALUE__ESIZE				0x00000004
+#define VIVS_RS_FILL_VALUE__LEN					0x00000004
+
+#define VIVS_RS_EXTRA_CONFIG					0x000016a0
+#define VIVS_RS_EXTRA_CONFIG_AA__MASK				0x00000003
+#define VIVS_RS_EXTRA_CONFIG_AA__SHIFT				0
+#define VIVS_RS_EXTRA_CONFIG_AA(x)				(((x) << VIVS_RS_EXTRA_CONFIG_AA__SHIFT) & VIVS_RS_EXTRA_CONFIG_AA__MASK)
+#define VIVS_RS_EXTRA_CONFIG_ENDIAN__MASK			0x00000300
+#define VIVS_RS_EXTRA_CONFIG_ENDIAN__SHIFT			8
+#define VIVS_RS_EXTRA_CONFIG_ENDIAN(x)				(((x) << VIVS_RS_EXTRA_CONFIG_ENDIAN__SHIFT) & VIVS_RS_EXTRA_CONFIG_ENDIAN__MASK)
+#define VIVS_RS_EXTRA_CONFIG_UNK20				0x00100000
+#define VIVS_RS_EXTRA_CONFIG_UNK28				0x10000000
+
+#define VIVS_RS_UNK016B0					0x000016b0
+
+#define VIVS_RS_UNK016B4					0x000016b4
+
+#define VIVS_RS_UNK016B8					0x000016b8
+#define VIVS_RS_UNK016B8_UNK0					0x00000001
+
+#define VIVS_RS_UNK016BC					0x000016bc
+
+#define VIVS_RS_PIPE(i0)				       (0x00000000 + 0x4*(i0))
+#define VIVS_RS_PIPE__ESIZE					0x00000004
+#define VIVS_RS_PIPE__LEN					0x00000008
+
+#define VIVS_RS_PIPE_SOURCE_ADDR(i0)			       (0x000016c0 + 0x4*(i0))
+
+#define VIVS_RS_PIPE_DEST_ADDR(i0)			       (0x000016e0 + 0x4*(i0))
+
+#define VIVS_RS_PIPE_OFFSET(i0)				       (0x00001700 + 0x4*(i0))
+#define VIVS_RS_PIPE_OFFSET_X__MASK				0x0000ffff
+#define VIVS_RS_PIPE_OFFSET_X__SHIFT				0
+#define VIVS_RS_PIPE_OFFSET_X(x)				(((x) << VIVS_RS_PIPE_OFFSET_X__SHIFT) & VIVS_RS_PIPE_OFFSET_X__MASK)
+#define VIVS_RS_PIPE_OFFSET_Y__MASK				0xffff0000
+#define VIVS_RS_PIPE_OFFSET_Y__SHIFT				16
+#define VIVS_RS_PIPE_OFFSET_Y(x)				(((x) << VIVS_RS_PIPE_OFFSET_Y__SHIFT) & VIVS_RS_PIPE_OFFSET_Y__MASK)
+
+#define VIVS_TS							0x00000000
+
+#define VIVS_TS_FLUSH_CACHE					0x00001650
+#define VIVS_TS_FLUSH_CACHE_FLUSH				0x00000001
+
+#define VIVS_TS_MEM_CONFIG					0x00001654
+#define VIVS_TS_MEM_CONFIG_DEPTH_FAST_CLEAR			0x00000001
+#define VIVS_TS_MEM_CONFIG_COLOR_FAST_CLEAR			0x00000002
+#define VIVS_TS_MEM_CONFIG_DEPTH_16BPP				0x00000008
+#define VIVS_TS_MEM_CONFIG_DEPTH_AUTO_DISABLE			0x00000010
+#define VIVS_TS_MEM_CONFIG_COLOR_AUTO_DISABLE			0x00000020
+#define VIVS_TS_MEM_CONFIG_DEPTH_COMPRESSION			0x00000040
+#define VIVS_TS_MEM_CONFIG_MSAA					0x00000080
+#define VIVS_TS_MEM_CONFIG_MSAA_FORMAT__MASK			0x00000f00
+#define VIVS_TS_MEM_CONFIG_MSAA_FORMAT__SHIFT			8
+#define VIVS_TS_MEM_CONFIG_MSAA_FORMAT_A4R4G4B4			0x00000000
+#define VIVS_TS_MEM_CONFIG_MSAA_FORMAT_A1R5G5B5			0x00000100
+#define VIVS_TS_MEM_CONFIG_MSAA_FORMAT_R5G6B5			0x00000200
+#define VIVS_TS_MEM_CONFIG_MSAA_FORMAT_A8R8G8B8			0x00000300
+#define VIVS_TS_MEM_CONFIG_MSAA_FORMAT_X8R8G8B8			0x00000400
+#define VIVS_TS_MEM_CONFIG_UNK12				0x00001000
+#define VIVS_TS_MEM_CONFIG_HDEPTH_AUTO_DISABLE			0x00002000
+
+#define VIVS_TS_COLOR_STATUS_BASE				0x00001658
+
+#define VIVS_TS_COLOR_SURFACE_BASE				0x0000165c
+
+#define VIVS_TS_COLOR_CLEAR_VALUE				0x00001660
+
+#define VIVS_TS_DEPTH_STATUS_BASE				0x00001664
+
+#define VIVS_TS_DEPTH_SURFACE_BASE				0x00001668
+
+#define VIVS_TS_DEPTH_CLEAR_VALUE				0x0000166c
+
+#define VIVS_TS_DEPTH_AUTO_DISABLE_COUNT			0x00001670
+
+#define VIVS_TS_COLOR_AUTO_DISABLE_COUNT			0x00001674
+
+#define VIVS_TS_HDEPTH_STATUS_BASE				0x000016a4
+
+#define VIVS_TS_HDEPTH_CLEAR_VALUE				0x000016a8
+
+#define VIVS_TS_HDEPTH_SIZE					0x000016ac
+
+#define VIVS_TS_SAMPLER(i0)				       (0x00000000 + 0x4*(i0))
+#define VIVS_TS_SAMPLER__ESIZE					0x00000004
+#define VIVS_TS_SAMPLER__LEN					0x00000008
+
+#define VIVS_TS_SAMPLER_CONFIG(i0)			       (0x00001720 + 0x4*(i0))
+#define VIVS_TS_SAMPLER_CONFIG_ENABLE__MASK			0x00000003
+#define VIVS_TS_SAMPLER_CONFIG_ENABLE__SHIFT			0
+#define VIVS_TS_SAMPLER_CONFIG_ENABLE(x)			(((x) << VIVS_TS_SAMPLER_CONFIG_ENABLE__SHIFT) & VIVS_TS_SAMPLER_CONFIG_ENABLE__MASK)
+#define VIVS_TS_SAMPLER_CONFIG_FORMAT__MASK			0x000000f0
+#define VIVS_TS_SAMPLER_CONFIG_FORMAT__SHIFT			4
+#define VIVS_TS_SAMPLER_CONFIG_FORMAT(x)			(((x) << VIVS_TS_SAMPLER_CONFIG_FORMAT__SHIFT) & VIVS_TS_SAMPLER_CONFIG_FORMAT__MASK)
+
+#define VIVS_TS_SAMPLER_STATUS_BASE(i0)			       (0x00001740 + 0x4*(i0))
+
+#define VIVS_TS_SAMPLER_CLEAR_VALUE(i0)			       (0x00001760 + 0x4*(i0))
+
+#define VIVS_YUV						0x00000000
+
+#define VIVS_YUV_UNK01678					0x00001678
+
+#define VIVS_YUV_UNK0167C					0x0000167c
+
+#define VIVS_YUV_UNK01680					0x00001680
+
+#define VIVS_YUV_UNK01684					0x00001684
+
+#define VIVS_YUV_UNK01688					0x00001688
+
+#define VIVS_YUV_UNK0168C					0x0000168c
+
+#define VIVS_YUV_UNK01690					0x00001690
+
+#define VIVS_YUV_UNK01694					0x00001694
+
+#define VIVS_YUV_UNK01698					0x00001698
+
+#define VIVS_YUV_UNK0169C					0x0000169c
+
+#define VIVS_TE							0x00000000
+
+#define VIVS_TE_SAMPLER(i0)				       (0x00000000 + 0x4*(i0))
+#define VIVS_TE_SAMPLER__ESIZE					0x00000004
+#define VIVS_TE_SAMPLER__LEN					0x0000000c
+
+#define VIVS_TE_SAMPLER_CONFIG0(i0)			       (0x00002000 + 0x4*(i0))
+#define VIVS_TE_SAMPLER_CONFIG0_TYPE__MASK			0x00000007
+#define VIVS_TE_SAMPLER_CONFIG0_TYPE__SHIFT			0
+#define VIVS_TE_SAMPLER_CONFIG0_TYPE(x)				(((x) << VIVS_TE_SAMPLER_CONFIG0_TYPE__SHIFT) & VIVS_TE_SAMPLER_CONFIG0_TYPE__MASK)
+#define VIVS_TE_SAMPLER_CONFIG0_UWRAP__MASK			0x00000018
+#define VIVS_TE_SAMPLER_CONFIG0_UWRAP__SHIFT			3
+#define VIVS_TE_SAMPLER_CONFIG0_UWRAP(x)			(((x) << VIVS_TE_SAMPLER_CONFIG0_UWRAP__SHIFT) & VIVS_TE_SAMPLER_CONFIG0_UWRAP__MASK)
+#define VIVS_TE_SAMPLER_CONFIG0_VWRAP__MASK			0x00000060
+#define VIVS_TE_SAMPLER_CONFIG0_VWRAP__SHIFT			5
+#define VIVS_TE_SAMPLER_CONFIG0_VWRAP(x)			(((x) << VIVS_TE_SAMPLER_CONFIG0_VWRAP__SHIFT) & VIVS_TE_SAMPLER_CONFIG0_VWRAP__MASK)
+#define VIVS_TE_SAMPLER_CONFIG0_MIN__MASK			0x00000180
+#define VIVS_TE_SAMPLER_CONFIG0_MIN__SHIFT			7
+#define VIVS_TE_SAMPLER_CONFIG0_MIN(x)				(((x) << VIVS_TE_SAMPLER_CONFIG0_MIN__SHIFT) & VIVS_TE_SAMPLER_CONFIG0_MIN__MASK)
+#define VIVS_TE_SAMPLER_CONFIG0_MIP__MASK			0x00000600
+#define VIVS_TE_SAMPLER_CONFIG0_MIP__SHIFT			9
+#define VIVS_TE_SAMPLER_CONFIG0_MIP(x)				(((x) << VIVS_TE_SAMPLER_CONFIG0_MIP__SHIFT) & VIVS_TE_SAMPLER_CONFIG0_MIP__MASK)
+#define VIVS_TE_SAMPLER_CONFIG0_MAG__MASK			0x00001800
+#define VIVS_TE_SAMPLER_CONFIG0_MAG__SHIFT			11
+#define VIVS_TE_SAMPLER_CONFIG0_MAG(x)				(((x) << VIVS_TE_SAMPLER_CONFIG0_MAG__SHIFT) & VIVS_TE_SAMPLER_CONFIG0_MAG__MASK)
+#define VIVS_TE_SAMPLER_CONFIG0_FORMAT__MASK			0x0003e000
+#define VIVS_TE_SAMPLER_CONFIG0_FORMAT__SHIFT			13
+#define VIVS_TE_SAMPLER_CONFIG0_FORMAT(x)			(((x) << VIVS_TE_SAMPLER_CONFIG0_FORMAT__SHIFT) & VIVS_TE_SAMPLER_CONFIG0_FORMAT__MASK)
+#define VIVS_TE_SAMPLER_CONFIG0_ROUND_UV			0x00080000
+#define VIVS_TE_SAMPLER_CONFIG0_ENDIAN__MASK			0x00c00000
+#define VIVS_TE_SAMPLER_CONFIG0_ENDIAN__SHIFT			22
+#define VIVS_TE_SAMPLER_CONFIG0_ENDIAN(x)			(((x) << VIVS_TE_SAMPLER_CONFIG0_ENDIAN__SHIFT) & VIVS_TE_SAMPLER_CONFIG0_ENDIAN__MASK)
+#define VIVS_TE_SAMPLER_CONFIG0_ANISOTROPY__MASK		0xff000000
+#define VIVS_TE_SAMPLER_CONFIG0_ANISOTROPY__SHIFT		24
+#define VIVS_TE_SAMPLER_CONFIG0_ANISOTROPY(x)			(((x) << VIVS_TE_SAMPLER_CONFIG0_ANISOTROPY__SHIFT) & VIVS_TE_SAMPLER_CONFIG0_ANISOTROPY__MASK)
+
+#define VIVS_TE_SAMPLER_SIZE(i0)			       (0x00002040 + 0x4*(i0))
+#define VIVS_TE_SAMPLER_SIZE_WIDTH__MASK			0x0000ffff
+#define VIVS_TE_SAMPLER_SIZE_WIDTH__SHIFT			0
+#define VIVS_TE_SAMPLER_SIZE_WIDTH(x)				(((x) << VIVS_TE_SAMPLER_SIZE_WIDTH__SHIFT) & VIVS_TE_SAMPLER_SIZE_WIDTH__MASK)
+#define VIVS_TE_SAMPLER_SIZE_HEIGHT__MASK			0xffff0000
+#define VIVS_TE_SAMPLER_SIZE_HEIGHT__SHIFT			16
+#define VIVS_TE_SAMPLER_SIZE_HEIGHT(x)				(((x) << VIVS_TE_SAMPLER_SIZE_HEIGHT__SHIFT) & VIVS_TE_SAMPLER_SIZE_HEIGHT__MASK)
+
+#define VIVS_TE_SAMPLER_LOG_SIZE(i0)			       (0x00002080 + 0x4*(i0))
+#define VIVS_TE_SAMPLER_LOG_SIZE_WIDTH__MASK			0x000003ff
+#define VIVS_TE_SAMPLER_LOG_SIZE_WIDTH__SHIFT			0
+#define VIVS_TE_SAMPLER_LOG_SIZE_WIDTH(x)			(((x) << VIVS_TE_SAMPLER_LOG_SIZE_WIDTH__SHIFT) & VIVS_TE_SAMPLER_LOG_SIZE_WIDTH__MASK)
+#define VIVS_TE_SAMPLER_LOG_SIZE_HEIGHT__MASK			0x000ffc00
+#define VIVS_TE_SAMPLER_LOG_SIZE_HEIGHT__SHIFT			10
+#define VIVS_TE_SAMPLER_LOG_SIZE_HEIGHT(x)			(((x) << VIVS_TE_SAMPLER_LOG_SIZE_HEIGHT__SHIFT) & VIVS_TE_SAMPLER_LOG_SIZE_HEIGHT__MASK)
+
+#define VIVS_TE_SAMPLER_LOD_CONFIG(i0)			       (0x000020c0 + 0x4*(i0))
+#define VIVS_TE_SAMPLER_LOD_CONFIG_BIAS_ENABLE			0x00000001
+#define VIVS_TE_SAMPLER_LOD_CONFIG_MAX__MASK			0x000007fe
+#define VIVS_TE_SAMPLER_LOD_CONFIG_MAX__SHIFT			1
+#define VIVS_TE_SAMPLER_LOD_CONFIG_MAX(x)			(((x) << VIVS_TE_SAMPLER_LOD_CONFIG_MAX__SHIFT) & VIVS_TE_SAMPLER_LOD_CONFIG_MAX__MASK)
+#define VIVS_TE_SAMPLER_LOD_CONFIG_MIN__MASK			0x001ff800
+#define VIVS_TE_SAMPLER_LOD_CONFIG_MIN__SHIFT			11
+#define VIVS_TE_SAMPLER_LOD_CONFIG_MIN(x)			(((x) << VIVS_TE_SAMPLER_LOD_CONFIG_MIN__SHIFT) & VIVS_TE_SAMPLER_LOD_CONFIG_MIN__MASK)
+#define VIVS_TE_SAMPLER_LOD_CONFIG_BIAS__MASK			0x7fe00000
+#define VIVS_TE_SAMPLER_LOD_CONFIG_BIAS__SHIFT			21
+#define VIVS_TE_SAMPLER_LOD_CONFIG_BIAS(x)			(((x) << VIVS_TE_SAMPLER_LOD_CONFIG_BIAS__SHIFT) & VIVS_TE_SAMPLER_LOD_CONFIG_BIAS__MASK)
+
+#define VIVS_TE_SAMPLER_UNK02100(i0)			       (0x00002100 + 0x4*(i0))
+
+#define VIVS_TE_SAMPLER_UNK02140(i0)			       (0x00002140 + 0x4*(i0))
+
+#define VIVS_TE_SAMPLER_UNK02180(i0)			       (0x00002180 + 0x4*(i0))
+
+#define VIVS_TE_SAMPLER_CONFIG1(i0)			       (0x000021c0 + 0x4*(i0))
+#define VIVS_TE_SAMPLER_CONFIG1_FORMAT_EXT__MASK		0x0000001f
+#define VIVS_TE_SAMPLER_CONFIG1_FORMAT_EXT__SHIFT		0
+#define VIVS_TE_SAMPLER_CONFIG1_FORMAT_EXT(x)			(((x) << VIVS_TE_SAMPLER_CONFIG1_FORMAT_EXT__SHIFT) & VIVS_TE_SAMPLER_CONFIG1_FORMAT_EXT__MASK)
+#define VIVS_TE_SAMPLER_CONFIG1_SWIZZLE_R__MASK			0x00000700
+#define VIVS_TE_SAMPLER_CONFIG1_SWIZZLE_R__SHIFT		8
+#define VIVS_TE_SAMPLER_CONFIG1_SWIZZLE_R(x)			(((x) << VIVS_TE_SAMPLER_CONFIG1_SWIZZLE_R__SHIFT) & VIVS_TE_SAMPLER_CONFIG1_SWIZZLE_R__MASK)
+#define VIVS_TE_SAMPLER_CONFIG1_SWIZZLE_G__MASK			0x00007000
+#define VIVS_TE_SAMPLER_CONFIG1_SWIZZLE_G__SHIFT		12
+#define VIVS_TE_SAMPLER_CONFIG1_SWIZZLE_G(x)			(((x) << VIVS_TE_SAMPLER_CONFIG1_SWIZZLE_G__SHIFT) & VIVS_TE_SAMPLER_CONFIG1_SWIZZLE_G__MASK)
+#define VIVS_TE_SAMPLER_CONFIG1_SWIZZLE_B__MASK			0x00070000
+#define VIVS_TE_SAMPLER_CONFIG1_SWIZZLE_B__SHIFT		16
+#define VIVS_TE_SAMPLER_CONFIG1_SWIZZLE_B(x)			(((x) << VIVS_TE_SAMPLER_CONFIG1_SWIZZLE_B__SHIFT) & VIVS_TE_SAMPLER_CONFIG1_SWIZZLE_B__MASK)
+#define VIVS_TE_SAMPLER_CONFIG1_SWIZZLE_A__MASK			0x00700000
+#define VIVS_TE_SAMPLER_CONFIG1_SWIZZLE_A__SHIFT		20
+#define VIVS_TE_SAMPLER_CONFIG1_SWIZZLE_A(x)			(((x) << VIVS_TE_SAMPLER_CONFIG1_SWIZZLE_A__SHIFT) & VIVS_TE_SAMPLER_CONFIG1_SWIZZLE_A__MASK)
+#define VIVS_TE_SAMPLER_CONFIG1_HALIGN__MASK			0x1c000000
+#define VIVS_TE_SAMPLER_CONFIG1_HALIGN__SHIFT			26
+#define VIVS_TE_SAMPLER_CONFIG1_HALIGN(x)			(((x) << VIVS_TE_SAMPLER_CONFIG1_HALIGN__SHIFT) & VIVS_TE_SAMPLER_CONFIG1_HALIGN__MASK)
+
+#define VIVS_TE_SAMPLER_UNK02200(i0)			       (0x00002200 + 0x4*(i0))
+
+#define VIVS_TE_SAMPLER_UNK02240(i0)			       (0x00002240 + 0x4*(i0))
+
+#define VIVS_TE_SAMPLER_LOD_ADDR(i0, i1)		       (0x00002400 + 0x4*(i0) + 0x40*(i1))
+#define VIVS_TE_SAMPLER_LOD_ADDR__ESIZE				0x00000040
+#define VIVS_TE_SAMPLER_LOD_ADDR__LEN				0x0000000e
+
+#define VIVS_NTE						0x00000000
+
+#define VIVS_NTE_SAMPLER(i0)				       (0x00010000 + 0x4*(i0))
+#define VIVS_NTE_SAMPLER__ESIZE					0x00000004
+#define VIVS_NTE_SAMPLER__LEN					0x00000020
+
+#define VIVS_NTE_SAMPLER_CONFIG0(i0)			       (0x00010000 + 0x4*(i0))
+#define VIVS_NTE_SAMPLER_CONFIG0_TYPE__MASK			0x00000007
+#define VIVS_NTE_SAMPLER_CONFIG0_TYPE__SHIFT			0
+#define VIVS_NTE_SAMPLER_CONFIG0_TYPE(x)			(((x) << VIVS_NTE_SAMPLER_CONFIG0_TYPE__SHIFT) & VIVS_NTE_SAMPLER_CONFIG0_TYPE__MASK)
+#define VIVS_NTE_SAMPLER_CONFIG0_UWRAP__MASK			0x00000018
+#define VIVS_NTE_SAMPLER_CONFIG0_UWRAP__SHIFT			3
+#define VIVS_NTE_SAMPLER_CONFIG0_UWRAP(x)			(((x) << VIVS_NTE_SAMPLER_CONFIG0_UWRAP__SHIFT) & VIVS_NTE_SAMPLER_CONFIG0_UWRAP__MASK)
+#define VIVS_NTE_SAMPLER_CONFIG0_VWRAP__MASK			0x00000060
+#define VIVS_NTE_SAMPLER_CONFIG0_VWRAP__SHIFT			5
+#define VIVS_NTE_SAMPLER_CONFIG0_VWRAP(x)			(((x) << VIVS_NTE_SAMPLER_CONFIG0_VWRAP__SHIFT) & VIVS_NTE_SAMPLER_CONFIG0_VWRAP__MASK)
+#define VIVS_NTE_SAMPLER_CONFIG0_MIN__MASK			0x00000180
+#define VIVS_NTE_SAMPLER_CONFIG0_MIN__SHIFT			7
+#define VIVS_NTE_SAMPLER_CONFIG0_MIN(x)				(((x) << VIVS_NTE_SAMPLER_CONFIG0_MIN__SHIFT) & VIVS_NTE_SAMPLER_CONFIG0_MIN__MASK)
+#define VIVS_NTE_SAMPLER_CONFIG0_MIP__MASK			0x00000600
+#define VIVS_NTE_SAMPLER_CONFIG0_MIP__SHIFT			9
+#define VIVS_NTE_SAMPLER_CONFIG0_MIP(x)				(((x) << VIVS_NTE_SAMPLER_CONFIG0_MIP__SHIFT) & VIVS_NTE_SAMPLER_CONFIG0_MIP__MASK)
+#define VIVS_NTE_SAMPLER_CONFIG0_MAG__MASK			0x00001800
+#define VIVS_NTE_SAMPLER_CONFIG0_MAG__SHIFT			11
+#define VIVS_NTE_SAMPLER_CONFIG0_MAG(x)				(((x) << VIVS_NTE_SAMPLER_CONFIG0_MAG__SHIFT) & VIVS_NTE_SAMPLER_CONFIG0_MAG__MASK)
+#define VIVS_NTE_SAMPLER_CONFIG0_FORMAT__MASK			0x0003e000
+#define VIVS_NTE_SAMPLER_CONFIG0_FORMAT__SHIFT			13
+#define VIVS_NTE_SAMPLER_CONFIG0_FORMAT(x)			(((x) << VIVS_NTE_SAMPLER_CONFIG0_FORMAT__SHIFT) & VIVS_NTE_SAMPLER_CONFIG0_FORMAT__MASK)
+#define VIVS_NTE_SAMPLER_CONFIG0_ROUND_UV			0x00080000
+#define VIVS_NTE_SAMPLER_CONFIG0_ENDIAN__MASK			0x00c00000
+#define VIVS_NTE_SAMPLER_CONFIG0_ENDIAN__SHIFT			22
+#define VIVS_NTE_SAMPLER_CONFIG0_ENDIAN(x)			(((x) << VIVS_NTE_SAMPLER_CONFIG0_ENDIAN__SHIFT) & VIVS_NTE_SAMPLER_CONFIG0_ENDIAN__MASK)
+#define VIVS_NTE_SAMPLER_CONFIG0_ANISOTROPY__MASK		0xff000000
+#define VIVS_NTE_SAMPLER_CONFIG0_ANISOTROPY__SHIFT		24
+#define VIVS_NTE_SAMPLER_CONFIG0_ANISOTROPY(x)			(((x) << VIVS_NTE_SAMPLER_CONFIG0_ANISOTROPY__SHIFT) & VIVS_NTE_SAMPLER_CONFIG0_ANISOTROPY__MASK)
+
+#define VIVS_NTE_SAMPLER_SIZE(i0)			       (0x00010080 + 0x4*(i0))
+#define VIVS_NTE_SAMPLER_SIZE_WIDTH__MASK			0x0000ffff
+#define VIVS_NTE_SAMPLER_SIZE_WIDTH__SHIFT			0
+#define VIVS_NTE_SAMPLER_SIZE_WIDTH(x)				(((x) << VIVS_NTE_SAMPLER_SIZE_WIDTH__SHIFT) & VIVS_NTE_SAMPLER_SIZE_WIDTH__MASK)
+#define VIVS_NTE_SAMPLER_SIZE_HEIGHT__MASK			0xffff0000
+#define VIVS_NTE_SAMPLER_SIZE_HEIGHT__SHIFT			16
+#define VIVS_NTE_SAMPLER_SIZE_HEIGHT(x)				(((x) << VIVS_NTE_SAMPLER_SIZE_HEIGHT__SHIFT) & VIVS_NTE_SAMPLER_SIZE_HEIGHT__MASK)
+
+#define VIVS_NTE_SAMPLER_LOG_SIZE(i0)			       (0x00010100 + 0x4*(i0))
+#define VIVS_NTE_SAMPLER_LOG_SIZE_WIDTH__MASK			0x000003ff
+#define VIVS_NTE_SAMPLER_LOG_SIZE_WIDTH__SHIFT			0
+#define VIVS_NTE_SAMPLER_LOG_SIZE_WIDTH(x)			(((x) << VIVS_NTE_SAMPLER_LOG_SIZE_WIDTH__SHIFT) & VIVS_NTE_SAMPLER_LOG_SIZE_WIDTH__MASK)
+#define VIVS_NTE_SAMPLER_LOG_SIZE_HEIGHT__MASK			0x000ffc00
+#define VIVS_NTE_SAMPLER_LOG_SIZE_HEIGHT__SHIFT			10
+#define VIVS_NTE_SAMPLER_LOG_SIZE_HEIGHT(x)			(((x) << VIVS_NTE_SAMPLER_LOG_SIZE_HEIGHT__SHIFT) & VIVS_NTE_SAMPLER_LOG_SIZE_HEIGHT__MASK)
+
+#define VIVS_NTE_SAMPLER_LOD_CONFIG(i0)			       (0x00010180 + 0x4*(i0))
+#define VIVS_NTE_SAMPLER_LOD_CONFIG_BIAS_ENABLE			0x00000001
+#define VIVS_NTE_SAMPLER_LOD_CONFIG_MAX__MASK			0x000007fe
+#define VIVS_NTE_SAMPLER_LOD_CONFIG_MAX__SHIFT			1
+#define VIVS_NTE_SAMPLER_LOD_CONFIG_MAX(x)			(((x) << VIVS_NTE_SAMPLER_LOD_CONFIG_MAX__SHIFT) & VIVS_NTE_SAMPLER_LOD_CONFIG_MAX__MASK)
+#define VIVS_NTE_SAMPLER_LOD_CONFIG_MIN__MASK			0x001ff800
+#define VIVS_NTE_SAMPLER_LOD_CONFIG_MIN__SHIFT			11
+#define VIVS_NTE_SAMPLER_LOD_CONFIG_MIN(x)			(((x) << VIVS_NTE_SAMPLER_LOD_CONFIG_MIN__SHIFT) & VIVS_NTE_SAMPLER_LOD_CONFIG_MIN__MASK)
+#define VIVS_NTE_SAMPLER_LOD_CONFIG_BIAS__MASK			0x7fe00000
+#define VIVS_NTE_SAMPLER_LOD_CONFIG_BIAS__SHIFT			21
+#define VIVS_NTE_SAMPLER_LOD_CONFIG_BIAS(x)			(((x) << VIVS_NTE_SAMPLER_LOD_CONFIG_BIAS__SHIFT) & VIVS_NTE_SAMPLER_LOD_CONFIG_BIAS__MASK)
+
+#define VIVS_NTE_SAMPLER_UNK10200(i0)			       (0x00010200 + 0x4*(i0))
+
+#define VIVS_NTE_SAMPLER_UNK10280(i0)			       (0x00010280 + 0x4*(i0))
+
+#define VIVS_NTE_SAMPLER_UNK10300(i0)			       (0x00010300 + 0x4*(i0))
+
+#define VIVS_NTE_SAMPLER_CONFIG1(i0)			       (0x00010380 + 0x4*(i0))
+#define VIVS_NTE_SAMPLER_CONFIG1_FORMAT_EXT__MASK		0x0000001f
+#define VIVS_NTE_SAMPLER_CONFIG1_FORMAT_EXT__SHIFT		0
+#define VIVS_NTE_SAMPLER_CONFIG1_FORMAT_EXT(x)			(((x) << VIVS_NTE_SAMPLER_CONFIG1_FORMAT_EXT__SHIFT) & VIVS_NTE_SAMPLER_CONFIG1_FORMAT_EXT__MASK)
+#define VIVS_NTE_SAMPLER_CONFIG1_SWIZZLE_R__MASK		0x00000700
+#define VIVS_NTE_SAMPLER_CONFIG1_SWIZZLE_R__SHIFT		8
+#define VIVS_NTE_SAMPLER_CONFIG1_SWIZZLE_R(x)			(((x) << VIVS_NTE_SAMPLER_CONFIG1_SWIZZLE_R__SHIFT) & VIVS_NTE_SAMPLER_CONFIG1_SWIZZLE_R__MASK)
+#define VIVS_NTE_SAMPLER_CONFIG1_SWIZZLE_G__MASK		0x00007000
+#define VIVS_NTE_SAMPLER_CONFIG1_SWIZZLE_G__SHIFT		12
+#define VIVS_NTE_SAMPLER_CONFIG1_SWIZZLE_G(x)			(((x) << VIVS_NTE_SAMPLER_CONFIG1_SWIZZLE_G__SHIFT) & VIVS_NTE_SAMPLER_CONFIG1_SWIZZLE_G__MASK)
+#define VIVS_NTE_SAMPLER_CONFIG1_SWIZZLE_B__MASK		0x00070000
+#define VIVS_NTE_SAMPLER_CONFIG1_SWIZZLE_B__SHIFT		16
+#define VIVS_NTE_SAMPLER_CONFIG1_SWIZZLE_B(x)			(((x) << VIVS_NTE_SAMPLER_CONFIG1_SWIZZLE_B__SHIFT) & VIVS_NTE_SAMPLER_CONFIG1_SWIZZLE_B__MASK)
+#define VIVS_NTE_SAMPLER_CONFIG1_SWIZZLE_A__MASK		0x00700000
+#define VIVS_NTE_SAMPLER_CONFIG1_SWIZZLE_A__SHIFT		20
+#define VIVS_NTE_SAMPLER_CONFIG1_SWIZZLE_A(x)			(((x) << VIVS_NTE_SAMPLER_CONFIG1_SWIZZLE_A__SHIFT) & VIVS_NTE_SAMPLER_CONFIG1_SWIZZLE_A__MASK)
+#define VIVS_NTE_SAMPLER_CONFIG1_HALIGN__MASK			0x1c000000
+#define VIVS_NTE_SAMPLER_CONFIG1_HALIGN__SHIFT			26
+#define VIVS_NTE_SAMPLER_CONFIG1_HALIGN(x)			(((x) << VIVS_NTE_SAMPLER_CONFIG1_HALIGN__SHIFT) & VIVS_NTE_SAMPLER_CONFIG1_HALIGN__MASK)
+
+#define VIVS_NTE_SAMPLER_UNK10400(i0)			       (0x00010400 + 0x4*(i0))
+
+#define VIVS_NTE_SAMPLER_UNK10480(i0)			       (0x00010480 + 0x4*(i0))
+
+#define VIVS_NTE_SAMPLER_ADDR(i0)			       (0x00010800 + 0x40*(i0))
+#define VIVS_NTE_SAMPLER_ADDR__ESIZE				0x00000040
+#define VIVS_NTE_SAMPLER_ADDR__LEN				0x00000020
+
+#define VIVS_NTE_SAMPLER_ADDR_LOD(i0, i1)		       (0x00010800 + 0x40*(i0) + 0x4*(i1))
+#define VIVS_NTE_SAMPLER_ADDR_LOD__ESIZE			0x00000004
+#define VIVS_NTE_SAMPLER_ADDR_LOD__LEN				0x0000000e
+
+#define VIVS_NTE_UNK12000(i0)				       (0x00012000 + 0x4*(i0))
+#define VIVS_NTE_UNK12000__ESIZE				0x00000004
+#define VIVS_NTE_UNK12000__LEN					0x00000100
+
+#define VIVS_NTE_UNK12400(i0)				       (0x00012400 + 0x4*(i0))
+#define VIVS_NTE_UNK12400__ESIZE				0x00000004
+#define VIVS_NTE_UNK12400__LEN					0x00000100
+
+#define VIVS_SH							0x00000000
+
+#define VIVS_SH_UNK20000(i0)				       (0x00020000 + 0x4*(i0))
+#define VIVS_SH_UNK20000__ESIZE					0x00000004
+#define VIVS_SH_UNK20000__LEN					0x00002000
+
+#define VIVS_SH_INST_MEM(i0)				       (0x0000c000 + 0x4*(i0))
+#define VIVS_SH_INST_MEM__ESIZE					0x00000004
+#define VIVS_SH_INST_MEM__LEN					0x00001000
+
+#define VIVS_SH_UNK0C000_MIRROR(i0)			       (0x00008000 + 0x4*(i0))
+#define VIVS_SH_UNK0C000_MIRROR__ESIZE				0x00000004
+#define VIVS_SH_UNK0C000_MIRROR__LEN				0x00001000
+
+#define VIVS_SH_UNIFORMS(i0)				       (0x00030000 + 0x4*(i0))
+#define VIVS_SH_UNIFORMS__ESIZE					0x00000004
+#define VIVS_SH_UNIFORMS__LEN					0x00000400
+
+
+#endif /* STATE_3D_XML */
diff --git a/src/gallium/targets/dri/Makefile.am b/src/gallium/targets/dri/Makefile.am
index 0527e9f2..e4404cc 100644
--- a/src/gallium/targets/dri/Makefile.am
+++ b/src/gallium/targets/dri/Makefile.am
@@ -91,6 +91,8 @@ include $(top_srcdir)/src/gallium/drivers/vc4/Automake.inc
 
 include $(top_srcdir)/src/gallium/drivers/virgl/Automake.inc
 
+include $(top_srcdir)/src/gallium/drivers/etnaviv/Automake.inc
+
 include $(top_srcdir)/src/gallium/drivers/softpipe/Automake.inc
 include $(top_srcdir)/src/gallium/drivers/llvmpipe/Automake.inc
 include $(top_srcdir)/src/gallium/drivers/swr/Automake.inc
diff --git a/src/gallium/targets/dri/target.c b/src/gallium/targets/dri/target.c
index 01532e2..98dfb15 100644
--- a/src/gallium/targets/dri/target.c
+++ b/src/gallium/targets/dri/target.c
@@ -162,3 +162,14 @@ PUBLIC const __DRIextension **__driDriverGetExtensions_i965(void)
 }
 #endif
 #endif
+
+#if defined(GALLIUM_ETNAVIV)
+
+const __DRIextension **__driDriverGetExtensions_etnaviv(void);
+
+PUBLIC const __DRIextension **__driDriverGetExtensions_etnaviv(void)
+{
+   globalDriverAPI = &galliumdrm_driver_api;
+   return galliumdrm_driver_extensions;
+}
+#endif
diff --git a/src/gallium/winsys/etnaviv/drm/Makefile.am b/src/gallium/winsys/etnaviv/drm/Makefile.am
new file mode 100644
index 0000000..995b709
--- /dev/null
+++ b/src/gallium/winsys/etnaviv/drm/Makefile.am
@@ -0,0 +1,32 @@
+# Copyright © 2012 Intel Corporation
+#
+# Permission is hereby granted, free of charge, to any person obtaining a
+# copy of this software and associated documentation files (the "Software"),
+# to deal in the Software without restriction, including without limitation
+# the rights to use, copy, modify, merge, publish, distribute, sublicense,
+# and/or sell copies of the Software, and to permit persons to whom the
+# Software is furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice (including the next
+# paragraph) shall be included in all copies or substantial portions of the
+# Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+# DEALINGS IN THE SOFTWARE.
+
+include $(top_srcdir)/src/gallium/Automake.inc
+
+AM_CFLAGS = \
+	-I$(top_srcdir)/src/gallium/drivers \
+	$(GALLIUM_CFLAGS) \
+	$(ETNAVIV_CFLAGS)
+
+noinst_LTLIBRARIES = libetnavivdrm.la
+
+libetnavivdrm_la_SOURCES = etnaviv_drm_winsys.c
diff --git a/src/gallium/winsys/etnaviv/drm/etnaviv_drm_public.h b/src/gallium/winsys/etnaviv/drm/etnaviv_drm_public.h
new file mode 100644
index 0000000..b3bb5fd
--- /dev/null
+++ b/src/gallium/winsys/etnaviv/drm/etnaviv_drm_public.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2015 Etnaviv Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Christian Gmeiner <christian.gmeiner at gmail.com>
+ */
+
+#ifndef __ETNA_DRM_PUBLIC_H__
+#define __ETNA_DRM_PUBLIC_H__
+
+struct pipe_screen;
+struct renderonly;
+
+struct pipe_screen *
+etna_drm_screen_create_renderonly(struct renderonly *ro);
+
+struct pipe_screen *
+etna_drm_screen_create(int fd);
+
+#endif
diff --git a/src/gallium/winsys/etnaviv/drm/etnaviv_drm_winsys.c b/src/gallium/winsys/etnaviv/drm/etnaviv_drm_winsys.c
new file mode 100644
index 0000000..d65fc85
--- /dev/null
+++ b/src/gallium/winsys/etnaviv/drm/etnaviv_drm_winsys.c
@@ -0,0 +1,161 @@
+/*
+ * Copyright (c) 2015 Etnaviv Project
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Christian Gmeiner <christian.gmeiner at gmail.com>
+ */
+
+#include <sys/stat.h>
+
+#include "util/u_hash_table.h"
+#include "util/u_memory.h"
+
+#include "etnaviv/etnaviv_screen.h"
+#include "etnaviv_drm_public.h"
+
+#include <stdio.h>
+
+static struct pipe_screen *
+screen_create(struct renderonly *ro)
+{
+   struct etna_device *dev;
+   struct etna_gpu *gpu;
+   uint64_t val;
+   int i;
+
+   dev = etna_device_new_dup(ro->gpu_fd);
+   if (!dev) {
+      fprintf(stderr, "Error creating device\n");
+      return NULL;
+   }
+
+   for (i = 0;; i++) {
+      gpu = etna_gpu_new(dev, i);
+      if (!gpu) {
+         fprintf(stderr, "Error creating gpu\n");
+         return NULL;
+      }
+
+      /* Look for a 3D capable GPU */
+      if (etna_gpu_get_param(gpu, ETNA_GPU_FEATURES_0, &val) == 0 &&
+            val & (1 << 2))
+         break;
+
+      etna_gpu_del(gpu);
+   }
+
+   return etna_screen_create(dev, gpu, ro);
+}
+
+static struct util_hash_table *etna_tab = NULL;
+
+pipe_static_mutex(etna_screen_mutex);
+
+static void
+etna_drm_screen_destroy(struct pipe_screen *pscreen)
+{
+   struct etna_screen *screen = etna_screen(pscreen);
+   boolean destroy;
+
+   pipe_mutex_lock(etna_screen_mutex);
+   destroy = --screen->refcnt == 0;
+   if (destroy) {
+      int fd = etna_device_fd(screen->dev);
+      util_hash_table_remove(etna_tab, intptr_to_pointer(fd));
+   }
+   pipe_mutex_unlock(etna_screen_mutex);
+
+   if (destroy) {
+      pscreen->destroy = screen->winsys_priv;
+      pscreen->destroy(pscreen);
+   }
+}
+
+static unsigned hash_fd(void *key)
+{
+   int fd = pointer_to_intptr(key);
+   struct stat stat;
+
+   fstat(fd, &stat);
+
+   return stat.st_dev ^ stat.st_ino ^ stat.st_rdev;
+}
+
+static int compare_fd(void *key1, void *key2)
+{
+   int fd1 = pointer_to_intptr(key1);
+   int fd2 = pointer_to_intptr(key2);
+   struct stat stat1, stat2;
+
+   fstat(fd1, &stat1);
+   fstat(fd2, &stat2);
+
+   return stat1.st_dev != stat2.st_dev ||
+          stat1.st_ino != stat2.st_ino ||
+          stat1.st_rdev != stat2.st_rdev;
+}
+
+struct pipe_screen *
+etna_drm_screen_create_renderonly(struct renderonly *ro)
+{
+   struct pipe_screen *pscreen = NULL;
+
+   pipe_mutex_lock(etna_screen_mutex);
+   if (!etna_tab) {
+      etna_tab = util_hash_table_create(hash_fd, compare_fd);
+      if (!etna_tab)
+         goto unlock;
+   }
+
+   pscreen = util_hash_table_get(etna_tab, intptr_to_pointer(ro->gpu_fd));
+   if (pscreen) {
+      etna_screen(pscreen)->refcnt++;
+   } else {
+      pscreen = screen_create(ro);
+      if (pscreen) {
+         int fd = etna_device_fd(etna_screen(pscreen)->dev);
+         util_hash_table_set(etna_tab, intptr_to_pointer(fd), pscreen);
+
+         /* Bit of a hack, to avoid circular linkage dependency,
+         * ie. pipe driver having to call in to winsys, we
+         * override the pipe drivers screen->destroy() */
+         etna_screen(pscreen)->winsys_priv = pscreen->destroy;
+      pscreen->destroy = etna_drm_screen_destroy;
+      }
+   }
+
+unlock:
+   pipe_mutex_unlock(etna_screen_mutex);
+   return pscreen;
+}
+
+struct pipe_screen *
+etna_drm_screen_create(int fd)
+{
+   struct renderonly ro = {
+      .create_for_resource = renderonly_create_gpu_import_for_resource,
+      .kms_fd = -1,
+      .gpu_fd = fd
+   };
+
+   return etna_drm_screen_create_renderonly(&ro);
+}
-- 
2.9.3



More information about the etnaviv mailing list