diff --git a/src/asahi/compiler/agx_compile.c b/src/asahi/compiler/agx_compile.c index cd2bbc984b3..f2cc5010c6a 100644 --- a/src/asahi/compiler/agx_compile.c +++ b/src/asahi/compiler/agx_compile.c @@ -774,6 +774,23 @@ 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 agx_instr * agx_emit_image_store(agx_builder *b, nir_intrinsic_instr *instr) { @@ -1432,11 +1449,8 @@ agx_emit_tex(agx_builder *b, nir_tex_instr *instr) bool txf = (instr->op == nir_texop_txf || instr->op == nir_texop_txf_ms); - /* txf loads a texture without an associated sampler, but in the hardware - * there is an associated load of a sampler. This requires that the driver - * upload a dummy sampler. - */ - b->shader->out->needs_dummy_sampler |= txf; + if (txf) + sampler = agx_txf_sampler(b->shader); for (unsigned i = 0; i < instr->num_srcs; ++i) { agx_index index = agx_src_index(&instr->src[i].src); diff --git a/src/asahi/compiler/agx_compile.h b/src/asahi/compiler/agx_compile.h index f2763fb1421..277ba155aae 100644 --- a/src/asahi/compiler/agx_compile.h +++ b/src/asahi/compiler/agx_compile.h @@ -125,8 +125,9 @@ struct agx_shader_info { /* Shader is incompatible with triangle merging */ bool disable_tri_merging; - /* Shader needs a dummy sampler (for txf reads) */ - bool needs_dummy_sampler; + /* Shader uses txf, requiring a workaround sampler in the given location */ + bool uses_txf; + unsigned txf_sampler; /* Number of bindful textures, images used */ unsigned nr_bindful_textures, nr_bindful_images; diff --git a/src/asahi/lib/agx_helpers.h b/src/asahi/lib/agx_helpers.h index 78c2d3e340b..e5175d963d7 100644 --- a/src/asahi/lib/agx_helpers.h +++ b/src/asahi/lib/agx_helpers.h @@ -12,7 +12,7 @@ static inline enum agx_sampler_states agx_translate_sampler_state_count(unsigned count, bool extended) { - assert(count <= 16 && "max 16 sampler state registers supported"); + assert(count <= 17 && "max 17 sampler state registers supported"); if (count == 0) { return AGX_SAMPLER_STATES_0; diff --git a/src/gallium/drivers/asahi/agx_state.c b/src/gallium/drivers/asahi/agx_state.c index 5adf89017a0..6e21212fa05 100644 --- a/src/gallium/drivers/asahi/agx_state.c +++ b/src/gallium/drivers/asahi/agx_state.c @@ -1973,12 +1973,12 @@ static unsigned sampler_count(struct agx_context *ctx, struct agx_compiled_shader *cs, enum pipe_shader_type stage) { - unsigned nr_samplers = ctx->stage[stage].sampler_count; + unsigned sampler_count = ctx->stage[stage].sampler_count; - if (cs->info.needs_dummy_sampler) - nr_samplers = MAX2(nr_samplers, 1); + if (cs->info.uses_txf) + sampler_count = MAX2(sampler_count, cs->info.txf_sampler + 1); - return nr_samplers; + return sampler_count; } static inline enum agx_sampler_states @@ -2107,31 +2107,35 @@ agx_build_pipeline(struct agx_batch *batch, struct agx_compiled_shader *cs, /* TODO: Dirty track me to save some CPU cycles and maybe improve caching */ uint8_t *out_sampler = T_samp.cpu; - if (nr_samplers && ctx->stage[stage].sampler_count == 0) { - /* Configuration is irrelevant for the dummy sampler */ - agx_pack(out_sampler, SAMPLER, cfg) - ; - } else { - for (unsigned i = 0; i < nr_samplers; ++i) { - struct agx_sampler_state *sampler = ctx->stage[stage].samplers[i]; - struct agx_sampler_packed *out = - (struct agx_sampler_packed *)out_sampler; + for (unsigned i = 0; i < nr_samplers; ++i) { + struct agx_sampler_state *sampler = ctx->stage[stage].samplers[i]; + struct agx_sampler_packed *out = (struct agx_sampler_packed *)out_sampler; - if (sampler) { - *out = sampler->desc; + 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; - if (custom_borders) { - memcpy(out_sampler + AGX_SAMPLER_LENGTH, &sampler->border, - AGX_BORDER_LENGTH); - } else { - assert(!sampler->uses_custom_border && "invalid combination"); - } - } else { - memset(out, 0, sampler_length); + /* 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) { + *out = sampler->desc; - out_sampler += sampler_length; + if (custom_borders) { + memcpy(out_sampler + AGX_SAMPLER_LENGTH, &sampler->border, + AGX_BORDER_LENGTH); + } else { + assert(!sampler->uses_custom_border && "invalid combination"); + } + } else { + memset(out, 0, sampler_length); } + + out_sampler += sampler_length; } struct agx_usc_builder b =