diff options
author | The etnaviv authors <etnaviv@lists.freedesktop.org> | 2016-12-23 20:58:23 +0100 |
---|---|---|
committer | Emil Velikov <emil.l.velikov@gmail.com> | 2017-01-12 19:27:11 +0000 |
commit | c9e8b49b885242d84ba031dacef5aa4a5ac1e5b6 (patch) | |
tree | c3ecc9ff62fedf193cb157b01426295ba4630f47 | |
parent | 848b49b288fc2fa942418d12829db2e559ad4916 (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>
71 files changed, 14962 insertions, 1 deletions
diff --git a/configure.ac b/configure.ac index d1ffb57f57..efac67c756 100644 --- a/configure.ac +++ b/configure.ac @@ -76,6 +76,7 @@ LIBDRM_NVVIEUX_REQUIRED=2.4.66 LIBDRM_NOUVEAU_REQUIRED=2.4.66 LIBDRM_FREEDRENO_REQUIRED=2.4.74 LIBDRM_VC4_REQUIRED=2.4.69 +LIBDRM_ETNAVIV_REQUIRED=2.4.74 DRI2PROTO_REQUIRED=2.6 DRI3PROTO_REQUIRED=1.0 PRESENTPROTO_REQUIRED=1.0 @@ -1233,7 +1234,7 @@ GALLIUM_DRIVERS_DEFAULT="r300,r600,svga,swrast" AC_ARG_WITH([gallium-drivers], [AS_HELP_STRING([--with-gallium-drivers@<:@=DIRS...@:>@], [comma delimited Gallium drivers list, e.g. - "i915,ilo,nouveau,r300,r600,radeonsi,freedreno,svga,swrast,vc4,virgl" + "i915,ilo,nouveau,r300,r600,radeonsi,freedreno,svga,swrast,vc4,virgl,etnaviv" @<:@default=r300,r600,svga,swrast@:>@])], [with_gallium_drivers="$withval"], [with_gallium_drivers="$GALLIUM_DRIVERS_DEFAULT"]) @@ -2506,6 +2507,11 @@ if test -n "$with_gallium_drivers"; then PKG_CHECK_MODULES([FREEDRENO], [libdrm_freedreno >= $LIBDRM_FREEDRENO_REQUIRED]) require_libdrm "freedreno" ;; + xetnaviv) + HAVE_GALLIUM_ETNAVIV=yes + PKG_CHECK_MODULES([ETNAVIV], [libdrm_etnaviv >= $LIBDRM_ETNAVIV_REQUIRED]) + require_libdrm "etnaviv" + ;; xswrast) HAVE_GALLIUM_SOFTPIPE=yes if test "x$MESA_LLVM" = x1 && test "x$enable_gallium_llvm" == "xyes"; then @@ -2624,6 +2630,7 @@ AM_CONDITIONAL(HAVE_GALLIUM_RADEON_COMMON, test "x$HAVE_GALLIUM_R600" = xyes -o "x$HAVE_GALLIUM_RADEONSI" = xyes) AM_CONDITIONAL(HAVE_GALLIUM_NOUVEAU, test "x$HAVE_GALLIUM_NOUVEAU" = xyes) AM_CONDITIONAL(HAVE_GALLIUM_FREEDRENO, test "x$HAVE_GALLIUM_FREEDRENO" = xyes) +AM_CONDITIONAL(HAVE_GALLIUM_ETNAVIV, test "x$HAVE_GALLIUM_ETNAVIV" = xyes) AM_CONDITIONAL(HAVE_GALLIUM_SOFTPIPE, test "x$HAVE_GALLIUM_SOFTPIPE" = xyes) AM_CONDITIONAL(HAVE_GALLIUM_LLVMPIPE, test "x$HAVE_GALLIUM_LLVMPIPE" = xyes) AM_CONDITIONAL(HAVE_GALLIUM_SWR, test "x$HAVE_GALLIUM_SWR" = xyes) @@ -2777,6 +2784,7 @@ AC_CONFIG_FILES([Makefile src/gallium/drivers/svga/Makefile src/gallium/drivers/swr/Makefile src/gallium/drivers/trace/Makefile + src/gallium/drivers/etnaviv/Makefile src/gallium/drivers/vc4/Makefile src/gallium/drivers/virgl/Makefile src/gallium/state_trackers/clover/Makefile @@ -2806,6 +2814,7 @@ AC_CONFIG_FILES([Makefile src/gallium/targets/xvmc/Makefile src/gallium/tests/trivial/Makefile src/gallium/tests/unit/Makefile + src/gallium/winsys/etnaviv/drm/Makefile src/gallium/winsys/freedreno/drm/Makefile src/gallium/winsys/i915/drm/Makefile src/gallium/winsys/intel/drm/Makefile diff --git a/src/gallium/Makefile.am b/src/gallium/Makefile.am index 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, ©_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, ©_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 = ®s[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); +} |