static void lower_implicit_lod(nir_builder *b, nir_tex_instr *tex) { assert(tex->op == nir_texop_tex || tex->op == nir_texop_txb); assert(nir_tex_instr_src_index(tex, nir_tex_src_lod) < 0); assert(nir_tex_instr_src_index(tex, nir_tex_src_ddx) < 0); assert(nir_tex_instr_src_index(tex, nir_tex_src_ddy) < 0); b->cursor = nir_before_instr(&tex->instr); nir_ssa_def *lod = get_texture_lod(b, tex); int bias_idx = nir_tex_instr_src_index(tex, nir_tex_src_bias); if (bias_idx >= 0) { /* If we have a bias, add it in */ lod = nir_fadd(b, lod, nir_ssa_for_src(b, tex->src[bias_idx].src, 1)); nir_tex_instr_remove_src(tex, bias_idx); } int min_lod_idx = nir_tex_instr_src_index(tex, nir_tex_src_min_lod); if (min_lod_idx >= 0) { /* If we have a minimum LOD, clamp LOD accordingly */ lod = nir_fmax(b, lod, nir_ssa_for_src(b, tex->src[min_lod_idx].src, 1)); nir_tex_instr_remove_src(tex, min_lod_idx); } nir_tex_instr_add_src(tex, nir_tex_src_lod, nir_src_for_ssa(lod)); tex->op = nir_texop_txl; }
static nir_src get_deref_reg_src(nir_deref_instr *deref, struct locals_to_regs_state *state) { nir_builder *b = &state->builder; nir_src src; src.is_ssa = false; src.reg.reg = get_reg_for_deref(deref, state); src.reg.base_offset = 0; src.reg.indirect = NULL; /* It is possible for a user to create a shader that has an array with a * single element and then proceed to access it indirectly. Indirectly * accessing a non-array register is not allowed in NIR. In order to * handle this case we just convert it to a direct reference. */ if (src.reg.reg->num_array_elems == 0) return src; unsigned inner_array_size = 1; for (const nir_deref_instr *d = deref; d; d = nir_deref_instr_parent(d)) { if (d->deref_type != nir_deref_type_array) continue; if (nir_src_is_const(d->arr.index) && !src.reg.indirect) { src.reg.base_offset += nir_src_as_uint(d->arr.index) * inner_array_size; } else { if (src.reg.indirect) { assert(src.reg.base_offset == 0); } else { src.reg.indirect = ralloc(b->shader, nir_src); *src.reg.indirect = nir_src_for_ssa(nir_imm_int(b, src.reg.base_offset)); src.reg.base_offset = 0; } assert(src.reg.indirect->is_ssa); nir_ssa_def *index = nir_i2i(b, nir_ssa_for_src(b, d->arr.index, 1), 32); src.reg.indirect->ssa = nir_iadd(b, src.reg.indirect->ssa, nir_imul(b, index, nir_imm_int(b, inner_array_size))); } inner_array_size *= glsl_get_length(nir_deref_instr_parent(d)->type); } return src; }
/* Calculate the sampler index based on array indicies and also * calculate the base uniform location for struct members. */ static void calc_sampler_offsets(nir_deref *tail, nir_tex_instr *instr, unsigned *array_elements, nir_ssa_def **indirect, nir_builder *b, unsigned *location) { if (tail->child == NULL) return; switch (tail->child->deref_type) { case nir_deref_type_array: { nir_deref_array *deref_array = nir_deref_as_array(tail->child); assert(deref_array->deref_array_type != nir_deref_array_type_wildcard); calc_sampler_offsets(tail->child, instr, array_elements, indirect, b, location); instr->sampler_index += deref_array->base_offset * *array_elements; if (deref_array->deref_array_type == nir_deref_array_type_indirect) { nir_ssa_def *mul = nir_imul(b, nir_imm_int(b, *array_elements), nir_ssa_for_src(b, deref_array->indirect, 1)); nir_instr_rewrite_src(&instr->instr, &deref_array->indirect, NIR_SRC_INIT); if (*indirect) { *indirect = nir_iadd(b, *indirect, mul); } else { *indirect = mul; } } *array_elements *= glsl_get_length(tail->type); break; } case nir_deref_type_struct: { nir_deref_struct *deref_struct = nir_deref_as_struct(tail->child); *location += glsl_get_record_location_offset(tail->type, deref_struct->index); calc_sampler_offsets(tail->child, instr, array_elements, indirect, b, location); break; } default: unreachable("Invalid deref type"); break; } }
static void saturate_src(nir_builder *b, nir_tex_instr *tex, unsigned sat_mask) { b->cursor = nir_before_instr(&tex->instr); /* Walk through the sources saturating the requested arguments. */ for (unsigned i = 0; i < tex->num_srcs; i++) { if (tex->src[i].src_type != nir_tex_src_coord) continue; nir_ssa_def *src = nir_ssa_for_src(b, tex->src[i].src, tex->coord_components); /* split src into components: */ nir_ssa_def *comp[4]; for (unsigned j = 0; j < tex->coord_components; j++) comp[j] = nir_channel(b, src, j); /* clamp requested components, array index does not get clamped: */ unsigned ncomp = tex->coord_components; if (tex->is_array) ncomp--; for (unsigned j = 0; j < ncomp; j++) { if ((1 << j) & sat_mask) { if (tex->sampler_dim == GLSL_SAMPLER_DIM_RECT) { /* non-normalized texture coords, so clamp to texture * size rather than [0.0, 1.0] */ nir_ssa_def *txs = get_texture_size(b, tex); comp[j] = nir_fmax(b, comp[j], nir_imm_float(b, 0.0)); comp[j] = nir_fmin(b, comp[j], nir_channel(b, txs, j)); } else { comp[j] = nir_fsat(b, comp[j]); } } } /* and move the result back into a single vecN: */ src = nir_vec(b, comp, tex->coord_components); nir_instr_rewrite_src(&tex->instr, &tex->src[i].src, nir_src_for_ssa(src)); } }
/* Multiply interp_var_at_offset's offset by transform.x to flip it. */ static void lower_interp_var_at_offset(lower_wpos_ytransform_state *state, nir_intrinsic_instr *interp) { nir_builder *b = &state->b; nir_ssa_def *offset; nir_ssa_def *flip_y; b->cursor = nir_before_instr(&interp->instr); offset = nir_ssa_for_src(b, interp->src[0], 2); flip_y = nir_fmul(b, nir_channel(b, offset, 1), nir_channel(b, get_transform(state), 0)); nir_instr_rewrite_src(&interp->instr, &interp->src[0], nir_src_for_ssa(nir_vec2(b, nir_channel(b, offset, 0), flip_y))); }
static void lower_rect(nir_builder *b, nir_tex_instr *tex) { nir_ssa_def *txs = get_texture_size(b, tex); nir_ssa_def *scale = nir_frcp(b, txs); /* Walk through the sources normalizing the requested arguments. */ for (unsigned i = 0; i < tex->num_srcs; i++) { if (tex->src[i].src_type != nir_tex_src_coord) continue; nir_ssa_def *coords = nir_ssa_for_src(b, tex->src[i].src, tex->coord_components); nir_instr_rewrite_src(&tex->instr, &tex->src[i].src, nir_src_for_ssa(nir_fmul(b, coords, scale))); } tex->sampler_dim = GLSL_SAMPLER_DIM_2D; }
static void project_src(nir_builder *b, nir_tex_instr *tex) { /* Find the projector in the srcs list, if present. */ int proj_index = nir_tex_instr_src_index(tex, nir_tex_src_projector); if (proj_index < 0) return; b->cursor = nir_before_instr(&tex->instr); nir_ssa_def *inv_proj = nir_frcp(b, nir_ssa_for_src(b, tex->src[proj_index].src, 1)); /* Walk through the sources projecting the arguments. */ for (unsigned i = 0; i < tex->num_srcs; i++) { switch (tex->src[i].src_type) { case nir_tex_src_coord: case nir_tex_src_comparator: break; default: continue; } nir_ssa_def *unprojected = nir_ssa_for_src(b, tex->src[i].src, nir_tex_instr_src_size(tex, i)); nir_ssa_def *projected = nir_fmul(b, unprojected, inv_proj); /* Array indices don't get projected, so make an new vector with the * coordinate's array index untouched. */ if (tex->is_array && tex->src[i].src_type == nir_tex_src_coord) { switch (tex->coord_components) { case 4: projected = nir_vec4(b, nir_channel(b, projected, 0), nir_channel(b, projected, 1), nir_channel(b, projected, 2), nir_channel(b, unprojected, 3)); break; case 3: projected = nir_vec3(b, nir_channel(b, projected, 0), nir_channel(b, projected, 1), nir_channel(b, unprojected, 2)); break; case 2: projected = nir_vec2(b, nir_channel(b, projected, 0), nir_channel(b, unprojected, 1)); break; default: unreachable("bad texture coord count for array"); break; } } nir_instr_rewrite_src(&tex->instr, &tex->src[i].src, nir_src_for_ssa(projected)); } nir_tex_instr_remove_src(tex, proj_index); }
static void convert_instr(nir_builder *bld, nir_alu_instr *alu) { nir_ssa_def *numer, *denom, *af, *bf, *a, *b, *q, *r; nir_op op = alu->op; bool is_signed; if ((op != nir_op_idiv) && (op != nir_op_udiv) && (op != nir_op_umod)) return; is_signed = (op == nir_op_idiv); bld->cursor = nir_before_instr(&alu->instr); numer = nir_ssa_for_src(bld, alu->src[0].src, nir_ssa_alu_instr_src_components(alu, 0)); denom = nir_ssa_for_src(bld, alu->src[1].src, nir_ssa_alu_instr_src_components(alu, 1)); if (is_signed) { af = nir_i2f(bld, numer); bf = nir_i2f(bld, denom); af = nir_fabs(bld, af); bf = nir_fabs(bld, bf); a = nir_iabs(bld, numer); b = nir_iabs(bld, denom); } else { af = nir_u2f(bld, numer); bf = nir_u2f(bld, denom); a = numer; b = denom; } /* get first result: */ bf = nir_frcp(bld, bf); bf = nir_isub(bld, bf, nir_imm_int(bld, 2)); /* yes, really */ q = nir_fmul(bld, af, bf); if (is_signed) { q = nir_f2i(bld, q); } else { q = nir_f2u(bld, q); } /* get error of first result: */ r = nir_imul(bld, q, b); r = nir_isub(bld, a, r); r = nir_u2f(bld, r); r = nir_fmul(bld, r, bf); r = nir_f2u(bld, r); /* add quotients: */ q = nir_iadd(bld, q, r); /* correction: if modulus >= divisor, add 1 */ r = nir_imul(bld, q, b); r = nir_isub(bld, a, r); r = nir_ige(bld, r, b); r = nir_b2i(bld, r); q = nir_iadd(bld, q, r); if (is_signed) { /* fix the sign: */ r = nir_ixor(bld, numer, denom); r = nir_ushr(bld, r, nir_imm_int(bld, 31)); r = nir_i2b(bld, r); b = nir_ineg(bld, q); q = nir_bcsel(bld, r, b, q); } if (op == nir_op_umod) { /* division result in q */ r = nir_imul(bld, q, b); q = nir_isub(bld, a, r); } assert(alu->dest.dest.is_ssa); nir_ssa_def_rewrite_uses(&alu->dest.dest.ssa, nir_src_for_ssa(q)); }