summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorThe etnaviv authors <etnaviv@lists.freedesktop.org>2016-12-23 20:58:23 +0100
committerEmil Velikov <emil.l.velikov@gmail.com>2017-01-12 19:27:11 +0000
commitc9e8b49b885242d84ba031dacef5aa4a5ac1e5b6 (patch)
treec3ecc9ff62fedf193cb157b01426295ba4630f47 /src
parent848b49b288fc2fa942418d12829db2e559ad4916 (diff)
etnaviv: gallium driver for Vivante GPUs
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@gmail.com> Signed-off-by: Lucas Stach <l.stach@pengutronix.de> Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de> Signed-off-by: Rob Herring <robh@kernel.org> Signed-off-by: Russell King <rmk@arm.linux.org.uk> Signed-off-by: Wladimir J. van der Laan <laanwj@gmail.com> Acked-by: Emil Velikov <emil.velikov@collabora.com>
Diffstat (limited to 'src')
-rw-r--r--src/gallium/Makefile.am4
-rw-r--r--src/gallium/auxiliary/pipe-loader/pipe_loader_drm.c5
-rw-r--r--src/gallium/auxiliary/target-helpers/drm_helper.h22
-rw-r--r--src/gallium/auxiliary/target-helpers/drm_helper_public.h3
-rw-r--r--src/gallium/drivers/etnaviv/.gitignore1
-rw-r--r--src/gallium/drivers/etnaviv/Automake.inc11
-rw-r--r--src/gallium/drivers/etnaviv/Makefile.am44
-rw-r--r--src/gallium/drivers/etnaviv/Makefile.sources49
-rw-r--r--src/gallium/drivers/etnaviv/README13
-rw-r--r--src/gallium/drivers/etnaviv/etnaviv_asm.c107
-rw-r--r--src/gallium/drivers/etnaviv/etnaviv_asm.h133
-rw-r--r--src/gallium/drivers/etnaviv/etnaviv_blend.c109
-rw-r--r--src/gallium/drivers/etnaviv/etnaviv_blend.h52
-rw-r--r--src/gallium/drivers/etnaviv/etnaviv_clear_blit.c640
-rw-r--r--src/gallium/drivers/etnaviv/etnaviv_clear_blit.h48
-rw-r--r--src/gallium/drivers/etnaviv/etnaviv_compiler.c2532
-rw-r--r--src/gallium/drivers/etnaviv/etnaviv_compiler.h120
-rw-r--r--src/gallium/drivers/etnaviv/etnaviv_compiler_cmdline.c146
-rw-r--r--src/gallium/drivers/etnaviv/etnaviv_context.c323
-rw-r--r--src/gallium/drivers/etnaviv/etnaviv_context.h194
-rw-r--r--src/gallium/drivers/etnaviv/etnaviv_debug.h79
-rw-r--r--src/gallium/drivers/etnaviv/etnaviv_disasm.c612
-rw-r--r--src/gallium/drivers/etnaviv/etnaviv_disasm.h40
-rw-r--r--src/gallium/drivers/etnaviv/etnaviv_emit.c770
-rw-r--r--src/gallium/drivers/etnaviv/etnaviv_emit.h123
-rw-r--r--src/gallium/drivers/etnaviv/etnaviv_fence.c87
-rw-r--r--src/gallium/drivers/etnaviv/etnaviv_fence.h39
-rw-r--r--src/gallium/drivers/etnaviv/etnaviv_format.c268
-rw-r--r--src/gallium/drivers/etnaviv/etnaviv_format.h47
-rw-r--r--src/gallium/drivers/etnaviv/etnaviv_internal.h259
-rw-r--r--src/gallium/drivers/etnaviv/etnaviv_query.c120
-rw-r--r--src/gallium/drivers/etnaviv/etnaviv_query.h64
-rw-r--r--src/gallium/drivers/etnaviv/etnaviv_query_sw.c123
-rw-r--r--src/gallium/drivers/etnaviv/etnaviv_query_sw.h47
-rw-r--r--src/gallium/drivers/etnaviv/etnaviv_rasterizer.c81
-rw-r--r--src/gallium/drivers/etnaviv/etnaviv_rasterizer.h57
-rw-r--r--src/gallium/drivers/etnaviv/etnaviv_resource.c438
-rw-r--r--src/gallium/drivers/etnaviv/etnaviv_resource.h148
-rw-r--r--src/gallium/drivers/etnaviv/etnaviv_rs.c127
-rw-r--r--src/gallium/drivers/etnaviv/etnaviv_rs.h86
-rw-r--r--src/gallium/drivers/etnaviv/etnaviv_screen.c813
-rw-r--r--src/gallium/drivers/etnaviv/etnaviv_screen.h95
-rw-r--r--src/gallium/drivers/etnaviv/etnaviv_shader.c285
-rw-r--r--src/gallium/drivers/etnaviv/etnaviv_shader.h45
-rw-r--r--src/gallium/drivers/etnaviv/etnaviv_state.c664
-rw-r--r--src/gallium/drivers/etnaviv/etnaviv_state.h52
-rw-r--r--src/gallium/drivers/etnaviv/etnaviv_surface.c152
-rw-r--r--src/gallium/drivers/etnaviv/etnaviv_surface.h55
-rw-r--r--src/gallium/drivers/etnaviv/etnaviv_texture.c338
-rw-r--r--src/gallium/drivers/etnaviv/etnaviv_texture.h75
-rw-r--r--src/gallium/drivers/etnaviv/etnaviv_tiling.c96
-rw-r--r--src/gallium/drivers/etnaviv/etnaviv_tiling.h56
-rw-r--r--src/gallium/drivers/etnaviv/etnaviv_transfer.c355
-rw-r--r--src/gallium/drivers/etnaviv/etnaviv_transfer.h35
-rw-r--r--src/gallium/drivers/etnaviv/etnaviv_translate.h516
-rw-r--r--src/gallium/drivers/etnaviv/etnaviv_uniforms.c118
-rw-r--r--src/gallium/drivers/etnaviv/etnaviv_uniforms.h45
-rw-r--r--src/gallium/drivers/etnaviv/etnaviv_util.h108
-rw-r--r--src/gallium/drivers/etnaviv/etnaviv_zsa.c123
-rw-r--r--src/gallium/drivers/etnaviv/etnaviv_zsa.h52
-rw-r--r--src/gallium/drivers/etnaviv/hw/cmdstream.xml.h270
-rw-r--r--src/gallium/drivers/etnaviv/hw/common.xml.h320
-rw-r--r--src/gallium/drivers/etnaviv/hw/isa.xml.h239
-rw-r--r--src/gallium/drivers/etnaviv/hw/state.xml.h397
-rw-r--r--src/gallium/drivers/etnaviv/hw/state_3d.xml.h1231
-rw-r--r--src/gallium/targets/dri/Makefile.am2
-rw-r--r--src/gallium/targets/dri/target.c11
-rw-r--r--src/gallium/winsys/etnaviv/drm/Makefile.am32
-rw-r--r--src/gallium/winsys/etnaviv/drm/etnaviv_drm_public.h39
-rw-r--r--src/gallium/winsys/etnaviv/drm/etnaviv_drm_winsys.c162
70 files changed, 14952 insertions, 0 deletions
diff --git a/src/gallium/Makefile.am b/src/gallium/Makefile.am
index 34671ca88d..9e47e9f5a4 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 2b7ab2757a..99d9da6fd0 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 90820d3fe9..e056c58ba9 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 d1f9382a6f..73cf1da073 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 0000000000..5199dad4a3
--- /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 0000000000..f9b39567e3
--- /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 0000000000..654671133e
--- /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)
+
+noinst_PROGRAMS = etnaviv_compiler
+
+etnaviv_compiler_SOURCES = \
+ etnaviv_compiler_cmdline.c
+
+etnaviv_compiler_LDADD = \
+ libetnaviv.la \
+ $(top_builddir)/src/gallium/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 0000000000..ded3a31106
--- /dev/null
+++ b/src/gallium/drivers/etnaviv/Makefile.sources
@@ -0,0 +1,49 @@
+C_SOURCES := \
+ etnaviv_asm.c \
+ etnaviv_asm.h \
+ etnaviv_blend.c \
+ etnaviv_blend.h \
+ etnaviv_clear_blit.c \
+ etnaviv_clear_blit.h \
+ etnaviv_compiler.c \
+ etnaviv_compiler.h \
+ etnaviv_context.c \
+ etnaviv_context.h \
+ etnaviv_debug.h \
+ etnaviv_disasm.c \
+ etnaviv_disasm.h \
+ etnaviv_emit.c \
+ etnaviv_emit.h \
+ etnaviv_fence.c \
+ etnaviv_fence.h \
+ etnaviv_format.c \
+ etnaviv_format.h \
+ etnaviv_query.c \
+ etnaviv_query.h \
+ etnaviv_query_sw.c \
+ etnaviv_query_sw.h \
+ etnaviv_rasterizer.c \
+ etnaviv_rasterizer.h \
+ etnaviv_resource.c \
+ etnaviv_resource.h \
+ etnaviv_rs.c \
+ etnaviv_rs.h \
+ etnaviv_screen.c \
+ etnaviv_screen.h \
+ etnaviv_shader.c \
+ etnaviv_shader.h \
+ etnaviv_state.c \
+ etnaviv_state.h \
+ etnaviv_surface.c \
+ etnaviv_surface.h \
+ etnaviv_texture.c \
+ etnaviv_texture.h \
+ etnaviv_tiling.c \
+ etnaviv_tiling.h \
+ etnaviv_transfer.c \
+ etnaviv_transfer.h \
+ etnaviv_uniforms.c \
+ etnaviv_uniforms.h \
+ etnaviv_utils.h \
+ etnaviv_zsa.c \
+ etnaviv_zsa.h
diff --git a/src/gallium/drivers/etnaviv/README b/src/gallium/drivers/etnaviv/README
new file mode 100644
index 0000000000..58034b56ea
--- /dev/null
+++ b/src/gallium/drivers/etnaviv/README
@@ -0,0 +1,13 @@
+Notes for the etnaviv gallium driver
+------------------------------------
+
+There are two ways how this driver might get used:
+
+- application opens kms device (kmscube, weston, ..)
+- X via xf86-video-armada
+
+For the kms device case we provide a renderonly based driver like
+imx where all the magic for buffer import and export between kms
+and renderonly GPU is handled automaticly.
+
+For X/xf86-video-armada we need to provide etnaviv_dri.so.
diff --git a/src/gallium/drivers/etnaviv/etnaviv_asm.c b/src/gallium/drivers/etnaviv/etnaviv_asm.c
new file mode 100644
index 0000000000..7d6270ca1f
--- /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@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 0000000000..2fe23df8d4
--- /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@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 0000000000..ebef75daa7
--- /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@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 0000000000..54e7bab0f8
--- /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@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 0000000000..6c61ad5fae
--- /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@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 0000000000..73d07044b2
--- /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@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 0000000000..59e1452d80
--- /dev/null
+++ b/src/gallium/drivers/etnaviv/etnaviv_compiler.c
@@ -0,0 +1,2532 @@
+/*
+ * 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@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_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(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 0000000000..d3101096f9
--- /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@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 0000000000..6f241d19e5
--- /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@freedesktop.org>
+ * Christian Gmeiner <christian.gmeiner@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 0000000000..d767cd1f38
--- /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@gmail.com>
+ * Christian Gmeiner <christian.gmeiner@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 0000000000..74e93e1631
--- /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@gmail.com>
+ * Christian Gmeiner <christian.gmeiner@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 0000000000..cfda52bb32
--- /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 0000000000..918d24eb46
--- /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@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 0000000000..15df612bb6
--- /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@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 0000000000..7eeeda57b6
--- /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@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 0000000000..6a3c77286d
--- /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@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 0000000000..02f520b8b3
--- /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@gmail.com>
+ * Rob Clark <robclark@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 0000000000..cd91d2e19e
--- /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@gmail.com>
+ * Rob Clark <robclark@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 0000000000..0794603b2f
--- /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@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 0000000000..549dfda689
--- /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@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 0000000000..fa75c3e936
--- /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 0000000000..b33e580463
--- /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@freedesktop.org>
+ * Christian Gmeiner <christian.gmeiner@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 0000000000..9a8d579e18
--- /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@freedesktop.org>
+ * Christian Gmeiner <christian.gmeiner@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 0000000000..d6420d9608
--- /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@freedesktop.org>
+ * Christian Gmeiner <christian.gmeiner@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 0000000000..9de2bc60f9
--- /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@freedesktop.org>
+ * Christian Gmeiner <christian.gmeiner@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 0000000000..4990fd1802
--- /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 0000000000..d715dd08de
--- /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@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 0000000000..aefe65bf0e
--- /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@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 0000000000..a9b288e708
--- /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@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 0000000000..295ca10cf2
--- /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@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 0000000000..ec5b659ccd
--- /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@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 0000000000..7dd3ccab21
--- /dev/null
+++ b/src/gallium/drivers/etnaviv/etnaviv_screen.c
@@ -0,0 +1,813 @@
+/*
+ * 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@gmail.com>
+ * Christian Gmeiner <christian.gmeiner@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:
+ case PIPE_CAP_GLSL_OPTIMIZE_CONSERVATIVELY:
+ 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 0000000000..c33a9e32fa
--- /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@gmail.com>
+ * Christian Gmeiner <christian.gmeiner@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 0000000000..88953116e6
--- /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@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 0000000000..b3093705c7
--- /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@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 0000000000..2256261c42
--- /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@gmail.com>
+ * Christian Gmeiner <christian.gmeiner@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 0000000000..a1db9f7896
--- /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@gmail.com>
+ * Christian Gmeiner <christian.gmeiner@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 0000000000..a0013a48bc
--- /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@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 0000000000..e8cfd209af
--- /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@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 0000000000..6b64de2d8e
--- /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@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 0000000000..a7a67fc246
--- /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@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 0000000000..f4f85c1d6e
--- /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@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 0000000000..3c69e22463
--- /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@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 0000000000..1a5aa7fc04
--- /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@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 0000000000..ca156a476f
--- /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@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 0000000000..d0623db147
--- /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 0000000000..70e5d58ecb
--- /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@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 0000000000..83a3a4983f
--- /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@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 0000000000..62f62548d2
--- /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 0000000000..7caba279b3
--- /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@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 0000000000..953a6a78bf
--- /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@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 0000000000..c5275db065
--- /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@gmail.com>
+- Christian Gmeiner <christian.gmeiner@gmail.com>
+- Lucas Stach <l.stach@pengutronix.de>
+- Russell King <rmk@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 0000000000..8d8ef7d4fc
--- /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@gmail.com>
+- Christian Gmeiner <christian.gmeiner@gmail.com>
+- Lucas Stach <l.stach@pengutronix.de>
+- Russell King <rmk@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 0000000000..70cc74a93e
--- /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@gmail.com>
+- Christian Gmeiner <christian.gmeiner@gmail.com>
+- Lucas Stach <l.stach@pengutronix.de>
+- Russell King <rmk@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 0000000000..d9bb9c4eab
--- /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@gmail.com>
+- Christian Gmeiner <christian.gmeiner@gmail.com>
+- Lucas Stach <l.stach@pengutronix.de>
+- Russell King <rmk@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 0000000000..41bbd0c2dd
--- /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@gmail.com>
+- Christian Gmeiner <christian.gmeiner@gmail.com>
+- Lucas Stach <l.stach@pengutronix.de>
+- Russell King <rmk@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 0527e9f2b1..e4404cc50e 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 01532e242b..98dfb15dbd 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 0000000000..995b709599
--- /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 0000000000..b3bb5fd7ef
--- /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@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 0000000000..3b34c300ad
--- /dev/null
+++ b/src/gallium/winsys/etnaviv/drm/etnaviv_drm_winsys.c
@@ -0,0 +1,162 @@
+/*
+ * 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@gmail.com>
+ */
+
+#include <sys/stat.h>
+
+#include "util/u_hash_table.h"
+#include "util/u_memory.h"
+
+#include "etnaviv/etnaviv_screen.h"
+#include "etnaviv/hw/common.xml.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 */
+ int ret = etna_gpu_get_param(gpu, ETNA_GPU_FEATURES_0, &val);
+ if (ret == 0 && (val & chipFeatures_PIPE_3D))
+ 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);
+}