xref: /aosp_15_r20/external/mesa3d/src/panfrost/util/pan_lower_image_index.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1 /*
2  * Copyright (C) 2024 Collabora, Ltd.
3  * SPDX-License-Identifier: MIT
4  */
5 
6 #include "compiler/nir/nir_builder.h"
7 #include "pan_ir.h"
8 
9 /* Vertex shader gets passed image attribute descriptors through the
10  * vertex attribute descriptor array. This forces us to apply an offset
11  * to all image access to get the actual attribute offset.
12  *
13  * The gallium driver emits the vertex attributes on each draw, and puts
14  * image attributes right after the vertex attributes, which implies passing
15  * vs_img_attrib_offset = util_bitcount64(nir->info.inputs_read).
16  *
17  * The Vulkan driver, on the other hand, uses
18  * VkVertexInputAttributeDescription to build a table of attributes passed
19  * to the shader. While there's no reason for the app to define more
20  * attributes than it actually uses in the vertex shader, it doesn't seem
21  * to be disallowed either. Not to mention that vkCmdSetVertexInputEXT()
22  * allows one to dynamically change the vertex input configuration, and
23  * possibly pass more attributes than referenced by the vertex shader bound to
24  * the command buffer at draw time. Of course, we could carry this information
25  * at the pipeline level, and re-emit the attribute array, but emitting only
26  * when the vertex input configuration is flagged dirty is simpler.
27  * In order for this to work, we use a fixed image attribute offset.
28  */
29 static bool
lower_image_intr(struct nir_builder * b,nir_intrinsic_instr * intr,void * data)30 lower_image_intr(struct nir_builder *b, nir_intrinsic_instr *intr, void *data)
31 {
32    if (intr->intrinsic != nir_intrinsic_image_load &&
33        intr->intrinsic != nir_intrinsic_image_store)
34       return false;
35 
36    unsigned img_attr_offset = *(unsigned *)data;
37    nir_def *index = intr->src[0].ssa;
38 
39    b->cursor = nir_before_instr(&intr->instr);
40 
41    index = nir_iadd_imm(b, index, img_attr_offset);
42    nir_src_rewrite(&intr->src[0], index);
43    return true;
44 }
45 
46 bool
pan_lower_image_index(nir_shader * shader,unsigned vs_img_attrib_offset)47 pan_lower_image_index(nir_shader *shader, unsigned vs_img_attrib_offset)
48 {
49    if (shader->info.stage != MESA_SHADER_VERTEX)
50       return false;
51 
52    return nir_shader_intrinsics_pass(
53       shader, lower_image_intr,
54       nir_metadata_control_flow, &vs_img_attrib_offset);
55 }
56