tu: Adjust multiview lowering for GS

When there is a GS, run multiview lowering for the VS and multiply the
per-primitive varying stride by the view count since all outputs are now
per-view.

Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/40153>
This commit is contained in:
Connor Abbott 2026-02-27 18:16:51 -05:00 committed by Marge Bot
parent be84cb6211
commit f497e3913b
4 changed files with 40 additions and 19 deletions

View file

@ -17,7 +17,8 @@
* gl_Position = ((1ull << gl_ViewIndex) & view_mask) ? gl_Position : vec4(0.);
*
* Scan backwards until we find the gl_Position write (there should only be
* one).
* one). This also needs to happen with multi-position, which doesn't respect
* the view mask.
*/
static bool
lower_multiview_mask(nir_shader *nir, uint32_t *mask)
@ -70,15 +71,18 @@ lower_multiview_mask(nir_shader *nir, uint32_t *mask)
}
bool
tu_nir_lower_multiview(nir_shader *nir, uint32_t mask, struct tu_device *dev)
tu_nir_lower_multiview(nir_shader *nir, uint32_t mask, struct tu_device *dev,
bool last_stage)
{
bool progress = false;
nir_lower_multiview_options options = {
.view_mask = mask,
.allowed_per_view_outputs = VARYING_BIT_POS
.allowed_per_view_outputs =
last_stage ? VARYING_BIT_POS : ~0ull,
};
if (!dev->physical_device->info->props.supports_multiview_mask)
if (!dev->physical_device->info->props.supports_multiview_mask &&
last_stage)
NIR_PASS(progress, nir, lower_multiview_mask, &options.view_mask);
unsigned num_views = util_logbase2(mask) + 1;
@ -95,10 +99,16 @@ tu_nir_lower_multiview(nir_shader *nir, uint32_t mask, struct tu_device *dev)
*/
nir_assign_io_var_locations(nir, nir_var_shader_out);
if (!last_stage) {
/* We will store outputs per-view and loop over all active views in the
* shader.
*/
NIR_PASS(progress, nir, nir_lower_multiview, options);
/* In addition to the generic checks done by NIR, check that we don't
* overflow VPC with the extra copies of gl_Position.
*/
if (!TU_DEBUG(NOMULTIPOS) &&
} else if (!TU_DEBUG(NOMULTIPOS) &&
num_views <= max_views_for_multipos && nir->num_outputs + (num_views - 1) <= 32 &&
nir_can_lower_multiview(nir, options)) {
/* It appears that the multiview mask is ignored when multi-position

View file

@ -1304,7 +1304,7 @@ tu6_emit_geom_tess_consts(struct tu_cs *cs,
if (gs && !hs) {
tu6_emit_vs_params(cs, ir3_const_state(vs), vs->constlen,
vs->output_size, gs->gs.vertices_in);
vs->output_size, gs->gs.vertices_in * vs->view_count);
}
if (hs) {
@ -1312,9 +1312,9 @@ tu6_emit_geom_tess_consts(struct tu_cs *cs,
tu_get_tess_iova<CHIP>(dev, &tess_factor_iova, &tess_param_iova);
uint32_t ds_params[8] = {
gs ? ds->output_size * gs->gs.vertices_in * 4 : 0, /* ds primitive stride */
ds->output_size * 4, /* ds vertex stride */
hs->output_size, /* hs vertex stride (dwords) */
gs ? ds->output_size * ds->view_count * gs->gs.vertices_in * 4 : 0, /* ds primitive stride */
ds->output_size * 4, /* ds vertex stride */
hs->output_size, /* hs vertex stride (dwords) */
hs->tess.tcs_vertices_out,
tess_param_iova,
tess_param_iova >> 32,
@ -1330,8 +1330,8 @@ tu6_emit_geom_tess_consts(struct tu_cs *cs,
if (gs) {
const struct ir3_shader_variant *prev = ds ? ds : vs;
uint32_t gs_params[4] = {
prev->output_size * gs->gs.vertices_in * 4, /* gs primitive stride */
prev->output_size * 4, /* gs vertex stride */
prev->output_size * prev->view_count * gs->gs.vertices_in * 4, /* gs primitive stride */
prev->output_size * 4, /* gs vertex stride */
0,
0,
};
@ -1887,8 +1887,12 @@ tu_pipeline_builder_compile_shaders(struct tu_pipeline_builder *builder,
if (builder->state &
VK_GRAPHICS_PIPELINE_LIBRARY_PRE_RASTERIZATION_SHADERS_BIT_EXT) {
keys[MESA_SHADER_VERTEX].multiview_mask =
builder->graphics_state.mv->view_mask;
for (int i = MESA_SHADER_VERTEX; i <= MESA_SHADER_GEOMETRY; i++) {
if (nir[i] || stage_infos[i]) {
keys[i].multiview_mask =
builder->graphics_state.mv->view_mask;
}
}
mesa_shader_stage last_pre_rast_stage = MESA_SHADER_VERTEX;
for (int i = MESA_SHADER_GEOMETRY; i >= MESA_SHADER_VERTEX; i--) {
@ -4972,7 +4976,7 @@ tu_compute_pipeline_create(VkDevice device,
nir_shader_as_str(nir, pipeline->base.executables_mem_ctx) : NULL;
struct tu_shader_info info = {};
tu_lower_nir(dev, nir, &key, &info);
tu_lower_nir(dev, nir, &key, &ir3_key, &info);
result = tu_shader_create(dev, &shader, nir, &key, &info, &ir3_key,
pipeline_blake3, sizeof(pipeline_blake3), layout,
executable_info);

View file

@ -2934,6 +2934,7 @@ void
tu_lower_nir(struct tu_device *dev,
nir_shader *nir,
const struct tu_shader_key *key,
const struct ir3_shader_key *ir3_key,
struct tu_shader_info *info)
{
const nir_opt_access_options access_options = {
@ -2999,9 +3000,13 @@ tu_lower_nir(struct tu_device *dev,
*/
ir3_nir_lower_io_vars_to_temporaries(nir);
if (nir->info.stage == MESA_SHADER_VERTEX && key->multiview_mask) {
tu_nir_lower_multiview(nir, key->multiview_mask, dev);
}
bool is_last_stage =
(nir->info.stage == MESA_SHADER_VERTEX && !ir3_key->has_gs && !ir3_key->tessellation);
if (nir->info.stage == MESA_SHADER_VERTEX && key->multiview_mask)
tu_nir_lower_multiview(nir, key->multiview_mask, dev, is_last_stage);
if (nir->info.stage == MESA_SHADER_GEOMETRY)
nir->info.view_mask = key->multiview_mask;
if (!key->multiview_mask)
tu_nir_lower_view_to_zero(nir);
@ -3347,7 +3352,7 @@ tu_compile_shaders(struct tu_device *device,
int64_t stage_start = os_time_get_nano();
tu_lower_nir(device, nir[stage], &keys[stage], &info[stage]);
tu_lower_nir(device, nir[stage], &keys[stage], &ir3_key, &info[stage]);
stage_feedbacks[stage].duration += os_time_get_nano() - stage_start;
}

View file

@ -146,7 +146,8 @@ void
tu_destroy_softfloat(struct tu_device *device);
bool
tu_nir_lower_multiview(nir_shader *nir, uint32_t mask, struct tu_device *dev);
tu_nir_lower_multiview(nir_shader *nir, uint32_t mask, struct tu_device *dev,
bool last_stage);
bool
tu_nir_lower_ray_queries(nir_shader *nir);
@ -202,6 +203,7 @@ void
tu_lower_nir(struct tu_device *dev,
nir_shader *nir,
const struct tu_shader_key *key,
const struct ir3_shader_key *ir3_key,
struct tu_shader_info *info);
VkResult