Signed-off-by: Christian Gmeiner <christian.gmei...@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.gmei...@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.gmei...@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.gmei...@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.gmei...@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 _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/mesa-dev