pan: Add a pass to resize I/O load/stores as needed by the varying layout

Reviewed-by: Lorenzo Rossi <lorenzo.rossi@collabora.com>
Acked-by: Eric R. Smith <eric.smith@collabora.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/38681>
This commit is contained in:
Faith Ekstrand 2025-12-04 11:37:51 -05:00 committed by Marge Bot
parent ceacec4cc9
commit c5fdc6faa8
3 changed files with 137 additions and 0 deletions

View file

@ -18,6 +18,7 @@ libpanfrost_compiler_files = files(
'pan_nir_lower_texel_buffer_index.c',
'pan_nir_lower_vertex_id.c',
'pan_nir_lower_xfb.c',
'pan_nir_resize_varying_io.c',
)
subdir('bifrost')

View file

@ -84,4 +84,7 @@ uint32_t pan_nir_collect_noperspective_varyings_fs(nir_shader *s);
void pan_nir_collect_varyings(nir_shader *s, struct pan_shader_info *info);
bool pan_nir_resize_varying_io(nir_shader *nir,
const struct pan_varying_layout *varying_layout);
#endif /* __PAN_NIR_H__ */

View file

@ -0,0 +1,133 @@
/*
* Copyright (c) 2025 Collabora, Ltd.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "pan_nir.h"
#include "nir_builder.h"
static bool
resize_io_intr(nir_builder *b, nir_intrinsic_instr *intr, void *data)
{
const struct pan_varying_layout *varying_layout = data;
bool is_load;
switch (intr->intrinsic) {
case nir_intrinsic_store_output:
case nir_intrinsic_store_per_view_output:
if (b->shader->info.stage != MESA_SHADER_VERTEX)
return false;
is_load = false;
break;
case nir_intrinsic_load_input:
case nir_intrinsic_load_interpolated_input:
if (b->shader->info.stage != MESA_SHADER_FRAGMENT)
return false;
is_load = true;
break;
default:
return false;
}
nir_io_semantics sem = nir_intrinsic_io_semantics(intr);
const struct pan_varying_slot *slot =
pan_varying_layout_find_slot(varying_layout, sem.location);
if (slot == NULL) {
if (is_load) {
b->cursor = nir_after_instr(&intr->instr);
nir_def *zero = nir_imm_zero(b, intr->def.num_components,
intr->def.bit_size);
nir_def_replace(&intr->def, zero);
} else {
assert(!"We should never have a mismatch on outputs");
nir_instr_remove(&intr->instr);
}
return true;
}
nir_alu_type data_type;
if (is_load) {
data_type = nir_intrinsic_dest_type(intr);
assert(intr->def.bit_size == nir_alu_type_get_type_size(data_type));
} else {
data_type = nir_intrinsic_src_type(intr);
assert(nir_src_bit_size(intr->src[0]) ==
nir_alu_type_get_type_size(data_type));
}
const unsigned slot_bit_size = nir_alu_type_get_type_size(slot->alu_type);
/* We trust the base type in the shader and only adjust the bit size */
const nir_alu_type slot_type =
nir_alu_type_get_base_type(data_type) | slot_bit_size;
if (slot_bit_size == nir_alu_type_get_type_size(data_type)) {
if (!sem.medium_precision)
return false;
/* There's nothing to actually lower but we still want to smash off
* mediump so the back-end doesn't screw anything up on us.
*
* TODO: This is a hack to work around the back-end. It really
* shouldn't care and should just do whatever load it's told.
*/
sem.medium_precision = false;
nir_intrinsic_set_io_semantics(intr, sem);
return true;
}
sem.medium_precision = false;
nir_intrinsic_set_io_semantics(intr, sem);
if (is_load) {
b->cursor = nir_after_instr(&intr->instr);
intr->def.bit_size = slot_bit_size;
nir_intrinsic_set_dest_type(intr, slot_type);
data = nir_type_convert(b, &intr->def, slot_type, data_type,
nir_rounding_mode_undef);
nir_def_rewrite_uses_after(&intr->def, data);
} else {
b->cursor = nir_before_instr(&intr->instr);
nir_def *data = nir_type_convert(b, intr->src[0].ssa, data_type,
slot_type, nir_rounding_mode_undef);
nir_src_rewrite(&intr->src[0], data);
nir_intrinsic_set_src_type(intr, slot_type);
}
return true;
}
bool
pan_nir_resize_varying_io(nir_shader *nir,
const struct pan_varying_layout *varying_layout)
{
return nir_shader_intrinsics_pass(nir, resize_io_intr,
nir_metadata_control_flow,
(void *)varying_layout);
}