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