1 /*
2 * Copyright © 2024 Imagination Technologies Ltd.
3 *
4 * SPDX-License-Identifier: MIT
5 */
6
7 /**
8 * \file pco_nir_pvfio.c
9 *
10 * \brief PCO NIR per-vertex/fragment input/output passes.
11 */
12
13 #include "compiler/glsl_types.h"
14 #include "compiler/shader_enums.h"
15 #include "nir.h"
16 #include "nir_builder.h"
17 #include "pco.h"
18 #include "pco_builder.h"
19 #include "pco_internal.h"
20 #include "util/macros.h"
21 #include "util/u_dynarray.h"
22
23 #include <assert.h>
24 #include <stdbool.h>
25 #include <stdio.h>
26
27 /** Per-fragment output pass state. */
28 struct pfo_state {
29 struct util_dynarray stores; /** List of fragment stores. */
30 pco_fs_data *fs; /** Fragment-specific data. */
31 };
32
33 /**
34 * \brief Returns a NIR intrinsic instruction if a NIR instruction matches the
35 * provided intrinsic op.
36 *
37 * \param[in] instr NIR instruction.
38 * \param[in] op Desired intrinsic op.
39 * \return The intrinsic instruction, else NULL.
40 */
is_intr(nir_instr * instr,nir_intrinsic_op op)41 static inline nir_intrinsic_instr *is_intr(nir_instr *instr,
42 nir_intrinsic_op op)
43 {
44 nir_intrinsic_instr *intr = NULL;
45
46 if (instr->type != nir_instr_type_intrinsic)
47 return NULL;
48
49 intr = nir_instr_as_intrinsic(instr);
50
51 if (intr->intrinsic != op)
52 return NULL;
53
54 return intr;
55 }
56
57 /**
58 * \brief Returns the GLSL base type equivalent of a pipe format.
59 *
60 * \param[in] format Pipe format.
61 * \return The GLSL base type, or GLSL_TYPE_ERROR if unsupported/invalid.
62 */
base_type_from_fmt(enum pipe_format format)63 static inline enum glsl_base_type base_type_from_fmt(enum pipe_format format)
64 {
65 const struct util_format_description *desc = util_format_description(format);
66 int chan = util_format_get_first_non_void_channel(format);
67 if (chan < 0)
68 return GLSL_TYPE_ERROR;
69
70 switch (desc->channel[chan].type) {
71 case UTIL_FORMAT_TYPE_UNSIGNED:
72 return GLSL_TYPE_UINT;
73
74 case UTIL_FORMAT_TYPE_SIGNED:
75 return GLSL_TYPE_INT;
76
77 case UTIL_FORMAT_TYPE_FLOAT:
78 return GLSL_TYPE_FLOAT;
79
80 default:
81 break;
82 }
83
84 return GLSL_TYPE_ERROR;
85 }
86
87 /**
88 * \brief Lowers a PFO-related instruction.
89 *
90 * \param[in] b NIR builder.
91 * \param[in] instr NIR instruction.
92 * \param[in] cb_data User callback data.
93 * \return True if the instruction was lowered.
94 */
lower_pfo(nir_builder * b,nir_instr * instr,void * cb_data)95 static bool lower_pfo(nir_builder *b, nir_instr *instr, void *cb_data)
96 {
97 struct pfo_state *state = cb_data;
98
99 /* TODO NEXT: move into separate function (pack_to_pbe),
100 * and use data from driver to actually figure out format stuff!
101 */
102 nir_intrinsic_instr *intr;
103 if ((intr = is_intr(instr, nir_intrinsic_store_output))) {
104 /* Skip stores we've already processed. */
105 util_dynarray_foreach (&state->stores, nir_intrinsic_instr *, store) {
106 if (intr == *store)
107 return false;
108 }
109
110 nir_src *value = &intr->src[0];
111 nir_src *offset = &intr->src[1];
112
113 /* TODO: more accurate way of detecting this */
114 /* Already in expected format. */
115 if (b->shader->info.internal && nir_src_num_components(*value) == 1) {
116 util_dynarray_append(&state->stores, nir_intrinsic_instr *, intr);
117 return false;
118 }
119
120 assert(nir_src_as_uint(*offset) == 0);
121
122 assert(nir_src_num_components(*value) == 4);
123 assert(nir_src_bit_size(*value) == 32);
124
125 struct nir_io_semantics io_semantics = nir_intrinsic_io_semantics(intr);
126 gl_frag_result location = io_semantics.location;
127
128 enum pipe_format format = state->fs->output_formats[location];
129
130 unsigned format_bits = util_format_get_blocksizebits(format);
131 assert(!(format_bits % 32));
132
133 /* Update the type of the stored variable. */
134 nir_variable *var = nir_find_variable_with_location(b->shader,
135 nir_var_shader_out,
136 location);
137 assert(var);
138
139 var->type = glsl_simple_explicit_type(base_type_from_fmt(format),
140 format_bits / 32,
141 1,
142 0,
143 false,
144 0);
145
146 b->cursor = nir_after_block(
147 nir_impl_last_block(nir_shader_get_entrypoint(b->shader)));
148
149 /* Emit and track the new store. */
150 /* TODO: support other formats. */
151 if (format == PIPE_FORMAT_R8G8B8A8_UNORM) {
152 nir_intrinsic_instr *store =
153 nir_store_output(b,
154 nir_pack_unorm_4x8(b, value->ssa),
155 offset->ssa,
156 .base = nir_intrinsic_base(intr),
157 .write_mask = 1,
158 .component = 0,
159 .src_type = nir_type_uint32,
160 .io_semantics = io_semantics,
161 .io_xfb = nir_intrinsic_io_xfb(intr),
162 .io_xfb2 = nir_intrinsic_io_xfb2(intr));
163 util_dynarray_append(&state->stores, nir_intrinsic_instr *, store);
164 } else {
165 unreachable();
166 }
167
168 /* Remove the old store. */
169 b->cursor = nir_instr_remove(instr);
170
171 return true;
172 }
173
174 return false;
175 }
176
177 /**
178 * \brief Per-fragment output pass.
179 *
180 * \param[in,out] nir NIR shader.
181 * \param[in,out] fs Fragment shader-specific data.
182 * \return True if the pass made progress.
183 */
pco_nir_pfo(nir_shader * nir,pco_fs_data * fs)184 bool pco_nir_pfo(nir_shader *nir, pco_fs_data *fs)
185 {
186 assert(nir->info.stage == MESA_SHADER_FRAGMENT);
187
188 struct pfo_state state = { .fs = fs };
189 util_dynarray_init(&state.stores, NULL);
190
191 bool progress =
192 nir_shader_instructions_pass(nir, lower_pfo, nir_metadata_none, &state);
193
194 util_dynarray_fini(&state.stores);
195
196 return progress;
197 }
198
199 /**
200 * \brief Per-vertex input pass.
201 *
202 * \param[in,out] nir NIR shader.
203 * \param[in,out] vs Vertex shader-specific data.
204 * \return True if the pass made progress.
205 */
pco_nir_pvi(nir_shader * nir,pco_vs_data * vs)206 bool pco_nir_pvi(nir_shader *nir, pco_vs_data *vs)
207 {
208 assert(nir->info.stage == MESA_SHADER_VERTEX);
209
210 puts("finishme: pco_nir_pvi");
211
212 /* TODO: format conversion and inserting unspecified/missing components. */
213
214 return false;
215 }
216