freedreno/a4xx: better workaround for astc+srgb
[mesa.git] / src / gallium / drivers / freedreno / ir3 / ir3_compiler_nir.c
index f38dc8643b412e1e9dd60fbd272e4b185342f70c..abdb1c27c91666b859986242bd552f4eca927008 100644 (file)
@@ -103,8 +103,15 @@ struct ir3_compile {
         */
        bool unminify_coords;
 
-       /* for looking up which system value is which */
-       unsigned sysval_semantics[8];
+       /* on a4xx, for array textures we need to add 0.5 to the array
+        * index coordinate:
+        */
+       bool array_index_add_half;
+
+       /* on a4xx, bitmask of samplers which need astc+srgb workaround: */
+       unsigned astc_srgb;
+
+       unsigned max_texture_index;
 
        /* set if we encounter something we can't handle yet, so we
         * can bail cleanly and fallback to TGSI compiler f/e
@@ -128,11 +135,19 @@ compile_init(struct ir3_compiler *compiler,
                ctx->flat_bypass = true;
                ctx->levels_add_one = false;
                ctx->unminify_coords = false;
+               ctx->array_index_add_half = true;
+
+               if (so->type == SHADER_VERTEX)
+                       ctx->astc_srgb = so->key.vastc_srgb;
+               else if (so->type == SHADER_FRAGMENT)
+                       ctx->astc_srgb = so->key.fastc_srgb;
+
        } else {
                /* no special handling for "flat" */
                ctx->flat_bypass = false;
                ctx->levels_add_one = true;
                ctx->unminify_coords = true;
+               ctx->array_index_add_half = false;
        }
 
        ctx->compiler = compiler;
@@ -286,7 +301,7 @@ create_immed(struct ir3_block *block, uint32_t val)
 {
        struct ir3_instruction *mov;
 
-       mov = ir3_instr_create(block, 1, 0);
+       mov = ir3_instr_create(block, OPC_MOV);
        mov->cat1.src_type = TYPE_U32;
        mov->cat1.dst_type = TYPE_U32;
        ir3_reg_create(mov, 0, 0);
@@ -366,7 +381,7 @@ create_uniform(struct ir3_compile *ctx, unsigned n)
 {
        struct ir3_instruction *mov;
 
-       mov = ir3_instr_create(ctx->block, 1, 0);
+       mov = ir3_instr_create(ctx->block, OPC_MOV);
        /* TODO get types right? */
        mov->cat1.src_type = TYPE_F32;
        mov->cat1.dst_type = TYPE_F32;
@@ -382,7 +397,7 @@ create_uniform_indirect(struct ir3_compile *ctx, int n,
 {
        struct ir3_instruction *mov;
 
-       mov = ir3_instr_create(ctx->block, 1, 0);
+       mov = ir3_instr_create(ctx->block, OPC_MOV);
        mov->cat1.src_type = TYPE_U32;
        mov->cat1.dst_type = TYPE_U32;
        ir3_reg_create(mov, 0, 0);
@@ -402,7 +417,7 @@ create_collect(struct ir3_block *block, struct ir3_instruction **arr,
        if (arrsz == 0)
                return NULL;
 
-       collect = ir3_instr_create2(block, -1, OPC_META_FI, 1 + arrsz);
+       collect = ir3_instr_create2(block, OPC_META_FI, 1 + arrsz);
        ir3_reg_create(collect, 0, 0);     /* dst */
        for (unsigned i = 0; i < arrsz; i++)
                ir3_reg_create(collect, 0, IR3_REG_SSA)->instr = arr[i];
@@ -418,7 +433,7 @@ create_indirect_load(struct ir3_compile *ctx, unsigned arrsz, int n,
        struct ir3_instruction *mov;
        struct ir3_register *src;
 
-       mov = ir3_instr_create(block, 1, 0);
+       mov = ir3_instr_create(block, OPC_MOV);
        mov->cat1.src_type = TYPE_U32;
        mov->cat1.dst_type = TYPE_U32;
        ir3_reg_create(mov, 0, 0);
@@ -441,7 +456,7 @@ create_var_load(struct ir3_compile *ctx, struct ir3_array *arr, int n,
        struct ir3_instruction *mov;
        struct ir3_register *src;
 
-       mov = ir3_instr_create(block, 1, 0);
+       mov = ir3_instr_create(block, OPC_MOV);
        mov->cat1.src_type = TYPE_U32;
        mov->cat1.dst_type = TYPE_U32;
        ir3_reg_create(mov, 0, 0);
@@ -469,7 +484,7 @@ create_var_store(struct ir3_compile *ctx, struct ir3_array *arr, int n,
        struct ir3_instruction *mov;
        struct ir3_register *dst;
 
-       mov = ir3_instr_create(block, 1, 0);
+       mov = ir3_instr_create(block, OPC_MOV);
        mov->cat1.src_type = TYPE_U32;
        mov->cat1.dst_type = TYPE_U32;
        dst = ir3_reg_create(mov, 0, IR3_REG_ARRAY |
@@ -492,7 +507,7 @@ create_input(struct ir3_block *block, unsigned n)
 {
        struct ir3_instruction *in;
 
-       in = ir3_instr_create(block, -1, OPC_META_INPUT);
+       in = ir3_instr_create(block, OPC_META_INPUT);
        in->inout.block = block;
        ir3_reg_create(in, n, 0);
 
@@ -613,15 +628,14 @@ create_driver_param(struct ir3_compile *ctx, enum ir3_driver_param dp)
  */
 static void
 split_dest(struct ir3_block *block, struct ir3_instruction **dst,
-               struct ir3_instruction *src, unsigned n)
+               struct ir3_instruction *src, unsigned base, unsigned n)
 {
        struct ir3_instruction *prev = NULL;
        for (int i = 0, j = 0; i < n; i++) {
-               struct ir3_instruction *split =
-                               ir3_instr_create(block, -1, OPC_META_FO);
+               struct ir3_instruction *split = ir3_instr_create(block, OPC_META_FO);
                ir3_reg_create(split, 0, IR3_REG_SSA);
                ir3_reg_create(split, 0, IR3_REG_SSA)->instr = src;
-               split->fo.off = i;
+               split->fo.off = i + base;
 
                if (prev) {
                        split->cp.left = prev;
@@ -631,7 +645,7 @@ split_dest(struct ir3_block *block, struct ir3_instruction **dst,
                }
                prev = split;
 
-               if (src->regs[0]->wrmask & (1 << i))
+               if (src->regs[0]->wrmask & (1 << (i + base)))
                        dst[j++] = split;
        }
 }
@@ -1017,7 +1031,7 @@ emit_intrinsic_load_ubo(struct ir3_compile *ctx, nir_intrinsic_instr *intr,
 
        const_offset = nir_src_as_const_value(intr->src[1]);
        if (const_offset) {
-               off += const_offset->u[0];
+               off += const_offset->u32[0];
        } else {
                /* For load_ubo_indirect, second src is indirect offset: */
                src1 = get_src(ctx, &intr->src[1])[0];
@@ -1109,7 +1123,7 @@ emit_intrinsic_store_var(struct ir3_compile *ctx, nir_intrinsic_instr *intr)
        default:
                compile_error(ctx, "Unhandled store deref type: %u\n",
                                darr->deref_array_type);
-               break;
+               return;
        }
 
        for (int i = 0; i < intr->num_components; i++) {
@@ -1159,7 +1173,7 @@ emit_intrinsic(struct ir3_compile *ctx, nir_intrinsic_instr *intr)
                idx = nir_intrinsic_base(intr);
                const_offset = nir_src_as_const_value(intr->src[0]);
                if (const_offset) {
-                       idx += const_offset->u[0];
+                       idx += const_offset->u32[0];
                        for (int i = 0; i < intr->num_components; i++) {
                                unsigned n = idx * 4 + i;
                                dst[i] = create_uniform(ctx, n);
@@ -1186,7 +1200,7 @@ emit_intrinsic(struct ir3_compile *ctx, nir_intrinsic_instr *intr)
                idx = nir_intrinsic_base(intr);
                const_offset = nir_src_as_const_value(intr->src[0]);
                if (const_offset) {
-                       idx += const_offset->u[0];
+                       idx += const_offset->u32[0];
                        for (int i = 0; i < intr->num_components; i++) {
                                unsigned n = idx * 4 + i;
                                dst[i] = ctx->ir->inputs[n];
@@ -1213,7 +1227,7 @@ emit_intrinsic(struct ir3_compile *ctx, nir_intrinsic_instr *intr)
                idx = nir_intrinsic_base(intr);
                const_offset = nir_src_as_const_value(intr->src[1]);
                compile_assert(ctx, const_offset != NULL);
-               idx += const_offset->u[0];
+               idx += const_offset->u32[0];
 
                src = get_src(ctx, &intr->src[0]);
                for (int i = 0; i < intr->num_components; i++) {
@@ -1258,7 +1272,14 @@ emit_intrinsic(struct ir3_compile *ctx, nir_intrinsic_instr *intr)
                        ctx->frag_face = create_input(b, 0);
                        ctx->frag_face->regs[0]->flags |= IR3_REG_HALF;
                }
-               dst[0] = ir3_ADD_S(b, ctx->frag_face, 0, create_immed(b, 1), 0);
+               /* for fragface, we always get -1 or 0, but that is inverse
+                * of what nir expects (where ~0 is true).  Unfortunately
+                * trying to widen from half to full in add.s seems to do a
+                * non-sign-extending widen (resulting in something that
+                * gets interpreted as float Inf??)
+                */
+               dst[0] = ir3_COV(b, ctx->frag_face, TYPE_S16, TYPE_S32);
+               dst[0] = ir3_ADD_S(b, dst[0], 0, create_immed(b, 1), 0);
                break;
        case nir_intrinsic_discard_if:
        case nir_intrinsic_discard: {
@@ -1301,7 +1322,7 @@ emit_load_const(struct ir3_compile *ctx, nir_load_const_instr *instr)
        struct ir3_instruction **dst = get_dst_ssa(ctx, &instr->def,
                        instr->def.num_components);
        for (int i = 0; i < instr->def.num_components; i++)
-               dst[i] = create_immed(ctx->block, instr->value.u[i]);
+               dst[i] = create_immed(ctx->block, instr->value.u32[i]);
 }
 
 static void
@@ -1365,7 +1386,6 @@ emit_tex(struct ir3_compile *ctx, nir_tex_instr *tex)
        struct ir3_block *b = ctx->block;
        struct ir3_instruction **dst, *sam, *src0[12], *src1[4];
        struct ir3_instruction **coord, *lod, *compare, *proj, **off, **ddx, **ddy;
-       struct ir3_instruction *const_off[4];
        bool has_bias = false, has_lod = false, has_proj = false, has_off = false;
        unsigned i, coords, flags;
        unsigned nsrc0 = 0, nsrc1 = 0;
@@ -1434,21 +1454,6 @@ emit_tex(struct ir3_compile *ctx, nir_tex_instr *tex)
 
        tex_info(tex, &flags, &coords);
 
-       if (!has_off) {
-               /* could still have a constant offset: */
-               if (tex->const_offset[0] || tex->const_offset[1] ||
-                               tex->const_offset[2] || tex->const_offset[3]) {
-                       off = const_off;
-
-                       off[0] = create_immed(b, tex->const_offset[0]);
-                       off[1] = create_immed(b, tex->const_offset[1]);
-                       off[2] = create_immed(b, tex->const_offset[2]);
-                       off[3] = create_immed(b, tex->const_offset[3]);
-
-                       has_off = true;
-               }
-       }
-
        /* scale up integer coords for TXF based on the LOD */
        if (ctx->unminify_coords && (opc == OPC_ISAML)) {
                assert(has_lod);
@@ -1457,9 +1462,8 @@ emit_tex(struct ir3_compile *ctx, nir_tex_instr *tex)
        }
 
        /* the array coord for cube arrays needs 0.5 added to it */
-       if (tex->sampler_dim == GLSL_SAMPLER_DIM_CUBE && tex->is_array &&
-               opc != OPC_ISAML)
-               coord[3] = ir3_ADD_F(b, coord[3], 0, create_immed(b, fui(0.5)), 0);
+       if (ctx->array_index_add_half && tex->is_array && (opc != OPC_ISAML))
+               coord[coords] = ir3_ADD_F(b, coord[coords], 0, create_immed(b, fui(0.5)), 0);
 
        /*
         * lay out the first argument in the proper order:
@@ -1547,12 +1551,35 @@ emit_tex(struct ir3_compile *ctx, nir_tex_instr *tex)
        if (opc == OPC_GETLOD)
                type = TYPE_U32;
 
-       sam = ir3_SAM(b, opc, type, TGSI_WRITEMASK_XYZW,
-                       flags, tex->sampler_index, tex->sampler_index,
-                       create_collect(b, src0, nsrc0),
-                       create_collect(b, src1, nsrc1));
+       unsigned tex_idx = tex->texture_index;
+
+       ctx->max_texture_index = MAX2(ctx->max_texture_index, tex_idx);
+
+       struct ir3_instruction *col0 = create_collect(b, src0, nsrc0);
+       struct ir3_instruction *col1 = create_collect(b, src1, nsrc1);
 
-       split_dest(b, dst, sam, 4);
+       sam = ir3_SAM(b, opc, type, TGSI_WRITEMASK_XYZW, flags,
+                       tex_idx, tex_idx, col0, col1);
+
+       if ((ctx->astc_srgb & (1 << tex_idx)) && !nir_tex_instr_is_query(tex)) {
+               /* only need first 3 components: */
+               sam->regs[0]->wrmask = 0x7;
+               split_dest(b, dst, sam, 0, 3);
+
+               /* we need to sample the alpha separately with a non-ASTC
+                * texture state:
+                */
+               sam = ir3_SAM(b, opc, type, TGSI_WRITEMASK_W, flags,
+                               tex_idx, tex_idx, col0, col1);
+
+               array_insert(ctx->ir->astc_srgb, sam);
+
+               /* fixup .w component: */
+               split_dest(b, &dst[3], sam, 3, 1);
+       } else {
+               /* normal (non-workaround) case: */
+               split_dest(b, dst, sam, 0, 4);
+       }
 
        /* GETLOD returns results in 4.8 fixed point */
        if (opc == OPC_GETLOD) {
@@ -1575,12 +1602,12 @@ emit_tex_query_levels(struct ir3_compile *ctx, nir_tex_instr *tex)
        dst = get_dst(ctx, &tex->dest, 1);
 
        sam = ir3_SAM(b, OPC_GETINFO, TYPE_U32, TGSI_WRITEMASK_Z, 0,
-                       tex->sampler_index, tex->sampler_index, NULL, NULL);
+                       tex->texture_index, tex->texture_index, NULL, NULL);
 
        /* even though there is only one component, since it ends
         * up in .z rather than .x, we need a split_dest()
         */
-       split_dest(b, dst, sam, 3);
+       split_dest(b, dst, sam, 0, 3);
 
        /* The # of levels comes from getinfo.z. We need to add 1 to it, since
         * the value in TEX_CONST_0 is zero-based.
@@ -1612,9 +1639,9 @@ emit_tex_txs(struct ir3_compile *ctx, nir_tex_instr *tex)
        lod = get_src(ctx, &tex->src[0].src)[0];
 
        sam = ir3_SAM(b, OPC_GETSIZE, TYPE_U32, TGSI_WRITEMASK_XYZW, flags,
-                       tex->sampler_index, tex->sampler_index, lod, NULL);
+                       tex->texture_index, tex->texture_index, lod, NULL);
 
-       split_dest(b, dst, sam, 4);
+       split_dest(b, dst, sam, 0, 4);
 
        /* Array size actually ends up in .w rather than .z. This doesn't
         * matter for miplevel 0, but for higher mips the value in z is
@@ -1640,7 +1667,7 @@ emit_phi(struct ir3_compile *ctx, nir_phi_instr *nphi)
 
        dst = get_dst(ctx, &nphi->dest, 1);
 
-       phi = ir3_instr_create2(ctx->block, -1, OPC_META_PHI,
+       phi = ir3_instr_create2(ctx->block, OPC_META_PHI,
                        1 + exec_list_length(&nphi->srcs));
        ir3_reg_create(phi, 0, 0);         /* dst */
        phi->phi.nphi = nphi;
@@ -1660,7 +1687,7 @@ resolve_phis(struct ir3_compile *ctx, struct ir3_block *block)
                nir_phi_instr *nphi;
 
                /* phi's only come at start of block: */
-               if (!(is_meta(instr) && (instr->opc == OPC_META_PHI)))
+               if (instr->opc != OPC_META_PHI)
                        break;
 
                if (!instr->phi.nphi)
@@ -1671,6 +1698,16 @@ resolve_phis(struct ir3_compile *ctx, struct ir3_block *block)
 
                foreach_list_typed(nir_phi_src, nsrc, node, &nphi->srcs) {
                        struct ir3_instruction *src = get_src(ctx, &nsrc->src)[0];
+
+                       /* NOTE: src might not be in the same block as it comes from
+                        * according to the phi.. but in the end the backend assumes
+                        * it will be able to assign the same register to each (which
+                        * only works if it is assigned in the src block), so insert
+                        * an extra mov to make sure the phi src is assigned in the
+                        * block it comes from:
+                        */
+                       src = ir3_MOV(get_block(ctx, nsrc->pred), src, TYPE_U32);
+
                        ir3_reg_create(instr, 0, IR3_REG_SSA)->instr = src;
                }
        }
@@ -2153,7 +2190,7 @@ emit_instructions(struct ir3_compile *ctx)
        if (ctx->so->type == SHADER_FRAGMENT) {
                // TODO maybe a helper for fi since we need it a few places..
                struct ir3_instruction *instr;
-               instr = ir3_instr_create(ctx->block, -1, OPC_META_FI);
+               instr = ir3_instr_create(ctx->block, OPC_META_FI);
                ir3_reg_create(instr, 0, 0);
                ir3_reg_create(instr, 0, IR3_REG_SSA);    /* r0.x */
                ir3_reg_create(instr, 0, IR3_REG_SSA);    /* r0.y */
@@ -2262,6 +2299,40 @@ fixup_frag_inputs(struct ir3_compile *ctx)
        ir->inputs = inputs;
 }
 
+/* Fixup tex sampler state for astc/srgb workaround instructions.  We
+ * need to assign the tex state indexes for these after we know the
+ * max tex index.
+ */
+static void
+fixup_astc_srgb(struct ir3_compile *ctx)
+{
+       struct ir3_shader_variant *so = ctx->so;
+       /* indexed by original tex idx, value is newly assigned alpha sampler
+        * state tex idx.  Zero is invalid since there is at least one sampler
+        * if we get here.
+        */
+       unsigned alt_tex_state[16] = {0};
+       unsigned tex_idx = ctx->max_texture_index + 1;
+       unsigned idx = 0;
+
+       so->astc_srgb.base = tex_idx;
+
+       for (unsigned i = 0; i < ctx->ir->astc_srgb_count; i++) {
+               struct ir3_instruction *sam = ctx->ir->astc_srgb[i];
+
+               compile_assert(ctx, sam->cat5.tex < ARRAY_SIZE(alt_tex_state));
+
+               if (alt_tex_state[sam->cat5.tex] == 0) {
+                       /* assign new alternate/alpha tex state slot: */
+                       alt_tex_state[sam->cat5.tex] = tex_idx++;
+                       so->astc_srgb.orig_idx[idx++] = sam->cat5.tex;
+                       so->astc_srgb.count++;
+               }
+
+               sam->cat5.tex = alt_tex_state[sam->cat5.tex];
+       }
+}
+
 int
 ir3_compile_shader_nir(struct ir3_compiler *compiler,
                struct ir3_shader_variant *so)
@@ -2332,12 +2403,12 @@ ir3_compile_shader_nir(struct ir3_compiler *compiler,
                         * in which case we need to propagate the half-reg flag
                         * up to the definer so that RA sees it:
                         */
-                       if (is_meta(out) && (out->opc == OPC_META_FO)) {
+                       if (out->opc == OPC_META_FO) {
                                out = out->regs[1]->instr;
                                out->regs[0]->flags |= IR3_REG_HALF;
                        }
 
-                       if (out->category == 1) {
+                       if (out->opc == OPC_MOV) {
                                out->cat1.dst_type = half_type(out->cat1.dst_type);
                        }
                }
@@ -2427,6 +2498,9 @@ ir3_compile_shader_nir(struct ir3_compiler *compiler,
                so->inputs[i].compmask = compmask;
        }
 
+       if (ctx->astc_srgb)
+               fixup_astc_srgb(ctx);
+
        /* We need to do legalize after (for frag shader's) the "bary.f"
         * offsets (inloc) have been assigned.
         */