[Mesa-dev] [RFC PATCH 08/17] eir: add nir compiler and all its infrastructure
Christian Gmeiner
christian.gmeiner at gmail.com
Fri May 10 09:09:06 UTC 2019
Signed-off-by: Christian Gmeiner <christian.gmeiner at gmail.com>
---
src/etnaviv/compiler/eir_compiler.c | 61 ++
src/etnaviv/compiler/eir_compiler.h | 29 +
src/etnaviv/compiler/eir_compiler_nir.c | 1035 +++++++++++++++++++++++
src/etnaviv/compiler/eir_shader.c | 312 +++++++
src/etnaviv/compiler/eir_shader.h | 203 +++++
src/etnaviv/compiler/meson.build | 4 +
6 files changed, 1644 insertions(+)
create mode 100644 src/etnaviv/compiler/eir_compiler.c
create mode 100644 src/etnaviv/compiler/eir_compiler_nir.c
create mode 100644 src/etnaviv/compiler/eir_shader.c
create mode 100644 src/etnaviv/compiler/eir_shader.h
diff --git a/src/etnaviv/compiler/eir_compiler.c b/src/etnaviv/compiler/eir_compiler.c
new file mode 100644
index 00000000000..386dcd0b0bc
--- /dev/null
+++ b/src/etnaviv/compiler/eir_compiler.c
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2018 Etnaviv Project
+ * Copyright (C) 2018 Zodiac Inflight Innovations
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Christian Gmeiner <christian.gmeiner at gmail.com>
+ */
+
+#include "eir.h"
+#include "eir_compiler.h"
+#include "util/ralloc.h"
+#include "util/u_debug.h"
+
+static const struct debug_named_value shader_debug_options[] = {
+ {"disasm", EIR_DBG_DISASM, "Dump NIR and etnaviv shader disassembly"},
+ {"optmsgs", EIR_DBG_OPTMSGS,"Enable optimizer debug messages"},
+ DEBUG_NAMED_VALUE_END
+};
+
+DEBUG_GET_ONCE_FLAGS_OPTION(eir_compiler_debug, "EIR_COMPILER_DEBUG", shader_debug_options, 0)
+
+enum eir_compiler_debug eir_compiler_debug = 0;
+
+struct eir_compiler *
+eir_compiler_create(void)
+{
+ struct eir_compiler *compiler = rzalloc(NULL, struct eir_compiler);
+
+ if (!compiler)
+ return NULL;
+
+ eir_compiler_debug = debug_get_option_eir_compiler_debug();
+ compiler->set = eir_ra_alloc_reg_set(compiler);
+
+ return compiler;
+}
+
+void
+eir_compiler_free(const struct eir_compiler *compiler)
+{
+ ralloc_free((void *)compiler);
+}
diff --git a/src/etnaviv/compiler/eir_compiler.h b/src/etnaviv/compiler/eir_compiler.h
index 5c5412e4773..645ee6a0db2 100644
--- a/src/etnaviv/compiler/eir_compiler.h
+++ b/src/etnaviv/compiler/eir_compiler.h
@@ -28,7 +28,21 @@
#ifndef H_EIR_COMPILER
#define H_EIR_COMPILER
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
struct eir_ra_reg_set;
+struct eir_shader_variant;
+
+enum eir_compiler_debug {
+ EIR_DBG_DISASM = (1 << 0),
+ EIR_DBG_OPTMSGS = (1 << 1),
+};
+
+extern enum eir_compiler_debug eir_compiler_debug;
/**
* Compiler state saved across compiler invocations, for any expensive global
@@ -36,6 +50,21 @@ struct eir_ra_reg_set;
*/
struct eir_compiler {
struct eir_ra_reg_set *set;
+ uint32_t shader_count;
};
+struct eir_compiler *
+eir_compiler_create(void);
+
+void
+eir_compiler_free(const struct eir_compiler *compiler);
+
+int
+eir_compile_shader_nir(struct eir_compiler *compiler,
+ struct eir_shader_variant *v);
+
+#ifdef __cplusplus
+}
+#endif
+
#endif // H_EIR_COMPILER
diff --git a/src/etnaviv/compiler/eir_compiler_nir.c b/src/etnaviv/compiler/eir_compiler_nir.c
new file mode 100644
index 00000000000..862f34390e0
--- /dev/null
+++ b/src/etnaviv/compiler/eir_compiler_nir.c
@@ -0,0 +1,1035 @@
+/*
+ * Copyright (c) 2018 Etnaviv Project
+ * Copyright (C) 2018 Zodiac Inflight Innovations
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Christian Gmeiner <christian.gmeiner at gmail.com>
+ */
+
+#include "compiler/nir/nir.h"
+#include "eir.h"
+#include "eir_compiler.h"
+#include "eir_nir.h"
+#include "eir_shader.h"
+#include "gc/gc_instr.h"
+#include "util/u_debug.h"
+#include "util/u_math.h"
+#include "util/u_memory.h"
+#include "util/ralloc.h"
+
+struct eir_context
+{
+ struct eir_compiler *compiler;
+ struct nir_shader *s;
+ struct eir *ir;
+ struct eir_shader_variant *variant;
+ struct eir_block *block;
+ bool error;
+
+ unsigned uniforms;
+ struct eir_register *nir_locals;
+ struct eir_register *nir_ssa_values;
+};
+
+#define DBG(compiler, fmt, ...) \
+ do { \
+ debug_printf("%s:%d: " fmt "\n", __FUNCTION__, __LINE__, \
+ ##__VA_ARGS__); \
+ } while (0)
+
+static struct eir_context *
+compile_init(struct eir_compiler *compiler,
+ struct eir_shader_variant *v)
+{
+ struct eir_context *ctx = rzalloc(NULL, struct eir_context);
+
+ ctx->compiler = compiler;
+
+ nir_shader *s = nir_shader_clone(ctx, v->shader->nir);
+ ctx->ir = eir_create();
+ ctx->ir->uniform_offset = s->num_uniforms * 4;
+ ctx->s = s;
+ ctx->variant = v;
+
+ /* reset to sane values */
+ v->fs_color_out_reg = -1;
+ v->fs_depth_out_reg = -1;
+ v->vs_pointsize_out_reg = -1;
+ v->vs_pos_out_reg = -1;
+
+ ctx->block = eir_block_create(ctx->ir);
+
+ return ctx;
+}
+
+static void
+compile_free(struct eir_context *ctx)
+{
+ ralloc_free(ctx);
+}
+
+static void
+compile_error(struct eir_context *ctx, const char *format, ...)
+{
+ va_list ap;
+
+ va_start(ap, format);
+ _debug_vprintf(format, ap);
+ va_end(ap);
+
+ nir_print_shader(ctx->s, stdout);
+
+ ctx->error = true;
+ debug_assert(0);
+}
+
+#define compile_assert(ctx, cond) do { \
+ if (!(cond)) compile_error((ctx), "failed assert: "#cond"\n"); \
+ } while (0)
+
+static struct eir_register
+get_nir_dest(struct eir_context *ctx, const nir_dest *dest)
+{
+ if (dest->is_ssa) {
+ struct eir_register dst = eir_temp_register(ctx->ir, dest->ssa.num_components);
+
+ ctx->nir_ssa_values[dest->ssa.index] = dst;
+ return dst;
+ } else {
+ return ctx->nir_locals[dest->reg.reg->index];
+ }
+}
+
+/**
+ * Construct an identity swizzle for the set of enabled channels given by \p
+ * mask. The result will only reference channels enabled in the provided \p
+ * mask, assuming that \p mask is non-zero.
+ */
+static inline unsigned
+eir_swizzle_for_mask(unsigned mask)
+{
+ unsigned last = (mask ? ffs(mask) - 1 : 0);
+ unsigned swz[4];
+
+ for (unsigned i = 0; i < 4; i++)
+ last = swz[i] = (mask & (1 << i) ? i : last);
+
+ return INST_SWIZ(swz[0], swz[1], swz[2], swz[3]);
+}
+
+/**
+ * Construct an identity swizzle for the first \p n components of a vector.
+ */
+static inline unsigned
+eir_swizzle_for_size(unsigned n)
+{
+ return eir_swizzle_for_mask((1 << n) - 1);
+}
+
+static struct eir_register
+get_nir_src(const struct eir_context *ctx, const nir_src *src,
+ unsigned num_components)
+{
+ nir_const_value *const_value = nir_src_as_const_value(*src);
+ struct eir_register reg;
+
+ if (const_value) {
+ assert(src->is_ssa);
+ uint32_t c[src->ssa->num_components];
+
+ nir_const_value_to_array(c, const_value, src->ssa->num_components, u32);
+
+ return eir_uniform_register_vec4_ui(ctx->ir, src->ssa->num_components, c);
+ }
+
+ if (src->is_ssa)
+ reg = ctx->nir_ssa_values[src->ssa->index];
+ else
+ reg = ctx->nir_locals[src->reg.reg->index];
+
+ reg.swizzle = eir_swizzle_for_size(num_components);
+
+ return reg;
+}
+
+static inline unsigned
+eir_writemask_for_size(unsigned n)
+{
+ return (1 << n) - 1;
+}
+
+static inline unsigned
+eir_swizzle_for_nir_swizzle(const uint8_t swizzle[4])
+{
+ return INST_SWIZ(swizzle[0], swizzle[1], swizzle[2], swizzle[3]);
+}
+
+static inline void
+nir_alu_src_to_eir(const struct eir_context *ctx, const nir_alu_src *src, struct eir_register *reg)
+{
+ *reg = get_nir_src(ctx, &src->src, 4);
+ reg->swizzle = eir_swizzle_for_nir_swizzle(src->swizzle);
+ reg->abs = src->abs;
+ reg->neg = src->negate;
+}
+
+static void
+emit_alu(struct eir_context *ctx, nir_alu_instr *alu)
+{
+ const nir_op_info *info = &nir_op_infos[alu->op];
+
+ struct eir_instruction *instr = NULL;
+ struct eir_register src[3] = { };
+
+ struct eir_register dst;
+ dst = get_nir_dest(ctx, &alu->dest.dest);
+ dst.writemask = alu->dest.write_mask;
+
+ for (unsigned i = 0; i < info->num_inputs; i++)
+ nir_alu_src_to_eir(ctx, &alu->src[i], &src[i]);
+
+ switch (alu->op) {
+ case nir_op_f2i32:
+ /* nothing to do - first seen when TGSI uses ARL opc */
+ break;
+
+ case nir_op_fmov:
+ instr = eir_MOV(ctx->block, &dst, &src[0]);
+ break;
+
+ case nir_op_fadd:
+ instr = eir_ADD(ctx->block, &dst, &src[0], &src[1]);
+ break;
+
+ case nir_op_fceil:
+ instr = eir_CEIL(ctx->block, &dst, &src[0]);
+ break;
+
+ case nir_op_fddx:
+ instr = eir_DSX(ctx->block, &dst, &src[0]);
+ break;
+
+ case nir_op_fddy:
+ instr = eir_DSY(ctx->block, &dst, &src[0]);
+ break;
+
+ case nir_op_fdot2:
+ /* fall-through */
+ case nir_op_fdot3:
+ /* fall-through */
+ case nir_op_fdot4:
+ unreachable("Should be lowered by fdot_replicates = true");
+ break;
+
+ case nir_op_fdot_replicated2:
+ instr = eir_DP2(ctx->block, &dst, &src[0], &src[1]);
+ break;
+
+ case nir_op_fdot_replicated3:
+ instr = eir_DP3(ctx->block, &dst, &src[0], &src[1]);
+ break;
+
+ case nir_op_fdot_replicated4:
+ instr = eir_DP4(ctx->block, &dst, &src[0], &src[1]);
+ break;
+
+ case nir_op_fexp2:
+ instr = eir_EXP(ctx->block, &dst, &src[0]);
+ break;
+
+ case nir_op_ffloor:
+ instr = eir_FLOOR(ctx->block, &dst, &src[0]);
+ break;
+
+ case nir_op_ffma:
+ instr = eir_MAD(ctx->block, &dst, &src[0], &src[1], &src[2]);
+ break;
+
+ case nir_op_ffract:
+ instr = eir_FRC(ctx->block, &dst, &src[0]);
+ break;
+
+ case nir_op_flog2:
+ /* TODO: new vs. old hw */
+ instr = eir_LOG(ctx->block, &dst, &src[0]);
+ break;
+
+ case nir_op_flrp:
+ unreachable("not reached: should be lowered by lower_flrp32 = true");
+ break;
+
+ case nir_op_fmax:
+ instr = eir_SELECT(ctx->block, &dst, &src[0], &src[1], &src[0]);
+ instr->gc.condition = GC_COND_LT;
+ break;
+
+ case nir_op_fmin:
+ instr = eir_SELECT(ctx->block, &dst, &src[0], &src[1], &src[2]);
+ instr->gc.condition = GC_COND_GT;
+ break;
+
+ case nir_op_fmul:
+ instr = eir_MUL(ctx->block, &dst, &src[0], &src[1]);
+ break;
+
+ case nir_op_fabs:
+ /* fall-through */
+ case nir_op_fneg:
+ /* fall-through */
+ case nir_op_fsat:
+ unreachable("not reached: should be lowered by lower_source mods");
+ break;
+
+ case nir_op_fpow:
+ unreachable("not reached: should be lowered by lower_fpow = true");
+ break;
+
+ case nir_op_frcp:
+ instr = eir_RCP(ctx->block, &dst, &src[0]);
+ break;
+
+ case nir_op_frsq:
+ instr = eir_RSQ(ctx->block, &dst, &src[0]);
+ break;
+
+ case nir_op_fcsel:
+ instr = eir_SELECT(ctx->block, &dst, &src[0], &src[1], &src[2]);
+ instr->gc.condition = GC_COND_NZ;
+ break;
+
+ case nir_op_fcos:
+ case nir_op_fsin: {
+ struct eir_register tmp = eir_temp_register(ctx->ir, 4);
+ struct eir_register m_2_pi = eir_uniform_register_f(ctx->ir, M_2_PI);
+
+ eir_MUL(ctx->block, &tmp, &src[0], &m_2_pi);
+
+ if (alu->op == nir_op_fsin)
+ instr = eir_SIN(ctx->block, &dst, &tmp);
+ else
+ instr = eir_COS(ctx->block, &dst, &tmp);
+ }
+ break;
+
+ case nir_op_fsqrt:
+ instr = eir_SQRT(ctx->block, &dst, &src[0]);
+ break;
+
+ case nir_op_ftrunc:
+ unreachable("not reached: should be lowered by lower_ftrunc = true");
+ break;
+
+ case nir_op_i2f32:
+ case nir_op_u2f32:
+ instr = eir_MOV(ctx->block, &dst, &src[0]);
+ break;
+
+ case nir_op_seq:
+ instr = eir_SET(ctx->block, &dst, &src[0], GC_COND_EQ, &src[1]);
+ break;
+
+ case nir_op_sge:
+ instr = eir_SET(ctx->block, &dst, &src[0], GC_COND_GE, &src[1]);
+ break;
+
+ case nir_op_slt:
+ instr = eir_SET(ctx->block, &dst, &src[0], GC_COND_LT, &src[1]);
+ break;
+
+ case nir_op_sne:
+ instr = eir_SET(ctx->block, &dst, &src[0], GC_COND_NE, &src[1]);
+ break;
+
+ case nir_op_b2f32:
+ /* fall-through */
+ case nir_op_b2i32:
+ /* fall-through */
+ case nir_op_f2b1:
+ /* fall-through */
+ case nir_op_i2b1:
+ /* fall-through */
+ case nir_op_flt:
+ /* fall-through */
+ case nir_op_fge:
+ /* fall-through */
+ case nir_op_feq:
+ /* fall-through */
+ case nir_op_fne:
+ /* fall-through */
+ case nir_op_ilt:
+ /* fall-through */
+ case nir_op_ige:
+ /* fall-through */
+ case nir_op_ieq:
+ /* fall-through */
+ case nir_op_ine:
+ /* fall-through */
+ case nir_op_ult:
+ /* fall-through */
+ case nir_op_uge:
+ /* fall-through */
+ case nir_op_ball_fequal2:
+ /* fall-through */
+ case nir_op_ball_fequal3:
+ /* fall-through */
+ case nir_op_ball_fequal4:
+ /* fall-through */
+ case nir_op_bany_fnequal2:
+ /* fall-through */
+ case nir_op_bany_fnequal3:
+ /* fall-through */
+ case nir_op_bany_fnequal4:
+ /* fall-through */
+ case nir_op_ball_iequal2:
+ /* fall-through */
+ case nir_op_ball_iequal3:
+ /* fall-through */
+ case nir_op_ball_iequal4:
+ /* fall-through */
+ case nir_op_bany_inequal2:
+ /* fall-through */
+ case nir_op_bany_inequal3:
+ /* fall-through */
+ case nir_op_bany_inequal4:
+ /* fall-through */
+ case nir_op_bcsel:
+ /* fall-through */
+ case nir_op_imov:
+ /* fall-through */
+ case nir_op_iand:
+ /* fall-through */
+ case nir_op_ixor:
+ /* fall-through */
+ case nir_op_ior:
+ /* fall-through */
+ case nir_op_inot:
+ unreachable("not reached: should be lowered by nir_lower_bool_to_float");
+ break;
+
+ default:
+ compile_error(ctx, "Unhandled ALU op: %s\n", info->name);
+ break;
+ }
+
+ if (instr)
+ instr->gc.saturate = alu->dest.saturate;
+}
+
+static void
+emit_intrinsic(struct eir_context *ctx, nir_intrinsic_instr *instr)
+{
+ const nir_intrinsic_info *info = &nir_intrinsic_infos[instr->intrinsic];
+
+ switch (instr->intrinsic) {
+ case nir_intrinsic_discard:
+ eir_TEXKILL(ctx->block);
+ break;
+
+ case nir_intrinsic_load_input: {
+ nir_const_value *const_offset = nir_src_as_const_value(instr->src[0]);
+ assert(const_offset);
+
+ struct eir_register src = {
+ .index = instr->const_index[0] + const_offset->u32,
+ .type = EIR_REG_TEMP,
+ };
+
+ ctx->nir_ssa_values[instr->dest.ssa.index] = src;
+ break;
+ }
+
+ case nir_intrinsic_load_uniform: {
+ if (nir_src_is_const(instr->src[0])) {
+ const unsigned load_offset = nir_src_as_uint(instr->src[0]);
+
+ /* Offsets are in bytes but they should always be multiples of 4 */
+ assert(load_offset % 4 == 0);
+
+ struct eir_register src = {
+ .index = instr->const_index[0],
+ .type = EIR_REG_UNIFORM,
+ };
+
+ ctx->nir_ssa_values[instr->dest.ssa.index] = src;
+ } else {
+ compile_error(ctx, "indirect load_uniform not supported yet\n");
+ }
+
+ break;
+ }
+
+ case nir_intrinsic_store_output: {
+ /* no support for indirect outputs */
+ nir_const_value *const_offset = nir_src_as_const_value(instr->src[1]);
+ assert(const_offset);
+
+ const int idx = nir_intrinsic_base(instr);
+ struct eir_register src = get_nir_src(ctx, &instr->src[0], instr->num_components);
+
+ struct eir_register dst = {
+ .index = idx,
+ .type = EIR_REG_TEMP,
+ .writemask = eir_writemask_for_size(instr->num_components),
+ };
+
+ eir_MOV(ctx->block, &dst, &src);
+
+ break;
+ }
+
+ case nir_intrinsic_nop:
+ eir_NOP(ctx->block);
+ break;
+
+ default:
+ compile_error(ctx, "Unhandled intrinsic type: %s\n", info->name);
+ break;
+ }
+}
+
+static void
+emit_tex(struct eir_context *ctx, nir_tex_instr *tex)
+{
+ const nir_op_info *info = &nir_op_infos[tex->op];
+ struct eir_register sampler;
+ struct eir_register coordinate;
+ struct eir_register bias;
+ MAYBE_UNUSED struct eir_register lod;
+
+ struct eir_register dst;
+ dst = get_nir_dest(ctx, &tex->dest);
+ dst.writemask = INST_COMPS_X | INST_COMPS_Y | INST_COMPS_Z | INST_COMPS_W;
+
+ sampler.type = EIR_REG_SAMPLER;
+ sampler.index = tex->texture_index;
+ sampler.swizzle = INST_SWIZ_IDENTITY;
+ /* TODO: amode */
+
+ for (unsigned i = 0; i < tex->num_srcs; i++) {
+ const unsigned src_size = nir_tex_instr_src_size(tex, i);
+
+ switch (tex->src[i].src_type) {
+ case nir_tex_src_coord:
+ coordinate = get_nir_src(ctx, &tex->src[i].src, src_size);
+ coordinate.swizzle = INST_SWIZ_IDENTITY;
+ break;
+
+ case nir_tex_src_projector:
+ unreachable("Should be lowered by nir_lower_tex");
+ break;
+
+ case nir_tex_src_bias:
+ bias = get_nir_src(ctx, &tex->src[i].src, src_size);
+ break;
+
+ case nir_tex_src_lod:
+ lod = get_nir_src(ctx, &tex->src[i].src, src_size);
+ break;
+
+ default:
+ compile_error(ctx, "Unhandled NIR tex src type: %d\n",
+ tex->src[i].src_type);
+ return;
+ }
+ }
+
+ switch (tex->op) {
+ case nir_texop_tex:
+ eir_TEXLD(ctx->block, &dst, &sampler, &coordinate);
+ break;
+
+ case nir_texop_txb:
+ eir_TEXLDB(ctx->block, &dst, &sampler, &bias);
+ break;
+
+ case nir_texop_txl:
+ eir_TEXLDL(ctx->block, &dst, &sampler, &coordinate);
+ break;
+
+ case nir_texop_txs: {
+ const int dest_size = nir_tex_instr_dest_size(tex);
+ const unsigned unit = tex->texture_index;
+
+ assert(dest_size < 3);
+
+ const uint32_t v[] = {
+ unit,
+ unit,
+ unit,
+ };
+
+ const enum eir_uniform_contents c[] = {
+ EIR_UNIFORM_IMAGE_WIDTH,
+ EIR_UNIFORM_IMAGE_HEIGHT,
+ EIR_UNIFORM_IMAGE_DEPTH,
+ };
+
+ /* we do not support lod yet */
+ assert(nir_tex_instr_src_index(tex, nir_tex_src_lod) == 0);
+
+ struct eir_register size = eir_uniform_register_vec4(ctx->ir, 3, c, v);
+
+ /* TODO: get rid of mov and use uniform directly */
+ eir_MOV(ctx->block, &dst, &size);
+ }
+ break;
+
+ default:
+ compile_error(ctx, "Unhandled NIR tex op: %d\n", info->name);
+ break;
+ }
+}
+
+static void
+emit_jump(struct eir_context *ctx, nir_jump_instr *jump)
+{
+ compile_error(ctx, "Unhandled NIR jump type: %d\n", jump->type);
+}
+
+static void
+emit_undef(struct eir_context *ctx, nir_ssa_undef_instr *undef)
+{
+ ctx->nir_ssa_values[undef->def.index] = eir_temp_register(ctx->ir, undef->def.num_components);
+}
+
+static void
+emit_instr(struct eir_context *ctx, nir_instr *instr)
+{
+ switch (instr->type) {
+ case nir_instr_type_alu:
+ emit_alu(ctx, nir_instr_as_alu(instr));
+ break;
+ case nir_instr_type_intrinsic:
+ emit_intrinsic(ctx, nir_instr_as_intrinsic(instr));
+ break;
+ case nir_instr_type_load_const:
+ /* dealt with when using nir_src */
+ break;
+ case nir_instr_type_tex:
+ emit_tex(ctx, nir_instr_as_tex(instr));
+ break;
+ case nir_instr_type_jump:
+ emit_jump(ctx, nir_instr_as_jump(instr));
+ break;
+ case nir_instr_type_ssa_undef:
+ emit_undef(ctx, nir_instr_as_ssa_undef(instr));
+ break;
+ case nir_instr_type_phi:
+ /* we have converted phi webs to regs in NIR by now */
+ compile_error(ctx, "Unexpected NIR instruction type: %d\n", instr->type);
+ break;
+ case nir_instr_type_deref:
+ case nir_instr_type_call:
+ case nir_instr_type_parallel_copy:
+ compile_error(ctx, "Unhandled NIR instruction type: %d\n", instr->type);
+ break;
+ }
+}
+
+static void emit_cf_list(struct eir_context *ctx, struct exec_list *list);
+
+static void
+emit_block(struct eir_context *ctx, nir_block *nblock)
+{
+ nir_foreach_instr(instr, nblock) {
+ emit_instr(ctx, instr);
+ if (ctx->error)
+ return;
+ }
+}
+
+static void
+emit_if(struct eir_context *ctx, nir_if *nif)
+{
+ nir_block *nir_else_block = nir_if_first_else_block(nif);
+ bool empty_else_block = (nir_else_block == nir_if_last_else_block(nif) &&
+ exec_list_is_empty(&nir_else_block->instr_list));
+
+ struct eir_block *then_block = eir_block_create(ctx->ir);
+ struct eir_block *after_block = eir_block_create(ctx->ir);
+ struct eir_block *else_block = NULL;
+
+ if (empty_else_block)
+ else_block = after_block;
+ else
+ else_block = eir_block_create(ctx->ir);
+
+ eir_link_blocks(ctx->block, else_block);
+ eir_link_blocks(ctx->block, then_block);
+
+ assert(nif->condition.is_ssa);
+ assert(nif->condition.ssa->parent_instr->type == nir_instr_type_alu);
+
+ nir_alu_instr *parent_alu = nir_instr_as_alu(nif->condition.ssa->parent_instr);
+
+ struct eir_register src0, src1;
+ nir_alu_src_to_eir(ctx, &parent_alu->src[0], &src0);
+ nir_alu_src_to_eir(ctx, &parent_alu->src[1], &src1);
+
+ struct eir_instruction *instr = eir_BRANCH(ctx->block, &src0, &src1);
+
+ switch (parent_alu->op) {
+ case nir_op_feq:
+ case nir_op_seq:
+ instr->gc.condition = GC_COND_NE;
+ break;
+
+ case nir_op_fne:
+ case nir_op_sne:
+ instr->gc.condition = GC_COND_EQ;
+ break;
+
+ case nir_op_flt:
+ case nir_op_slt:
+ instr->gc.condition = GC_COND_GT;
+ break;
+
+ case nir_op_fge:
+ case nir_op_sge:
+ instr->gc.condition = GC_COND_LE;
+ break;
+
+ default:
+ unreachable("not supported opc");
+ }
+
+ ctx->block = then_block;
+ eir_link_blocks(ctx->block, after_block);
+ emit_cf_list(ctx, &nif->then_list);
+
+ if (!empty_else_block) {
+ ctx->block = else_block;
+ emit_cf_list(ctx, &nif->else_list);
+
+ eir_link_blocks(ctx->block, after_block);
+ eir_link_blocks(ctx->block, else_block);
+ }
+
+ ctx->block = after_block;
+}
+
+static void
+emit_loop(struct eir_context *ctx, nir_loop *nloop)
+{
+ emit_cf_list(ctx, &nloop->body);
+
+ ctx->variant->num_loops++;
+}
+
+static void
+emit_cf_list(struct eir_context *ctx, struct exec_list *list)
+{
+ foreach_list_typed(nir_cf_node, node, node, list) {
+ switch (node->type) {
+ case nir_cf_node_block:
+ emit_block(ctx, nir_cf_node_as_block(node));
+ break;
+ case nir_cf_node_if:
+ emit_if(ctx, nir_cf_node_as_if(node));
+ break;
+ case nir_cf_node_loop:
+ emit_loop(ctx, nir_cf_node_as_loop(node));
+ break;
+ case nir_cf_node_function:
+ compile_error(ctx, "TODO\n");
+ break;
+ }
+ }
+}
+
+static void
+emit_function(struct eir_context *ctx, nir_function_impl *impl)
+{
+ emit_cf_list(ctx, &impl->body);
+}
+
+static void
+setup_input(struct eir_context *ctx, nir_variable *in)
+{
+ unsigned array_len = MAX2(glsl_get_length(in->type), 1);
+ unsigned ncomp = glsl_get_components(in->type);
+ unsigned n = in->data.driver_location;
+ unsigned slot = in->data.location;
+
+ DBG(ctx->compiler, "; in: slot=%u, len=%ux%u, drvloc=%u",
+ slot, array_len, ncomp, n);
+
+ compile_assert(ctx, n < ARRAY_SIZE(ctx->ir->inputs));
+
+ if (ctx->s->info.stage == MESA_SHADER_FRAGMENT) {
+ eir_assign_input(ctx->ir, n, slot, ncomp);
+ } else if (ctx->s->info.stage == MESA_SHADER_VERTEX) {
+ eir_assign_input(ctx->ir, n, slot, ncomp);
+ } else {
+ compile_error(ctx, "unknown shader type: %d\n", ctx->s->info.stage);
+ }
+}
+
+static void
+setup_output(struct eir_context *ctx, nir_variable *out)
+{
+ unsigned array_len = MAX2(glsl_get_length(out->type), 1);
+ unsigned ncomp = glsl_get_components(out->type);
+ unsigned n = out->data.driver_location;
+ unsigned slot = out->data.location;
+
+ DBG(ctx->compiler, "; out: slot=%u, len=%ux%u, drvloc=%u",
+ slot, array_len, ncomp, n);
+
+ compile_assert(ctx, n < ARRAY_SIZE(ctx->ir->outputs));
+
+ if (ctx->s->info.stage == MESA_SHADER_FRAGMENT) {
+ switch (slot) {
+ case FRAG_RESULT_DEPTH:
+ eir_assign_output(ctx->ir, n, slot, ncomp);
+ break;
+
+ case FRAG_RESULT_COLOR:
+ eir_assign_output(ctx->ir, n, slot, ncomp);
+ break;
+
+ default:
+ if (slot >= FRAG_RESULT_DATA0) {
+ eir_assign_output(ctx->ir, n, slot, ncomp);
+ break;
+ }
+
+ compile_error(ctx, "unknown FS output name: %s\n",
+ gl_frag_result_name(slot));
+ }
+ } else if (ctx->s->info.stage == MESA_SHADER_VERTEX) {
+ switch (slot) {
+ case VARYING_SLOT_POS:
+ eir_assign_output(ctx->ir, n, slot, ncomp);
+ break;
+
+ case VARYING_SLOT_PSIZ:
+ eir_assign_output(ctx->ir, n, slot, ncomp);
+ break;
+
+ case VARYING_SLOT_COL0:
+ eir_assign_output(ctx->ir, n, slot, ncomp);
+ break;
+
+ default:
+ if (slot >= VARYING_SLOT_VAR0) {
+ eir_assign_output(ctx->ir, n, slot, ncomp);
+ break;
+ }
+
+ if ((VARYING_SLOT_TEX0 <= slot) && (slot <= VARYING_SLOT_TEX7)) {
+ eir_assign_output(ctx->ir, n, slot, ncomp);
+ break;
+ }
+
+ compile_error(ctx, "unknown VS output name: %s\n",
+ gl_varying_slot_name(slot));
+ }
+ } else {
+ compile_error(ctx, "unknown shader type: %d\n", ctx->s->info.stage);
+ }
+}
+
+static int
+max_drvloc(struct exec_list *vars)
+{
+ int drvloc = -1;
+
+ nir_foreach_variable(var, vars)
+ drvloc = MAX2(drvloc, (int)var->data.driver_location);
+
+ return drvloc;
+}
+
+static void
+emit_instructions(struct eir_context *ctx)
+{
+ const unsigned ninputs = max_drvloc(&ctx->s->inputs) + 1;
+ const unsigned noutputs = max_drvloc(&ctx->s->outputs) + 1;
+
+ // keep t0..tn registers reserved for inputs and outputs
+ const unsigned reserved = MAX2(ninputs, noutputs);
+ for (unsigned i = 0; i < reserved; i++)
+ eir_temp_register(ctx->ir, 4);
+
+ nir_function_impl *fxn = nir_shader_get_entrypoint(ctx->s);
+
+ ctx->nir_locals = ralloc_array(ctx, struct eir_register, fxn->reg_alloc);
+ ctx->nir_ssa_values = ralloc_array(ctx, struct eir_register, fxn->ssa_alloc);
+
+ foreach_list_typed(nir_register, reg, node, &fxn->registers) {
+ assert(reg->num_array_elems == 0);
+ assert(reg->bit_size == 32);
+
+ ctx->nir_locals[reg->index] = eir_temp_register(ctx->ir, 4);
+ }
+
+ if (ctx->s->num_uniforms > 0)
+ ctx->uniforms = ctx->s->num_uniforms / 16;
+
+ nir_foreach_variable(var, &ctx->s->inputs)
+ setup_input(ctx, var);
+
+ nir_foreach_variable(var, &ctx->s->outputs)
+ setup_output(ctx, var);
+
+ emit_function(ctx, fxn);
+}
+
+static void
+setup_special_vert_register(const struct eir *ir, unsigned i, struct eir_shader_variant *v)
+{
+ const int reg = ir->outputs[i].reg;
+
+ switch (ir->outputs[i].slot) {
+ case VARYING_SLOT_POS:
+ v->vs_pos_out_reg = reg;
+ break;
+ default:
+ /* nothing to do */
+ break;
+ }
+}
+
+static void
+setup_special_frag_register(const struct eir *ir, unsigned i, struct eir_shader_variant *v)
+{
+ const int reg = ir->outputs[i].reg;
+
+ switch (ir->outputs[i].slot) {
+ case FRAG_RESULT_DEPTH:
+ v->fs_depth_out_reg = reg;
+ break;
+ case FRAG_RESULT_COLOR:
+ v->fs_color_out_reg = reg;
+ break;
+ default:
+ /* nothing to do */
+ break;
+ }
+}
+
+static void
+setup_shader_io(struct eir_context *ctx, struct eir_shader_variant *v)
+{
+ const struct eir *ir = ctx->ir;
+
+ for (unsigned i = 0; i < ir->num_inputs; i++) {
+ v->inputs[i].reg = ir->inputs[i].reg;
+ v->inputs[i].slot = ir->inputs[i].slot;
+ v->inputs[i].ncomp = ir->inputs[i].ncomp;
+
+ /* TODO:
+ v->inputs[n].interpolate = in->data.interpolation;
+ */
+ }
+
+ for (unsigned i = 0; i < ir->num_outputs; i++) {
+ v->outputs[i].reg = ir->outputs[i].reg;
+ v->outputs[i].slot = ir->outputs[i].slot;
+ v->outputs[i].ncomp = ir->outputs[i].ncomp;
+
+ if (v->shader->type == MESA_SHADER_VERTEX)
+ setup_special_vert_register(ir, i, v);
+ else if (v->shader->type == MESA_SHADER_FRAGMENT)
+ setup_special_frag_register(ir, i, v);
+ }
+
+ v->num_inputs = ir->num_inputs;
+ v->num_outputs = ir->num_outputs;
+}
+
+int
+eir_compile_shader_nir(struct eir_compiler *compiler,
+ struct eir_shader_variant *v)
+{
+ int ret = 0;
+ struct eir_context *ctx;
+ bool success;
+
+ assert(!v->ir);
+ assert(v->shader->mem_ctx);
+
+ ctx = compile_init(compiler, v);
+ if (!ctx) {
+ DBG(compiler, "INIT failed!");
+ ret = -1;
+ goto out;
+ }
+
+ v->ir = ctx->ir;
+
+ emit_instructions(ctx);
+
+ if (ctx->error) {
+ DBG(compiler, "EMIT failed!");
+ ret = -1;
+ goto out;
+ }
+
+ if (eir_compiler_debug & EIR_DBG_OPTMSGS) {
+ printf("AFTER emitting:\n");
+ eir_print(ctx->ir);
+ }
+
+ eir_legalize(ctx->ir);
+ if (eir_compiler_debug & EIR_DBG_OPTMSGS) {
+ printf("AFTER legalization:\n");
+ eir_print(ctx->ir);
+ }
+
+ eir_calculate_live_intervals(ctx->ir);
+ if (eir_compiler_debug & EIR_DBG_OPTMSGS) {
+ printf("AFTER live-ranges:\n");
+ eir_print(ctx->ir);
+ }
+
+ success = eir_register_allocate(ctx->ir, v->shader->type, ctx->compiler);
+ if (!success) {
+ DBG(compiler, "RA failed!");
+ ret = -1;
+ goto out;
+ }
+
+ if (eir_compiler_debug & EIR_DBG_OPTMSGS) {
+ printf("AFTER RA:\n");
+ eir_print(ctx->ir);
+ }
+
+ setup_shader_io(ctx, v);
+
+ v->num_temps = ctx->ir->num_temps;
+ v->const_size = ctx->ir->uniform_offset;
+
+ util_dynarray_clone(&v->uniforms, v->shader->mem_ctx, &ctx->ir->uniform_alloc);
+
+out:
+ if (ret) {
+ if (v->ir)
+ eir_destroy(v->ir);
+ v->ir = NULL;
+ }
+
+ compile_free(ctx);
+
+ return ret;
+}
diff --git a/src/etnaviv/compiler/eir_shader.c b/src/etnaviv/compiler/eir_shader.c
new file mode 100644
index 00000000000..7ad40be5cc6
--- /dev/null
+++ b/src/etnaviv/compiler/eir_shader.c
@@ -0,0 +1,312 @@
+/*
+ * Copyright (c) 2018 Etnaviv Project
+ * Copyright (C) 2018 Zodiac Inflight Innovations
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Christian Gmeiner <christian.gmeiner at gmail.com>
+ */
+
+#include "compiler/nir/nir.h"
+#include "eir_compiler.h"
+#include "eir_nir.h"
+#include "eir_shader.h"
+#include "gc/gc_disasm.h"
+
+#include "util/u_memory.h"
+#include "util/ralloc.h"
+
+static inline bool
+eir_shader_key_equal(struct eir_shader_key *a, struct eir_shader_key *b)
+{
+ STATIC_ASSERT(sizeof(struct eir_shader_key) <= sizeof(a->global));
+
+ return a->global == b->global;
+}
+
+static void
+delete_variant(struct eir_shader_variant *v)
+{
+ if (v->ir)
+ eir_destroy(v->ir);
+
+ if (v->code)
+ free(v->code);
+
+ FREE(v);
+}
+
+static inline void
+assemble_variant(struct eir_shader_variant *v)
+{
+ v->code = eir_assemble(v->ir, &v->info);
+
+ /* no need to keep the ir around beyond this point */
+ eir_destroy(v->ir);
+ v->ir = NULL;
+}
+
+static struct eir_shader_variant *
+create_variant(struct eir_shader *shader, struct eir_shader_key key)
+{
+ struct eir_shader_variant *v = CALLOC_STRUCT(eir_shader_variant);
+ int ret;
+
+ nir_print_shader(shader->nir, stdout);
+
+ if (!v)
+ return NULL;
+
+ v->id = shader->variant_count++;
+ v->shader = shader;
+ v->key = key;
+
+ ret = eir_compile_shader_nir(shader->compiler, v);
+ if (ret) {
+ debug_error("compile failed!");
+ goto fail;
+ }
+
+ assemble_variant(v);
+ if (!v->code) {
+ debug_error("assemble failed!");
+ goto fail;
+ }
+
+ return v;
+
+fail:
+ delete_variant(v);
+ return NULL;
+}
+
+/**
+ * Returns the minimum number of vec4 elements needed to pack a type.
+ *
+ * For simple types, it will return 1 (a single vec4); for matrices, the
+ * number of columns; for array and struct, the sum of the vec4_size of
+ * each of its elements; and for sampler and atomic, zero.
+ *
+ * This method is useful to calculate how much register space is needed to
+ * store a particular type.
+ */
+static int
+eir_type_size_vec4(const struct glsl_type *type, bool bindless)
+{
+ switch (glsl_get_base_type(type)) {
+ case GLSL_TYPE_UINT:
+ case GLSL_TYPE_INT:
+ case GLSL_TYPE_FLOAT:
+ case GLSL_TYPE_FLOAT16:
+ case GLSL_TYPE_BOOL:
+ case GLSL_TYPE_DOUBLE:
+ case GLSL_TYPE_UINT16:
+ case GLSL_TYPE_INT16:
+ case GLSL_TYPE_UINT8:
+ case GLSL_TYPE_INT8:
+ case GLSL_TYPE_UINT64:
+ case GLSL_TYPE_INT64:
+ if (glsl_type_is_matrix(type)) {
+ const struct glsl_type *col_type = glsl_get_column_type(type);
+ unsigned col_slots = glsl_type_is_dual_slot(col_type) ? 2 : 1;
+ return glsl_get_matrix_columns(type) * col_slots;
+ } else {
+ /* Regardless of size of vector, it gets a vec4. This is bad
+ * packing for things like floats, but otherwise arrays become a
+ * mess. Hopefully a later pass over the code can pack scalars
+ * down if appropriate.
+ */
+ return glsl_type_is_dual_slot(type) ? 2 : 1;
+ }
+ case GLSL_TYPE_ARRAY:
+ assert(glsl_get_length(type) > 0);
+ return eir_type_size_vec4(glsl_get_array_element(type), bindless) * glsl_get_length(type);
+ case GLSL_TYPE_STRUCT:
+ case GLSL_TYPE_SUBROUTINE:
+ case GLSL_TYPE_SAMPLER:
+ case GLSL_TYPE_ATOMIC_UINT:
+ case GLSL_TYPE_IMAGE:
+ case GLSL_TYPE_VOID:
+ case GLSL_TYPE_ERROR:
+ case GLSL_TYPE_INTERFACE:
+ case GLSL_TYPE_FUNCTION:
+ default:
+ unreachable("todo");
+ }
+
+ return 0;
+}
+
+struct eir_shader *
+eir_shader_from_nir(struct eir_compiler *compiler, struct nir_shader *nir)
+{
+ struct eir_shader *shader = CALLOC_STRUCT(eir_shader);
+
+ assert(compiler);
+
+ shader->mem_ctx = ralloc_context(NULL);
+ shader->compiler = compiler;
+ shader->id = shader->compiler->shader_count++;
+ shader->type = nir->info.stage;
+
+ NIR_PASS_V(nir, nir_lower_io, nir_var_all, eir_type_size_vec4,
+ (nir_lower_io_options)0);
+
+ shader->nir = eir_optimize_nir(nir);
+
+ return shader;
+}
+
+void
+eir_shader_destroy(struct eir_shader *shader)
+{
+ struct eir_shader_variant *v, *t;
+
+ assert(shader);
+
+ v = shader->variants;
+ while (v) {
+ t = v;
+ v = v->next;
+ delete_variant(t);
+ }
+
+ ralloc_free(shader->nir);
+ ralloc_free(shader->mem_ctx);
+ FREE(shader);
+}
+
+struct eir_shader_variant *
+eir_shader_get_variant(struct eir_shader *shader, struct eir_shader_key key, bool *created)
+{
+ struct eir_shader_variant *v;
+
+ *created = false;
+
+ for (v = shader->variants; v; v = v->next)
+ if (eir_shader_key_equal(&key, &v->key))
+ return v;
+
+ /* compile new variant if it doesn't exist already */
+ v = create_variant(shader, key);
+ if (v) {
+ v->next = shader->variants;
+ shader->variants = v;
+ *created = true;
+ }
+
+ return v;
+}
+
+static const char *
+swizzle_names[4] =
+{
+ "x",
+ "y",
+ "z",
+ "w"
+};
+
+void
+eir_dump_shader(struct eir_shader_variant *v)
+{
+ assert(v);
+ assert(v->shader);
+ assert((v->info.sizedwords % 2) == 0);
+ unsigned i;
+
+ printf("%s\n", _mesa_shader_stage_to_string(v->shader->type));
+
+ struct gc_string decoded = {
+ .string = (char *)rzalloc_size(NULL, 1),
+ .offset = 0,
+ };
+
+ for (i = 0; i < v->info.sizedwords; i += 4) {
+ const uint32_t *raw = &v->code[i];
+ gc_disasm(&decoded, raw);
+
+ printf("%04d: %08x %08x %08x %08x %s\n",
+ i / 4,
+ raw[0], raw[1], raw[2], raw[3],
+ decoded.string);
+ }
+
+ ralloc_free(decoded.string);
+
+ printf("num loops: 0\n");
+ printf("num temps: %i\n", v->num_temps);
+ printf("num const: %i\n", v->const_size);
+
+ printf("immediates:\n");
+ i = 0;
+ util_dynarray_foreach(&v->uniforms, struct eir_uniform_data, uniform) {
+ printf(" u%i.%s = 0x%08x [%s]\n",
+ (v->const_size + i) / 4,
+ swizzle_names[i % 4],
+ uniform->data,
+ eir_uniform_content(uniform->content));
+
+ i++;
+ }
+
+ switch (v->shader->type) {
+ case MESA_SHADER_VERTEX:
+ printf("inputs:\n");
+ for (unsigned i = 0; i < v->num_inputs; i++)
+ printf(" [%i] %s comps: %u interp: %s\n",
+ i, gl_varying_slot_name(v->inputs[i].slot), v->inputs[i].ncomp,
+ glsl_interp_mode_name(v->inputs[i].interpolate));
+
+ printf("outputs:\n");
+ for (unsigned i = 0; i < v->num_outputs; i++)
+ printf(" [%i] %s comps: %u\n",
+ i, gl_varying_slot_name(v->outputs[i].slot), v->outputs[i].ncomp);
+
+ break;
+ case MESA_SHADER_FRAGMENT:
+ printf("inputs:\n");
+ for (unsigned i = 0; i < v->num_inputs; i++)
+ printf(" [%i] %s comps: %u interp: %s\n",
+ i, gl_varying_slot_name(v->inputs[i].slot), v->inputs[i].ncomp,
+ glsl_interp_mode_name(v->inputs[i].interpolate));
+
+ printf("outputs:\n");
+ for (unsigned i = 0; i < v->num_outputs; i++)
+ printf(" [%i] %s comps: %u\n",
+ i, gl_frag_result_name(v->outputs[i].slot), v->outputs[i].ncomp);
+
+ break;
+
+ default:
+ /* TODO */
+ break;
+ }
+
+ printf("special:\n");
+ if (v->shader->type == MESA_SHADER_VERTEX) {
+ printf(" vs_pos_out_reg=%i\n", v->vs_pos_out_reg);
+ printf(" vs_pointsize_out_reg=%i\n", v->vs_pointsize_out_reg);
+ } else {
+ printf(" ps_color_out_reg=%i\n", v->fs_color_out_reg);
+ printf(" ps_depth_out_reg=%i\n", v->fs_depth_out_reg);
+ }
+}
diff --git a/src/etnaviv/compiler/eir_shader.h b/src/etnaviv/compiler/eir_shader.h
new file mode 100644
index 00000000000..60c446f2943
--- /dev/null
+++ b/src/etnaviv/compiler/eir_shader.h
@@ -0,0 +1,203 @@
+/*
+ * Copyright (c) 2018 Etnaviv Project
+ * Copyright (C) 2018 Zodiac Inflight Innovations
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Christian Gmeiner <christian.gmeiner at gmail.com>
+ */
+
+#ifndef H_EIR_SHADER
+#define H_EIR_SHADER
+
+#include "compiler/glsl_types.h"
+#include "compiler/shader_enums.h"
+#include "eir.h"
+#include <stdbool.h>
+#include <util/u_debug.h>
+
+struct nir_shader;
+
+struct eir_shader_key
+{
+ union {
+ struct {
+ /*
+ * Combined Vertex/Fragment shader parameters:
+ */
+
+ /* do we need to swap rb in frag color? */
+ unsigned frag_rb_swap : 1;
+ };
+ uint32_t global;
+ };
+};
+
+struct eir_shader;
+
+struct eir_shader_variant
+{
+ /* variant id (for debug) */
+ uint32_t id;
+
+ struct eir_shader *shader;
+ struct eir_shader_key key;
+ struct eir_info info;
+ struct eir *ir;
+
+ uint32_t *code;
+
+ unsigned num_temps;
+ unsigned num_loops;
+ unsigned const_size;
+
+ /* keep track of uniforms */
+ struct util_dynarray uniforms;
+
+ /* attributes/varyings: */
+ unsigned num_inputs;
+ struct {
+ uint8_t reg;
+ uint8_t slot;
+ uint8_t ncomp;
+
+ enum glsl_interp_mode interpolate;
+ } inputs[16];
+
+ /* varyings/outputs: */
+ unsigned num_outputs;
+ struct {
+ uint8_t reg;
+ uint8_t slot;
+ uint8_t ncomp;
+ } outputs[16];
+
+ /* special outputs (vs only) */
+ int vs_pos_out_reg; /* VS position output */
+ int vs_pointsize_out_reg; /* VS point size output */
+
+ /* special outputs (fs only) */
+ int fs_color_out_reg; /* color output register */
+ int fs_depth_out_reg; /* depth output register */
+
+ /* shader variants form a linked list */
+ struct eir_shader_variant *next;
+};
+
+struct eir_shader
+{
+ void *mem_ctx;
+ gl_shader_stage type;
+
+ /* shader id (for debug): */
+ uint32_t id;
+ uint32_t variant_count;
+
+ struct eir_compiler *compiler;
+ struct nir_shader *nir;
+ struct eir_shader_variant *variants;
+};
+
+struct eir_shader *
+eir_shader_from_nir(struct eir_compiler *compiler, struct nir_shader *nir);
+
+void
+eir_shader_destroy(struct eir_shader *shader);
+
+struct eir_shader_variant *
+eir_shader_get_variant(struct eir_shader *shader, struct eir_shader_key key, bool *created);
+
+void
+eir_dump_shader(struct eir_shader_variant *variant);
+
+struct eir_shader_linkage {
+ uint8_t num_varyings;
+ struct {
+ uint32_t pa_attributes;
+ uint8_t ncomp;
+ uint8_t use[4];
+ uint8_t reg;
+ } varyings[16];
+};
+
+static inline int
+eir_find_output(const struct eir_shader_variant *v, gl_varying_slot slot)
+{
+ for (unsigned i = 0; i < v->num_outputs; i++)
+ if (v->outputs[i].slot == slot)
+ return i;
+
+ debug_assert(0);
+
+ return 0;
+}
+
+/* TODO: */
+#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
+
+static inline void
+eir_link_add(struct eir_shader_linkage *l, uint8_t reg, uint8_t ncomp)
+{
+ bool interpolate_always = false; /* TODO: */
+ uint32_t pa_attributes;
+ int i = l->num_varyings++;
+
+ debug_assert(i < ARRAY_SIZE(l->varyings));
+
+ if (!interpolate_always) /* colors affected by flat shading */
+ pa_attributes = 0x200;
+ else /* texture coord or other bypasses flat shading */
+ pa_attributes = 0x2f1;
+
+ l->varyings[i].reg = reg;
+ l->varyings[i].ncomp = ncomp;
+ l->varyings[i].pa_attributes = pa_attributes;
+
+ l->varyings[i].use[0] = interpolate_always ? VARYING_COMPONENT_USE_POINTCOORD_X : VARYING_COMPONENT_USE_USED;
+ l->varyings[i].use[1] = interpolate_always ? VARYING_COMPONENT_USE_POINTCOORD_Y : VARYING_COMPONENT_USE_USED;
+ l->varyings[i].use[2] = VARYING_COMPONENT_USE_USED;
+ l->varyings[i].use[3] = VARYING_COMPONENT_USE_USED;
+}
+
+static inline void
+eir_link_shader(struct eir_shader_linkage *l,
+ const struct eir_shader_variant *vs,
+ const struct eir_shader_variant *fs)
+{
+ int i = 0;
+
+ while (l->num_varyings < ARRAY_SIZE(l->varyings)) {
+
+ if (i >= fs->num_inputs)
+ break;
+
+ int reg = eir_find_output(vs, fs->inputs[i].slot);
+
+ eir_link_add(l, reg, fs->inputs[i].ncomp);
+
+ i++;
+ }
+}
+
+#endif // H_EIR_SHADER
diff --git a/src/etnaviv/compiler/meson.build b/src/etnaviv/compiler/meson.build
index 747b9536bb7..f8af6c8b35d 100644
--- a/src/etnaviv/compiler/meson.build
+++ b/src/etnaviv/compiler/meson.build
@@ -23,13 +23,17 @@
libetnaviv_compiler_files = files(
'eir.c',
'eir.h',
+ 'eir_compiler.c',
'eir_compiler.h',
+ 'eir_compiler_nir.c',
'eir_legalize.c',
'eir_live_variables.c',
'eir_nir.c',
'eir_nir.h',
'eir_print.c',
'eir_register_allocate.c',
+ 'eir_shader.c',
+ 'eir_shader.h',
'eir_uniform.c',
)
--
2.21.0
More information about the mesa-dev
mailing list