blob: 7f33f4782997a4e8e398b46fe2933342829febaa [file] [log] [blame]
/*
* Copyright (C) 2022 Alyssa Rosenzweig <alyssa@rosenzweig.io>
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "agx_compiler.h"
#include "compiler/nir/nir.h"
#include "compiler/nir/nir_builder.h"
#define AGX_TEXTURE_DESC_STRIDE 24
static nir_ssa_def *
texture_descriptor_ptr(nir_builder *b, nir_tex_instr *tex)
{
/* For bindless, we store the descriptor pointer in the texture handle */
int handle_idx = nir_tex_instr_src_index(tex, nir_tex_src_texture_handle);
if (handle_idx >= 0)
return tex->src[handle_idx].src.ssa;
/* For non-bindless, compute from the texture index, offset, and table */
unsigned base_B = tex->texture_index * AGX_TEXTURE_DESC_STRIDE;
nir_ssa_def *offs = nir_imm_int(b, base_B);
int offs_idx = nir_tex_instr_src_index(tex, nir_tex_src_texture_offset);
if (offs_idx >= 0) {
nir_ssa_def *offset_src = tex->src[offs_idx].src.ssa;
offs = nir_iadd(b, offs,
nir_imul_imm(b, offset_src, AGX_TEXTURE_DESC_STRIDE));
}
return nir_iadd(b, nir_load_texture_base_agx(b), nir_u2u64(b, offs));
}
static nir_ssa_def *
agx_txs(nir_builder *b, nir_tex_instr *tex)
{
nir_ssa_def *ptr = texture_descriptor_ptr(b, tex);
nir_ssa_def *comp[4] = { NULL };
nir_ssa_def *desc = nir_load_global_constant(b, ptr, 8, 4, 32);
nir_ssa_def *w0 = nir_channel(b, desc, 0);
nir_ssa_def *w1 = nir_channel(b, desc, 1);
nir_ssa_def *w3 = nir_channel(b, desc, 3);
/* Width minus 1: bits [28, 42) */
nir_ssa_def *width_m1 = nir_ior(b, nir_ushr_imm(b, w0, 28),
nir_ishl_imm(b, nir_iand_imm(b, w1,
BITFIELD_MASK(14 - 4)), 4));
/* Height minus 1: bits [42, 56) */
nir_ssa_def *height_m1 = nir_iand_imm(b, nir_ushr_imm(b, w1, 42 - 32),
BITFIELD_MASK(14));
/* Depth minus 1: bits [110, 124) */
nir_ssa_def *depth_m1 = nir_iand_imm(b, nir_ushr_imm(b, w3, 110 - 96),
BITFIELD_MASK(14));
/* First level: bits [56, 60) */
nir_ssa_def *lod = nir_iand_imm(b, nir_ushr_imm(b, w1, 56 - 32),
BITFIELD_MASK(4));
/* Add LOD offset to first level to get the interesting LOD */
int lod_idx = nir_tex_instr_src_index(tex, nir_tex_src_lod);
if (lod_idx >= 0)
lod = nir_iadd(b, lod, nir_ssa_for_src(b, tex->src[lod_idx].src, 1));
/* Add 1 to width-1, height-1 to get base dimensions */
nir_ssa_def *width = nir_iadd_imm(b, width_m1, 1);
nir_ssa_def *height = nir_iadd_imm(b, height_m1, 1);
nir_ssa_def *depth = nir_iadd_imm(b, depth_m1, 1);
/* How we finish depends on the size of the result */
unsigned nr_comps = nir_dest_num_components(tex->dest);
assert(nr_comps <= 3);
/* Adjust for LOD, do not adjust array size */
assert(!(nr_comps <= 1 && tex->is_array));
width = nir_imax(b, nir_ushr(b, width, lod), nir_imm_int(b, 1));
if (!(nr_comps == 2 && tex->is_array))
height = nir_imax(b, nir_ushr(b, height, lod), nir_imm_int(b, 1));
if (!(nr_comps == 3 && tex->is_array))
depth = nir_imax(b, nir_ushr(b, depth, lod), nir_imm_int(b, 1));
comp[0] = width;
comp[1] = height;
comp[2] = depth;
return nir_vec(b, comp, nr_comps);
}
static bool
lower_txs(nir_builder *b, nir_instr *instr, UNUSED void *data)
{
if (instr->type != nir_instr_type_tex)
return false;
nir_tex_instr *tex = nir_instr_as_tex(instr);
b->cursor = nir_before_instr(instr);
if (tex->op != nir_texop_txs)
return false;
nir_ssa_def *res = agx_txs(b, tex);
nir_ssa_def_rewrite_uses_after(&tex->dest.ssa, res, instr);
nir_instr_remove(instr);
return true;
}
/*
* Lower txs.
*/
bool
agx_lower_resinfo(nir_shader *s)
{
return nir_shader_instructions_pass(s, lower_txs,
nir_metadata_block_index |
nir_metadata_dominance, NULL);
}