agx: Implement texture offsets and comparators

Texture offsets and shadow comparison values get grouped into a vector
passed by register. Comparison values are provided as-is (fp32). Texture
offsets are packed into nibbles, but we can do this on the CPU, as
nonconstant offsets are forbidden in GLSL at least. They're also
forbidden in Vulkan/SPIR-V without ImageGatherExtended/
shaderImageGatherExtended. I'm happy kicking the NIR lowering can down
the line, this commit is complicated enough already.

Passes dEQP-GLES3.functional.shaders.texture_functions.texture.* and
dEQP-GLES3.functional.shaders.texture_functions.textureoffset.*

Signed-off-by: Alyssa Rosenzweig <alyssa@rosenzweig.io>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/18525>
This commit is contained in:
Alyssa Rosenzweig
2022-09-08 18:59:35 -04:00
committed by Marge Bot
parent 4f85a7be8c
commit 7a4e0a4d35
5 changed files with 62 additions and 18 deletions

View File

@@ -1020,7 +1020,8 @@ agx_emit_tex(agx_builder *b, nir_tex_instr *instr)
texture = agx_immediate(instr->texture_index),
sampler = agx_immediate(instr->sampler_index),
lod = agx_immediate(0),
offset = agx_null();
compare = agx_null(),
packed_offset = agx_null();
bool txf = instr->op == nir_texop_txf;
@@ -1085,9 +1086,32 @@ agx_emit_tex(agx_builder *b, nir_tex_instr *instr)
lod = index;
break;
case nir_tex_src_ms_index:
case nir_tex_src_offset:
case nir_tex_src_comparator:
assert(index.size == AGX_SIZE_32);
compare = index;
break;
case nir_tex_src_offset:
{
assert(instr->src[i].src.is_ssa);
nir_ssa_def *def = instr->src[i].src.ssa;
uint32_t packed = 0;
for (unsigned c = 0; c < def->num_components; ++c) {
nir_ssa_scalar s = nir_ssa_scalar_resolved(def, c);
assert(nir_ssa_scalar_is_const(s) && "no nonconstant offsets");
int32_t val = nir_ssa_scalar_as_uint(s);
assert((val >= -8 && val <= 7) && "out of bounds offset");
packed |= (val & 0xF) << (4 * c);
}
packed_offset = agx_mov_imm(b, 32, packed);
break;
}
case nir_tex_src_ms_index:
case nir_tex_src_texture_offset:
case nir_tex_src_sampler_offset:
default:
@@ -1097,11 +1121,22 @@ agx_emit_tex(agx_builder *b, nir_tex_instr *instr)
agx_index dst = agx_dest_index(&instr->dest);
agx_instr *I = agx_texture_sample_to(b, dst, coords, lod, texture, sampler, offset,
/* Pack shadow reference value (compare) and packed offset together */
agx_index compare_offset = agx_null();
if (!agx_is_null(compare) && !agx_is_null(packed_offset))
compare_offset = agx_vec2(b, compare, packed_offset);
else if (!agx_is_null(packed_offset))
compare_offset = packed_offset;
else if (!agx_is_null(compare))
compare_offset = compare;
agx_instr *I = agx_texture_sample_to(b, dst, coords, lod, texture, sampler,
compare_offset,
agx_tex_dim(instr->sampler_dim, instr->is_array),
agx_lod_mode_for_nir(instr->op),
0xF, /* TODO: wrmask */
0);
0, !agx_is_null(packed_offset), !agx_is_null(compare));
if (txf)
I->op = AGX_OPCODE_TEXTURE_LOAD;

View File

@@ -319,6 +319,8 @@ typedef struct {
/* TODO: Handle tex ops more efficient */
enum agx_dim dim : 3;
bool offset : 1;
bool shadow : 1;
/* Final st_vary op */
bool last : 1;

View File

@@ -94,6 +94,8 @@ MASK = immediate("mask")
BFI_MASK = immediate("bfi_mask")
LOD_MODE = immediate("lod_mode", "enum agx_lod_mode")
DIM = immediate("dim", "enum agx_dim")
OFFSET = immediate("offset", "bool")
SHADOW = immediate("shadow", "bool")
SCOREBOARD = immediate("scoreboard")
ICOND = immediate("icond", "enum agx_icond")
FCOND = immediate("fcond", "enum agx_fcond")
@@ -197,14 +199,14 @@ op("fcmpsel",
encoding_32 = (0x02, 0x7F, 8, 10),
srcs = 4, imms = [FCOND])
# sources are coordinates, LOD, texture, sampler, offset
# sources are coordinates, LOD, texture, sampler, shadow/offset
# TODO: anything else?
op("texture_sample",
encoding_32 = (0x31, 0x7F, 8, 10), # XXX WRONG SIZE
srcs = 5, imms = [DIM, LOD_MODE, MASK, SCOREBOARD])
srcs = 5, imms = [DIM, LOD_MODE, MASK, SCOREBOARD, OFFSET, SHADOW])
op("texture_load",
encoding_32 = (0x71, 0x7F, 8, 10), # XXX WRONG SIZE
srcs = 5, imms = [DIM, LOD_MODE, MASK, SCOREBOARD])
srcs = 5, imms = [DIM, LOD_MODE, MASK, SCOREBOARD, OFFSET])
# sources are base, index
op("device_load",

View File

@@ -198,7 +198,9 @@ agx_optimizer_forward(agx_context *ctx)
agx_optimizer_fmov(defs, I);
/* Inline immediates if we can. TODO: systematic */
if (I->op != AGX_OPCODE_ST_VARY && I->op != AGX_OPCODE_ST_TILE && I->op != AGX_OPCODE_P_COMBINE)
if (I->op != AGX_OPCODE_ST_VARY && I->op != AGX_OPCODE_ST_TILE &&
I->op != AGX_OPCODE_P_COMBINE && I->op != AGX_OPCODE_TEXTURE_SAMPLE &&
I->op != AGX_OPCODE_TEXTURE_LOAD)
agx_optimizer_inline_imm(defs, I, info.nr_srcs, info.is_float);
}

View File

@@ -77,12 +77,15 @@ agx_pack_sampler(agx_index index, bool *flag)
}
static unsigned
agx_pack_sample_offset(agx_index index, bool *flag)
agx_pack_sample_compare_offset(agx_index index)
{
/* TODO: offsets */
assert(index.type == AGX_INDEX_NULL);
*flag = 0;
if (index.type == AGX_INDEX_NULL)
return 0;
assert(index.size == AGX_SIZE_32);
assert(index.value < 0x100);
assert_register_is_aligned(index);
return index.value;
}
static unsigned
@@ -576,18 +579,18 @@ agx_pack_instr(struct util_dynarray *emission, struct util_dynarray *fixups, agx
assert(I->mask != 0);
assert(I->format <= 0x10);
bool Rt, Ot, Ct, St;
bool Rt, Ct, St;
unsigned Tt;
unsigned R = agx_pack_memory_reg(I->dest[0], &Rt);
unsigned C = agx_pack_sample_coords(I->src[0], &Ct);
unsigned T = agx_pack_texture(I->src[2], &Tt);
unsigned S = agx_pack_sampler(I->src[3], &St);
unsigned O = agx_pack_sample_offset(I->src[4], &Ot);
unsigned O = agx_pack_sample_compare_offset(I->src[4]);
unsigned D = agx_pack_lod(I->src[1]);
unsigned U = 0; // TODO: what is sampler ureg?
unsigned q1 = 0; // XXX
unsigned q1 = I->shadow;
unsigned q2 = 0; // XXX
unsigned q3 = 12; // XXX
unsigned kill = 0; // helper invocation kill bit
@@ -603,7 +606,7 @@ agx_pack_instr(struct util_dynarray *emission, struct util_dynarray *fixups, agx
((T >> 6) << 14) |
((O & BITFIELD_MASK(6)) << 16) |
(q6 << 22) |
(Ot << 27) |
(I->offset << 27) |
((S >> 6) << 28) |
((O >> 6) << 30);