glsl: validate MS/FS interstage in/out block

Mesh shader output block is always in array type, need
to validate if the mesh shader output array element type
match the fragment shader input type.

Reviewed-by: Ian Romanick <ian.d.romanick@intel.com>
Acked-by: Marek Olšák <marek.olsak@amd.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/36405>
This commit is contained in:
Qiang Yu 2025-02-25 10:06:28 +08:00 committed by Marge Bot
parent ae3c0ac9e9
commit faa9fea7d2

View file

@ -404,13 +404,15 @@ intrastage_match(nir_variable *a,
* Check if two interfaces match, according to interstage (in/out) interface
* matching rules.
*
* If \c extra_array_level is true, the consumer interface is required to be
* an array and the producer interface is required to be a non-array.
* This is used for tessellation control and geometry shader consumers.
* If \c producer_extra_array_level and/or \c consumer_extra_array_level is true,
* the producer and/or consumer interface is required to be an array.
* This is used for tessellation control and geometry shader consumers,
* or mesh shader producers.
*/
static bool
interstage_match(struct gl_shader_program *prog, nir_variable *producer,
nir_variable *consumer, bool extra_array_level)
nir_variable *consumer, bool producer_extra_array_level,
bool consumer_extra_array_level)
{
/* Types must match. */
if (consumer->interface_type != producer->interface_type) {
@ -432,12 +434,20 @@ interstage_match(struct gl_shader_program *prog, nir_variable *producer,
/* Ignore outermost array if geom shader */
const glsl_type *consumer_instance_type;
if (extra_array_level) {
if (consumer_extra_array_level) {
consumer_instance_type = glsl_get_array_element(consumer->type);
} else {
consumer_instance_type = consumer->type;
}
/* Ignore outermost array if mesh shader */
const glsl_type *producer_instance_type;
if (producer_extra_array_level) {
producer_instance_type = glsl_get_array_element(producer->type);
} else {
producer_instance_type = producer->type;
}
/* If a block is an array then it must match across shaders.
* Since unsized arrays have been ruled out, we can check this by just
* making sure the types are equal.
@ -445,8 +455,8 @@ interstage_match(struct gl_shader_program *prog, nir_variable *producer,
if ((is_interface_instance(consumer) &&
glsl_type_is_array(consumer_instance_type)) ||
(is_interface_instance(producer) &&
glsl_type_is_array(producer->type))) {
if (consumer_instance_type != producer->type)
glsl_type_is_array(producer_instance_type))) {
if (consumer_instance_type != producer_instance_type)
return false;
}
@ -614,9 +624,13 @@ gl_nir_validate_interstage_inout_blocks(struct gl_shader_program *prog,
_mesa_key_string_equal);
/* VS -> GS, VS -> TCS, VS -> TES, TES -> GS */
const bool extra_array_level = (producer->Stage == MESA_SHADER_VERTEX &&
consumer->Stage != MESA_SHADER_FRAGMENT) ||
consumer->Stage == MESA_SHADER_GEOMETRY;
const bool consumer_extra_array_level =
(producer->Stage == MESA_SHADER_VERTEX &&
consumer->Stage != MESA_SHADER_FRAGMENT) ||
consumer->Stage == MESA_SHADER_GEOMETRY;
/* MS -> FS */
const bool producer_extra_array_level = producer->Stage == MESA_SHADER_MESH;
/* Check that block re-declarations of gl_PerVertex are compatible
* across shaders: From OpenGL Shading Language 4.5, section
@ -739,7 +753,8 @@ gl_nir_validate_interstage_inout_blocks(struct gl_shader_program *prog,
}
if (producer_def &&
!interstage_match(prog, producer_def, var, extra_array_level)) {
!interstage_match(prog, producer_def, var, producer_extra_array_level,
consumer_extra_array_level)) {
linker_error(prog, "definitions of interface block `%s' do not "
"match\n", glsl_get_type_name(var->interface_type));
ralloc_free(mem_ctx);