asahi,agx: Fix txf sampler

Bizarrely, the clamps/wrap modes are respected so we need to set them
appropriately for correct out-of-bounds behaviour (returning all zero). That in
turn means we can't use whatever sampler is already there, instead we need to
allocate a dedicated sampler just for txf. Good news is we have an extra sampler
state register available for the purpose.

Signed-off-by: Alyssa Rosenzweig <alyssa@rosenzweig.io>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/24258>
This commit is contained in:
Alyssa Rosenzweig
2023-06-07 16:14:13 -04:00
committed by Marge Bot
parent 1106e2499e
commit 02b1ddeca6
4 changed files with 51 additions and 32 deletions
+19 -5
View File
@@ -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);
+3 -2
View File
@@ -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;
+1 -1
View File
@@ -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;
+28 -24
View File
@@ -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 =