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:
committed by
Marge Bot
parent
1106e2499e
commit
02b1ddeca6
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 =
|
||||
|
||||
Reference in New Issue
Block a user