agx: always reserve sampler #0 for txf

this is a lot simpler for non-monolithic programs and is unlikely to be a
meaningful performance problem.

Signed-off-by: Alyssa Rosenzweig <alyssa@rosenzweig.io>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/28483>
This commit is contained in:
Alyssa Rosenzweig 2024-03-15 19:28:50 -04:00 committed by Marge Bot
parent be81812a4b
commit caad4703aa
4 changed files with 43 additions and 59 deletions

View file

@ -969,23 +969,6 @@ agx_translate_bindless_handle(agx_builder *b, nir_src *handle, agx_index *base)
return agx_emit_extract(b, agx_src_index(handle), 1);
}
/*
* Contrary to NIR, in the hardware txf requires a special sampler. The sampler
* cannot be arbitrary, since the hardware honours the clamps so particular
* configuration is required for correct out-of-bounds behaviour for txf. This
* helper gets the shader's txf sampler, allocating one if needed.
*/
static agx_index
agx_txf_sampler(agx_context *ctx)
{
if (!ctx->out->uses_txf) {
ctx->out->txf_sampler = BITSET_LAST_BIT(ctx->nir->info.samplers_used);
ctx->out->uses_txf = true;
}
return agx_immediate(ctx->out->txf_sampler);
}
static unsigned
agx_expand_tex_to(agx_builder *b, nir_def *def, agx_index src, bool masked)
{
@ -1078,8 +1061,8 @@ agx_emit_image_load(agx_builder *b, agx_index dst, nir_intrinsic_instr *intr)
agx_index tmp = agx_vec_temp(b->shader, dst.size, 4);
agx_instr *I = agx_image_load_to(
b, tmp, coords, lod, bindless, texture, agx_txf_sampler(b->shader),
agx_null(), agx_tex_dim(dim, is_array), lod_mode, 0, false);
b, tmp, coords, lod, bindless, texture, agx_immediate(0), agx_null(),
agx_tex_dim(dim, is_array), lod_mode, 0, false);
I->mask = agx_expand_tex_to(b, &intr->def, tmp, true);
return NULL;
}
@ -1910,14 +1893,8 @@ agx_emit_tex(agx_builder *b, nir_tex_instr *instr)
{
agx_index coords = agx_null(), bindless = agx_immediate(0),
texture = agx_immediate(instr->texture_index),
sampler = agx_immediate(instr->sampler_index),
lod = agx_immediate(0), compare = agx_null(),
packed_offset = agx_null();
bool txf = (instr->op == nir_texop_txf || instr->op == nir_texop_txf_ms);
if (txf)
sampler = agx_txf_sampler(b->shader);
sampler = agx_immediate(0), lod = agx_immediate(0),
compare = agx_null(), packed_offset = agx_null();
for (unsigned i = 0; i < instr->num_srcs; ++i) {
agx_index index = agx_src_index(&instr->src[i].src);
@ -1944,7 +1921,6 @@ agx_emit_tex(agx_builder *b, nir_tex_instr *instr)
case nir_tex_src_texture_offset:
texture = index;
break;
case nir_tex_src_sampler_offset:
case nir_tex_src_sampler_handle:
sampler = index;
break;
@ -2005,7 +1981,7 @@ agx_emit_tex(agx_builder *b, nir_tex_instr *instr)
0, !agx_is_null(packed_offset), !agx_is_null(compare),
instr->op == nir_texop_lod, agx_gather_for_nir(instr));
if (txf)
if (instr->op == nir_texop_txf || instr->op == nir_texop_txf_ms)
I->op = AGX_OPCODE_TEXTURE_LOAD;
/* Destination masking doesn't seem to work properly for gathers (because

View file

@ -109,10 +109,6 @@ struct agx_shader_info {
/* Reads base vertex/instance */
bool uses_base_param;
/* Shader uses txf, requiring a workaround sampler in the given location */
bool uses_txf;
unsigned txf_sampler;
/* Number of 16-bit registers used by the main shader and preamble
* respectively.
*/

View file

@ -162,6 +162,8 @@ lower_buffer_texture(nir_builder *b, nir_tex_instr *tex)
nir_instr_remove(&tex->instr);
nir_builder_instr_insert(b, &tex->instr);
nir_tex_instr_add_src(tex, nir_tex_src_backend1, coord2d);
nir_steal_tex_src(tex, nir_tex_src_sampler_handle);
nir_steal_tex_src(tex, nir_tex_src_sampler_offset);
nir_block *else_block = nir_cursor_current_block(b->cursor);
nir_pop_if(b, nif);
@ -292,6 +294,20 @@ lower_regular_texture(nir_builder *b, nir_instr *instr, UNUSED void *data)
nir_tex_instr_add_src(tex, nir_tex_src_backend2, packed);
}
/* We reserve bound sampler #0, so we offset bound samplers by 1 and
* otherwise map bound samplers as-is.
*/
nir_def *sampler = nir_steal_tex_src(tex, nir_tex_src_sampler_offset);
if (!sampler)
sampler = nir_imm_intN_t(b, tex->sampler_index, 16);
if (!is_txf &&
nir_tex_instr_src_index(tex, nir_tex_src_sampler_handle) < 0) {
nir_tex_instr_add_src(tex, nir_tex_src_sampler_handle,
nir_iadd_imm(b, nir_u2u16(b, sampler), 1));
}
return true;
}

View file

@ -2641,15 +2641,10 @@ agx_build_meta_shader(struct agx_context *ctx, meta_shader_builder_t builder,
}
static unsigned
sampler_count(struct agx_context *ctx, struct agx_compiled_shader *cs,
enum pipe_shader_type stage)
sampler_count(struct agx_context *ctx, enum pipe_shader_type stage)
{
unsigned sampler_count = ctx->stage[stage].sampler_count;
if (cs->info.uses_txf)
sampler_count = MAX2(sampler_count, cs->info.txf_sampler + 1);
return sampler_count;
/* We reserve sampler #0 for txf so add 1 to the API count */
return ctx->stage[stage].sampler_count + 1;
}
static inline enum agx_sampler_states
@ -2658,9 +2653,8 @@ translate_sampler_state_count(struct agx_context *ctx,
enum pipe_shader_type stage)
{
/* Clamp to binding table maximum, anything larger will be bindless */
return agx_translate_sampler_state_count(
MIN2(sampler_count(ctx, cs, stage), 16),
ctx->stage[stage].custom_borders);
return agx_translate_sampler_state_count(MIN2(sampler_count(ctx, stage), 16),
ctx->stage[stage].custom_borders);
}
/*
@ -2872,7 +2866,7 @@ agx_upload_samplers(struct agx_batch *batch, struct agx_compiled_shader *cs,
{
struct agx_context *ctx = batch->ctx;
unsigned nr_samplers = sampler_count(ctx, cs, stage);
unsigned nr_samplers = sampler_count(ctx, stage);
bool custom_borders = ctx->stage[stage].custom_borders;
size_t sampler_length =
@ -2881,23 +2875,25 @@ agx_upload_samplers(struct agx_batch *batch, struct agx_compiled_shader *cs,
struct agx_ptr T =
agx_pool_alloc_aligned(&batch->pool, sampler_length * nr_samplers, 64);
uint8_t *out_sampler = T.cpu;
for (unsigned i = 0; i < nr_samplers; ++i) {
/* Sampler #0 is reserved for txf */
agx_pack(T.cpu, SAMPLER, cfg) {
/* Allow mipmapping. This is respected by txf, weirdly. */
cfg.mip_filter = AGX_MIP_FILTER_NEAREST;
/* Out-of-bounds reads must return 0 */
cfg.wrap_s = AGX_WRAP_CLAMP_TO_BORDER;
cfg.wrap_t = AGX_WRAP_CLAMP_TO_BORDER;
cfg.wrap_r = AGX_WRAP_CLAMP_TO_BORDER;
cfg.border_colour = AGX_BORDER_COLOUR_TRANSPARENT_BLACK;
}
/* Remaining samplers are API samplers */
uint8_t *out_sampler = (uint8_t *)T.cpu + sampler_length;
for (unsigned i = 0; i < ctx->stage[stage].sampler_count; ++i) {
struct agx_sampler_state *sampler = ctx->stage[stage].samplers[i];
struct agx_sampler_packed *out = (struct agx_sampler_packed *)out_sampler;
if (cs->info.uses_txf && i == cs->info.txf_sampler) {
agx_pack(out, SAMPLER, cfg) {
/* Allow mipmapping. This is respected by txf, weirdly. */
cfg.mip_filter = AGX_MIP_FILTER_NEAREST;
/* Out-of-bounds reads must return 0 */
cfg.wrap_s = AGX_WRAP_CLAMP_TO_BORDER;
cfg.wrap_t = AGX_WRAP_CLAMP_TO_BORDER;
cfg.wrap_r = AGX_WRAP_CLAMP_TO_BORDER;
cfg.border_colour = AGX_BORDER_COLOUR_TRANSPARENT_BLACK;
}
} else if (sampler) {
if (sampler) {
*out = sampler->desc;
if (custom_borders) {