From d93f9d6d1a85268df41923d5750a211bd61d8100 Mon Sep 17 00:00:00 2001 From: Benjamin Lee Date: Fri, 15 Nov 2024 20:58:37 -0800 Subject: [PATCH] panvk: use static noperspective when statically linking VS and FS This triggers with VK_EXT_graphics_pipeline_library and monolithic pipelines when VK_PIPELINE_CREATE_LINK_TIME_OPTIMIZATION_BIT_EXT is set. With VK_EXT_shader_object, it would trigger when VK_SHADER_CREATE_LINK_STAGE_BIT_EXT is set on both VS and FS. The fast-linking interface from [1] (unmerged) would allow us to use the optimization with monolithic pipelines. [1]: https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/27024/diffs?commit_id=cd1ba4d6375764680c5ced9be90f5519b92eefe6 Signed-off-by: Benjamin Lee Reviewed-by: Boris Brezillon Part-of: --- src/panfrost/util/pan_collect_varyings.c | 7 ++--- src/panfrost/util/pan_ir.h | 1 + src/panfrost/vulkan/panvk_vX_shader.c | 34 ++++++++++++++++++++---- 3 files changed, 34 insertions(+), 8 deletions(-) diff --git a/src/panfrost/util/pan_collect_varyings.c b/src/panfrost/util/pan_collect_varyings.c index 1282fe428d0..03b43bfd79f 100644 --- a/src/panfrost/util/pan_collect_varyings.c +++ b/src/panfrost/util/pan_collect_varyings.c @@ -183,8 +183,8 @@ collect_noperspective_varyings_fs(UNUSED nir_builder *b, return false; } -static uint32_t -nir_collect_noperspective_varyings_fs(nir_shader *s) +uint32_t +pan_nir_collect_noperspective_varyings_fs(nir_shader *s) { assert(s->info.stage == MESA_SHADER_FRAGMENT); @@ -233,5 +233,6 @@ pan_nir_collect_varyings(nir_shader *s, struct pan_shader_info *info) info->varyings.input_count = count; if (s->info.stage == MESA_SHADER_FRAGMENT) - info->varyings.noperspective = nir_collect_noperspective_varyings_fs(s); + info->varyings.noperspective = + pan_nir_collect_noperspective_varyings_fs(s); } diff --git a/src/panfrost/util/pan_ir.h b/src/panfrost/util/pan_ir.h index 76b328beb49..d7130b4a63c 100644 --- a/src/panfrost/util/pan_ir.h +++ b/src/panfrost/util/pan_ir.h @@ -401,6 +401,7 @@ bool pan_lower_xfb(nir_shader *nir); bool pan_lower_image_index(nir_shader *shader, unsigned vs_img_attrib_offset); +uint32_t pan_nir_collect_noperspective_varyings_fs(nir_shader *s); void pan_nir_collect_varyings(nir_shader *s, struct pan_shader_info *info); /* diff --git a/src/panfrost/vulkan/panvk_vX_shader.c b/src/panfrost/vulkan/panvk_vX_shader.c index d009225b863..b5e61885352 100644 --- a/src/panfrost/vulkan/panvk_vX_shader.c +++ b/src/panfrost/vulkan/panvk_vX_shader.c @@ -121,7 +121,6 @@ panvk_lower_sysvals(nir_builder *b, nir_instr *instr, void *data) bit_size, num_comps); break; case nir_intrinsic_load_noperspective_varyings_pan: - /* TODO: lower this to a constant with monolithic pipelines */ /* TODO: use a VS epilog specialized on constant noperspective_varyings * with VK_EXT_graphics_pipeline_libraries and VK_EXT_shader_object */ assert(b->shader->info.stage == MESA_SHADER_VERTEX); @@ -495,6 +494,7 @@ panvk_lower_nir(struct panvk_device *dev, nir_shader *nir, uint32_t set_layout_count, struct vk_descriptor_set_layout *const *set_layouts, const struct vk_pipeline_robustness_state *rs, + uint32_t *noperspective_varyings, const struct panfrost_compile_inputs *compile_input, struct panvk_shader *shader) { @@ -606,6 +606,10 @@ panvk_lower_nir(struct panvk_device *dev, nir_shader *nir, if (PAN_ARCH < 9 && stage == MESA_SHADER_VERTEX) NIR_PASS(_, nir, pan_lower_image_index, MAX_VS_ATTRIBS); + if (noperspective_varyings && stage == MESA_SHADER_VERTEX) + NIR_PASS(_, nir, pan_nir_lower_static_noperspective, + *noperspective_varyings); + NIR_PASS(_, nir, nir_shader_instructions_pass, panvk_lower_sysvals, nir_metadata_control_flow, NULL); } @@ -880,6 +884,7 @@ static VkResult panvk_compile_shader(struct panvk_device *dev, struct vk_shader_compile_info *info, const struct vk_graphics_pipeline_state *state, + uint32_t *noperspective_varyings, const VkAllocationCallbacks *pAllocator, struct vk_shader **shader_out) { @@ -908,7 +913,7 @@ panvk_compile_shader(struct panvk_device *dev, nir->info.fs.uses_sample_shading = true; panvk_lower_nir(dev, nir, info->set_layout_count, info->set_layouts, - info->robustness, &inputs, shader); + info->robustness, noperspective_varyings, &inputs, shader); result = panvk_compile_nir(dev, nir, info->flags, &inputs, shader); @@ -937,11 +942,20 @@ panvk_compile_shaders(struct vk_device *vk_dev, uint32_t shader_count, struct vk_shader **shaders_out) { struct panvk_device *dev = to_panvk_device(vk_dev); + bool use_static_noperspective = false; + uint32_t noperspective_varyings = 0; VkResult result; - uint32_t i; + int32_t i; - for (i = 0; i < shader_count; i++) { - result = panvk_compile_shader(dev, &infos[i], state, pAllocator, + /* Vulkan runtime passes us shaders in stage order, so the FS will always + * be last if it exists. Iterate shaders in reverse order to ensure FS is + * processed before VS. */ + for (i = shader_count - 1; i >= 0; i--) { + uint32_t *noperspective_varyings_ptr = + use_static_noperspective ? &noperspective_varyings : NULL; + result = panvk_compile_shader(dev, &infos[i], state, + noperspective_varyings_ptr, + pAllocator, &shaders_out[i]); /* Clean up NIR for the current shader */ @@ -949,6 +963,16 @@ panvk_compile_shaders(struct vk_device *vk_dev, uint32_t shader_count, if (result != VK_SUCCESS) goto err_cleanup; + + /* If we are linking VS and FS, we can use the static interpolation + * qualifiers from the FS in the VS. */ + if (infos[i].nir->info.stage == MESA_SHADER_FRAGMENT) { + struct panvk_shader *shader = + container_of(shaders_out[i], struct panvk_shader, vk); + + use_static_noperspective = true; + noperspective_varyings = shader->info.varyings.noperspective; + } } /* TODO: If we get multiple shaders here, we can perform part of the link