pan/compiler: Fix noperspective int varyings

Ints and floats do not need to match between VS and FS, some crazy
shaders might write an uint from the VS and read a noperspective float
from the FS.  There will be new tests in the conformance tests that
check that too shortly.

Is this a performance regression? yes.
Can we fix this easily? No, we'll need dynamic prolog/epilog linking.

Since maybe_noperspective is almost useless after this fix, the whole
logic has been removed

Signed-off-by: Lorenzo Rossi <lorenzo.rossi@collabora.com>
Reviewed-by: Christoph Pillmayer <christoph.pillmayer@arm.com>
Reviewed-by: Faith Ekstrand <faith.ekstrand@collabora.com>
Reviewed-by: Lars-Ivar Hesselberg Simonsen <lars-ivar.simonsen@arm.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/40844>
This commit is contained in:
Lorenzo Rossi 2026-04-04 19:43:39 +02:00 committed by Marge Bot
parent 6e67f2a996
commit 83fd45aa5a

View file

@ -78,72 +78,6 @@ has_noperspective_load(nir_function_impl *impl)
return false;
}
/**
* Returns a bitfield of VS outputs where it is known at compile-time that
* noperspective interpolation may be used at runtime. Similar to the
* noperspective_varyings_pan sysval, this bitfield only covers user varyings
* (starting at VARYING_SLOT_VAR0).
*
* Precomputed because struct outputs may be split into multiple store_output
* intrinsics. If any struct members are integers, then the whole struct
* cannot be noperspective.
*/
static uint32_t
get_maybe_noperspective_outputs(nir_function_impl *impl)
{
uint32_t used_outputs = 0;
uint32_t integer_outputs = 0;
/* nir_lower_io_vars_to_temporaries ensures all stores are in the exit block */
nir_block *block = nir_impl_last_block(impl);
nir_foreach_instr_safe(instr, block) {
if (instr->type != nir_instr_type_intrinsic)
continue;
nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(instr);
if (intrin->intrinsic != nir_intrinsic_store_output)
continue;
nir_io_semantics sem = nir_intrinsic_io_semantics(intrin);
if (sem.location < VARYING_SLOT_VAR0)
continue;
uint32_t location_bit = BITFIELD_BIT(sem.location - VARYING_SLOT_VAR0);
used_outputs |= location_bit;
nir_alu_type type = nir_intrinsic_src_type(intrin);
nir_alu_type base_type = nir_alu_type_get_base_type(type);
if (base_type == nir_type_int ||
base_type == nir_type_uint ||
base_type == nir_type_bool)
integer_outputs |= location_bit;
}
/* From the Vulkan 1.1.301 spec:
*
* "Output attributes of integer or unsigned integer type must always be
* flat shaded."
*
* From the OpenGL 4.6 spec:
*
* "Implementations need not support interpolation of output values of
* integer or unsigned integer type, as all such attributes must be flat
* shaded."
*
* So we can assume varyings that contain integers are never noperspective.
*/
return used_outputs & ~integer_outputs;
}
static bool
is_maybe_noperspective_output(unsigned location,
uint32_t maybe_noperspective_outputs)
{
return location >= VARYING_SLOT_VAR0 &&
maybe_noperspective_outputs & BITFIELD_BIT(location - VARYING_SLOT_VAR0);
}
static nir_def *
is_noperspective_output(nir_builder *b, unsigned location,
nir_def *noperspective_outputs)
@ -156,7 +90,6 @@ is_noperspective_output(nir_builder *b, unsigned location,
struct lower_noperspective_vs_state {
nir_def *pos_w;
uint32_t maybe_noperspective_outputs;
nir_def *noperspective_outputs;
};
@ -173,8 +106,8 @@ lower_noperspective_vs(nir_builder *b, nir_intrinsic_instr *intrin,
return false;
nir_io_semantics sem = nir_intrinsic_io_semantics(intrin);
if (!is_maybe_noperspective_output(sem.location,
state->maybe_noperspective_outputs))
/* Only generic varyings can be noperspective */
if (sem.location < VARYING_SLOT_VAR0)
return false;
b->cursor = nir_before_instr(&intrin->instr);
@ -251,10 +184,6 @@ pan_nir_lower_noperspective_vs(nir_shader *shader)
nir_function_impl *impl = nir_shader_get_entrypoint(shader);
uint32_t maybe_noperspective_outputs = get_maybe_noperspective_outputs(impl);
if (!maybe_noperspective_outputs)
return false;
nir_intrinsic_instr *pos_store = find_pos_store(impl);
/* gl_Position may be written, it can also be left undefined */
bool has_pos_w =
@ -274,7 +203,6 @@ pan_nir_lower_noperspective_vs(nir_shader *shader)
nir_def *noperspective_outputs = nir_load_noperspective_varyings_pan(&b);
struct lower_noperspective_vs_state state = {
.pos_w = pos_w,
.maybe_noperspective_outputs = maybe_noperspective_outputs,
.noperspective_outputs = noperspective_outputs,
};
nir_shader_intrinsics_pass(shader, lower_noperspective_vs,