About Social Code
aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon Perretta <simon.perretta@imgtec.com>2025-08-30 22:06:52 +0100
committerMarge Bot <marge-bot@fdo.invalid>2025-09-30 12:15:46 +0000
commitcb6c92150226148787a52c9ac96c12e2b7bb5f81 (patch)
tree074e55a149b639c9216828d46ca4fc0dc784bc29
parent9d48088428bfe52d234319d2ec9c5b01d56edbc8 (diff)
pvr, pco: add multiview compiler support, advertise extension
- Pass view index to fragment shader via linked flat varying. - Use view index instead of layer id for input attachments when required. Signed-off-by: Simon Perretta <simon.perretta@imgtec.com> Acked-by: Erik Faye-Lund <erik.faye-lund@collabora.com> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/37512>
-rw-r--r--docs/features.txt2
-rw-r--r--src/imagination/pco/pco.h6
-rw-r--r--src/imagination/pco/pco_data.h3
-rw-r--r--src/imagination/pco/pco_internal.h3
-rw-r--r--src/imagination/pco/pco_nir.c22
-rw-r--r--src/imagination/pco/pco_nir_pvfio.c65
-rw-r--r--src/imagination/pco/pco_nir_tex.c17
-rw-r--r--src/imagination/pco/pco_trans_nir.c1
-rw-r--r--src/imagination/vulkan/pvr_device.c10
-rw-r--r--src/imagination/vulkan/pvr_pipeline.c46
10 files changed, 167 insertions, 8 deletions
diff --git a/docs/features.txt b/docs/features.txt
index 62aa1c79078..5d778d6c1c4 100644
--- a/docs/features.txt
+++ b/docs/features.txt
@@ -452,7 +452,7 @@ Vulkan 1.1 -- all DONE: anv, hk, lvp, nvk, panvk/v10+, radv, tu, vn
VK_KHR_maintenance1 DONE (anv, dzn, hasvk, lvp, nvk, panvk, pvr, radv, tu, v3dv, vn)
VK_KHR_maintenance2 DONE (anv, dzn, hasvk, lvp, nvk, panvk, pvr, radv, tu, v3dv, vn)
VK_KHR_maintenance3 DONE (anv, dzn, hasvk, lvp, nvk, panvk, pvr, radv, tu, v3dv, vn)
- VK_KHR_multiview DONE (anv, dzn, hasvk, lvp, nvk, panvk/v10+, radv, tu, v3dv, vn)
+ VK_KHR_multiview DONE (anv, dzn, hasvk, lvp, nvk, panvk/v10+, pvr, radv, tu, v3dv, vn)
VK_KHR_relaxed_block_layout DONE (anv, dzn, hasvk, lvp, nvk, panvk, radv, tu, v3dv, vn)
VK_KHR_sampler_ycbcr_conversion DONE (anv, hasvk, lvp, nvk, panvk/v10+, radv, tu, v3dv, vn)
VK_KHR_shader_draw_parameters DONE (anv, dzn, hasvk, lvp, nvk, panvk, radv, tu, vn)
diff --git a/src/imagination/pco/pco.h b/src/imagination/pco/pco.h
index ed915c18c47..03e4b02103f 100644
--- a/src/imagination/pco/pco.h
+++ b/src/imagination/pco/pco.h
@@ -34,7 +34,11 @@ const struct spirv_to_nir_options *pco_spirv_options(void);
const nir_shader_compiler_options *pco_nir_options(void);
void pco_preprocess_nir(pco_ctx *ctx, nir_shader *nir);
-void pco_link_nir(pco_ctx *ctx, nir_shader *producer, nir_shader *consumer);
+void pco_link_nir(pco_ctx *ctx,
+ nir_shader *producer,
+ nir_shader *consumer,
+ pco_data *producer_data,
+ pco_data *consumer_data);
void pco_rev_link_nir(pco_ctx *ctx, nir_shader *producer, nir_shader *consumer);
void pco_lower_nir(pco_ctx *ctx, nir_shader *nir, pco_data *data);
void pco_postprocess_nir(pco_ctx *ctx, nir_shader *nir, pco_data *data);
diff --git a/src/imagination/pco/pco_data.h b/src/imagination/pco/pco_data.h
index 4dddec6ed53..d754f03427b 100644
--- a/src/imagination/pco/pco_data.h
+++ b/src/imagination/pco/pco_data.h
@@ -106,6 +106,8 @@ typedef struct _pco_fs_data {
pco_range sample_locations;
+ gl_varying_slot view_index_slot;
+
struct {
bool w; /** Whether the shader uses pos.w. */
bool z; /** Whether the shader uses pos.z */
@@ -224,6 +226,7 @@ typedef struct _pco_common_data {
bool robust_buffer_access;
bool image_2d_view_of_3d;
+ bool multiview;
} pco_common_data;
/** PCO shader data. */
diff --git a/src/imagination/pco/pco_internal.h b/src/imagination/pco/pco_internal.h
index 713946f262e..ab5a0ba4645 100644
--- a/src/imagination/pco/pco_internal.h
+++ b/src/imagination/pco/pco_internal.h
@@ -1756,6 +1756,9 @@ bool pco_legalize(pco_shader *shader);
bool pco_opt_comp_only_vecs(pco_shader *shader);
bool pco_nir_compute_instance_check(nir_shader *shader);
bool pco_nir_link_clip_cull_vars(nir_shader *producer, nir_shader *consumer);
+bool pco_nir_link_multiview(nir_shader *producer,
+ nir_shader *consumer,
+ pco_data *consumer_data);
bool pco_nir_lower_algebraic(nir_shader *shader);
bool pco_nir_lower_algebraic_late(nir_shader *shader);
bool pco_nir_lower_atomics(nir_shader *shader, pco_data *data);
diff --git a/src/imagination/pco/pco_nir.c b/src/imagination/pco/pco_nir.c
index 6ee2a6848a1..9ce0eb9acec 100644
--- a/src/imagination/pco/pco_nir.c
+++ b/src/imagination/pco/pco_nir.c
@@ -636,15 +636,27 @@ void pco_preprocess_nir(pco_ctx *ctx, nir_shader *nir)
}
}
+static bool can_remove_var(nir_variable *var, UNUSED void *data)
+{
+ return !var->data.always_active_io;
+}
+
/**
* \brief Performs linking optimizations on consecutive NIR shader stages.
*
* \param[in] ctx PCO compiler context.
* \param[in,out] producer NIR producer shader.
* \param[in,out] consumer NIR consumer shader.
+ * \param[in,out] producer_data Producer shader data.
+ * \param[in,out] consumer_data Consumer shader data.
*/
-void pco_link_nir(pco_ctx *ctx, nir_shader *producer, nir_shader *consumer)
+void pco_link_nir(pco_ctx *ctx,
+ nir_shader *producer,
+ nir_shader *consumer,
+ pco_data *producer_data,
+ pco_data *consumer_data)
{
+ pco_nir_link_multiview(producer, consumer, consumer_data);
pco_nir_link_clip_cull_vars(producer, consumer);
nir_lower_io_array_vars_to_elements(producer, consumer);
@@ -660,8 +672,12 @@ void pco_link_nir(pco_ctx *ctx, nir_shader *producer, nir_shader *consumer)
if (nir_link_opt_varyings(producer, consumer))
pco_nir_opt(ctx, consumer);
- NIR_PASS(_, producer, nir_remove_dead_variables, nir_var_shader_out, NULL);
- NIR_PASS(_, consumer, nir_remove_dead_variables, nir_var_shader_in, NULL);
+ nir_remove_dead_variables_options rdv = {
+ .can_remove_var = can_remove_var,
+ };
+
+ NIR_PASS(_, producer, nir_remove_dead_variables, nir_var_shader_out, &rdv);
+ NIR_PASS(_, consumer, nir_remove_dead_variables, nir_var_shader_in, &rdv);
bool progress = nir_remove_unused_varyings(producer, consumer);
nir_compact_varyings(producer, consumer, true);
diff --git a/src/imagination/pco/pco_nir_pvfio.c b/src/imagination/pco/pco_nir_pvfio.c
index b004261e5f0..04799be13f7 100644
--- a/src/imagination/pco/pco_nir_pvfio.c
+++ b/src/imagination/pco/pco_nir_pvfio.c
@@ -1549,3 +1549,68 @@ bool pco_nir_lower_interpolation(nir_shader *shader, pco_fs_data *fs)
return progress;
}
+
+static bool lower_load_view_index_fs(struct nir_builder *b,
+ nir_intrinsic_instr *intr,
+ void *cb_data)
+{
+ if (intr->intrinsic != nir_intrinsic_load_view_index)
+ return false;
+
+ nir_variable *view_index_var = cb_data;
+ b->cursor = nir_before_instr(&intr->instr);
+ nir_def_replace(&intr->def, nir_load_var(b, view_index_var));
+ nir_instr_free(&intr->instr);
+
+ return true;
+}
+
+bool pco_nir_link_multiview(nir_shader *producer,
+ nir_shader *consumer,
+ pco_data *consumer_data)
+{
+ if (producer->info.stage != MESA_SHADER_VERTEX ||
+ consumer->info.stage != MESA_SHADER_FRAGMENT ||
+ !consumer_data->common.multiview) {
+ return false;
+ }
+
+ /* Find unused varying slot for the view index. */
+ gl_varying_slot view_index_slot = VARYING_SLOT_VAR0;
+ nir_foreach_shader_out_variable (var, producer) {
+ view_index_slot = MAX2(view_index_slot, var->data.location + 1);
+ }
+ assert(view_index_slot < VARYING_SLOT_MAX);
+ consumer_data->fs.view_index_slot = view_index_slot;
+
+ /* Create output variable in the producer. */
+ nir_variable *view_index_var = nir_variable_create(producer,
+ nir_var_shader_out,
+ glsl_uint_type(),
+ "view_index");
+ view_index_var->data.location = view_index_slot;
+ view_index_var->data.interpolation = INTERP_MODE_FLAT;
+ view_index_var->data.always_active_io = true;
+
+ /* Store view index in the producer. */
+ nir_builder b = nir_builder_at(nir_after_block(
+ nir_impl_last_block(nir_shader_get_entrypoint(producer))));
+ nir_store_var(&b, view_index_var, nir_load_view_index(&b), 1);
+
+ /* Create input variable in the consumer. */
+ view_index_var = nir_variable_create(consumer,
+ nir_var_shader_in,
+ glsl_uint_type(),
+ "view_index");
+ view_index_var->data.location = view_index_slot;
+ view_index_var->data.interpolation = INTERP_MODE_FLAT;
+ view_index_var->data.always_active_io = true;
+
+ /* Lower view index loads in the consumer. */
+ nir_shader_intrinsics_pass(consumer,
+ lower_load_view_index_fs,
+ nir_metadata_all,
+ view_index_var);
+
+ return true;
+}
diff --git a/src/imagination/pco/pco_nir_tex.c b/src/imagination/pco/pco_nir_tex.c
index a07d4083b8c..74aefa2c7a8 100644
--- a/src/imagination/pco/pco_nir_tex.c
+++ b/src/imagination/pco/pco_nir_tex.c
@@ -1226,7 +1226,22 @@ static nir_def *lower_image(nir_builder *b, nir_instr *instr, void *cb_data)
frag_coords = nir_f2i32(b, frag_coords);
coords = nir_iadd(b, frag_coords, coords);
- nir_def *layer = nir_load_layer_id(b); /* TODO: view id for multiview? */
+ nir_def *layer = nir_load_layer_id(b);
+
+ /* Use the view index instead if we're in multiview. */
+ if (data->common.multiview) {
+ assert(data->fs.view_index_slot >= VARYING_SLOT_VAR0 &&
+ data->fs.view_index_slot < VARYING_SLOT_MAX);
+ layer = nir_load_input(b,
+ 1,
+ 32,
+ nir_imm_int(b, 0),
+ .dest_type = nir_type_uint32,
+ .io_semantics = (nir_io_semantics){
+ .location = data->fs.view_index_slot,
+ .num_slots = 1,
+ });
+ }
coords = nir_pad_vector(b, coords, 3);
coords = nir_vector_insert_imm(b, coords, layer, 2);
diff --git a/src/imagination/pco/pco_trans_nir.c b/src/imagination/pco/pco_trans_nir.c
index 32b65e356dc..962ec90d2a8 100644
--- a/src/imagination/pco/pco_trans_nir.c
+++ b/src/imagination/pco/pco_trans_nir.c
@@ -2113,6 +2113,7 @@ static pco_instr *trans_intr(trans_ctx *tctx, nir_intrinsic_instr *intr)
case nir_intrinsic_load_base_instance:
case nir_intrinsic_load_base_vertex:
case nir_intrinsic_load_draw_id:
+ case nir_intrinsic_load_view_index:
/* Compute sysvals. */
case nir_intrinsic_load_local_invocation_index:
diff --git a/src/imagination/vulkan/pvr_device.c b/src/imagination/vulkan/pvr_device.c
index 82c0d5f9c5a..6b0ce3419c9 100644
--- a/src/imagination/vulkan/pvr_device.c
+++ b/src/imagination/vulkan/pvr_device.c
@@ -189,6 +189,7 @@ static void pvr_physical_device_get_supported_extensions(
.KHR_maintenance1 = true,
.KHR_maintenance2 = true,
.KHR_maintenance3 = true,
+ .KHR_multiview = true,
.KHR_present_id2 = PVR_USE_WSI_PLATFORM,
.KHR_present_wait2 = PVR_USE_WSI_PLATFORM,
.KHR_separate_depth_stencil_layouts = true,
@@ -293,6 +294,11 @@ static void pvr_physical_device_get_supported_features(
/* Vulkan 1.2 / VK_KHR_imageless_framebuffer */
.imagelessFramebuffer = true,
+ /* Vulkan 1.1 / VK_KHR_multiview */
+ .multiview = true,
+ .multiviewGeometryShader = false,
+ .multiviewTessellationShader = false,
+
/* Vulkan 1.2 / VK_KHR_timeline_semaphore */
.timelineSemaphore = true,
@@ -586,6 +592,10 @@ static bool pvr_physical_device_get_properties(
.maxPerSetDescriptors = PVR_MAX_DESCRIPTORS_PER_SET,
.maxMemoryAllocationSize = max_memory_alloc_size,
+ /* Vulkan 1.1 / VK_KHR_multiview */
+ .maxMultiviewViewCount = PVR_MAX_MULTIVIEW,
+ .maxMultiviewInstanceIndex = (1 << 27) - 1,
+
/* Vulkan 1.2 / VK_KHR_driver_properties */
.driverID = VK_DRIVER_ID_IMAGINATION_OPEN_SOURCE_MESA,
.driverName = "Imagination open-source Mesa driver",
diff --git a/src/imagination/vulkan/pvr_pipeline.c b/src/imagination/vulkan/pvr_pipeline.c
index 49673af035b..5fdc2d07e3a 100644
--- a/src/imagination/vulkan/pvr_pipeline.c
+++ b/src/imagination/vulkan/pvr_pipeline.c
@@ -400,6 +400,11 @@ static VkResult pvr_pds_vertex_attrib_programs_create_and_upload(
input.draw_index_register = sys_vals[SYSTEM_VALUE_DRAW_ID].start;
}
+ if (sys_vals[SYSTEM_VALUE_VIEW_INDEX].count > 0) {
+ input.flags |= PVR_PDS_VERTEX_FLAGS_VIEW_INDEX_REQUIRED;
+ input.view_index_register = sys_vals[SYSTEM_VALUE_VIEW_INDEX].start;
+ }
+
pvr_pds_setup_doutu(&input.usc_task_control,
0,
usc_temp_count,
@@ -930,6 +935,10 @@ static void pvr_pipeline_finish(struct pvr_device *device,
vk_object_base_finish(&pipeline->base);
}
+static void pvr_early_init_shader_data(pco_data *data,
+ nir_shader *nir,
+ const void *pCreateInfo);
+
static void
pvr_preprocess_shader_data(pco_data *data,
nir_shader *nir,
@@ -987,6 +996,7 @@ static VkResult pvr_compute_pipeline_compile(
if (result != VK_SUCCESS)
goto err_free_build_context;
+ pvr_early_init_shader_data(&shader_data, nir, pCreateInfo);
pco_preprocess_nir(pco_ctx, nir);
pvr_preprocess_shader_data(&shader_data, nir, pCreateInfo, layout, NULL);
pco_lower_nir(pco_ctx, nir, &shader_data);
@@ -1651,7 +1661,7 @@ static void pvr_alloc_vs_sysvals(pco_data *data, nir_shader *nir)
gl_system_value sys_vals[] = {
SYSTEM_VALUE_VERTEX_ID, SYSTEM_VALUE_INSTANCE_ID,
SYSTEM_VALUE_BASE_INSTANCE, SYSTEM_VALUE_BASE_VERTEX,
- SYSTEM_VALUE_DRAW_ID,
+ SYSTEM_VALUE_DRAW_ID, SYSTEM_VALUE_VIEW_INDEX,
};
for (unsigned u = 0; u < ARRAY_SIZE(sys_vals); ++u) {
@@ -2570,6 +2580,29 @@ static void pvr_postprocess_shader_data(pco_data *data,
/* TODO: common things, like large constants being put into shareds. */
}
+static void pvr_early_init_shader_data(pco_data *data,
+ nir_shader *nir,
+ const void *pCreateInfo)
+{
+ const VkGraphicsPipelineCreateInfo *pGraphicsCreateInfo = pCreateInfo;
+
+ switch (nir->info.stage) {
+ case MESA_SHADER_VERTEX:
+ case MESA_SHADER_FRAGMENT: {
+ VK_FROM_HANDLE(pvr_render_pass, pass, pGraphicsCreateInfo->renderPass);
+ data->common.multiview = pass->multiview_enabled;
+
+ break;
+ }
+
+ case MESA_SHADER_COMPUTE:
+ break;
+
+ default:
+ UNREACHABLE("Unsupported stage.");
+ }
+}
+
/* Compiles and uploads shaders and PDS programs. */
static VkResult
pvr_graphics_pipeline_compile(struct pvr_device *const device,
@@ -2594,6 +2627,7 @@ pvr_graphics_pipeline_compile(struct pvr_device *const device,
nir_shader *producer = NULL;
nir_shader *consumer = NULL;
pco_data shader_data[MESA_SHADER_STAGES] = { 0 };
+ pco_data *producer_data = NULL;
nir_shader *nir_shaders[MESA_SHADER_STAGES] = { 0 };
pco_shader *pco_shaders[MESA_SHADER_STAGES] = { 0 };
pco_shader **vs = &pco_shaders[MESA_SHADER_VERTEX];
@@ -2621,6 +2655,9 @@ pvr_graphics_pipeline_compile(struct pvr_device *const device,
if (result != VK_SUCCESS)
goto err_free_build_context;
+ pvr_early_init_shader_data(&shader_data[stage],
+ nir_shaders[stage],
+ pCreateInfo);
pco_preprocess_nir(pco_ctx, nir_shaders[stage]);
}
@@ -2629,9 +2666,14 @@ pvr_graphics_pipeline_compile(struct pvr_device *const device,
continue;
if (producer)
- pco_link_nir(pco_ctx, producer, nir_shaders[stage]);
+ pco_link_nir(pco_ctx,
+ producer,
+ nir_shaders[stage],
+ producer_data,
+ &shader_data[stage]);
producer = nir_shaders[stage];
+ producer_data = &shader_data[stage];
}
for (mesa_shader_stage stage = MESA_SHADER_STAGES; stage-- > 0;) {