1bf215546Sopenharmony_ci/*
2bf215546Sopenharmony_ci * Copyright © 2018 Intel Corporation
3bf215546Sopenharmony_ci *
4bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
5bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"),
6bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation
7bf215546Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8bf215546Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the
9bf215546Sopenharmony_ci * Software is furnished to do so, subject to the following conditions:
10bf215546Sopenharmony_ci *
11bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the next
12bf215546Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the
13bf215546Sopenharmony_ci * Software.
14bf215546Sopenharmony_ci *
15bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18bf215546Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19bf215546Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20bf215546Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21bf215546Sopenharmony_ci * IN THE SOFTWARE.
22bf215546Sopenharmony_ci */
23bf215546Sopenharmony_ci
24bf215546Sopenharmony_ci#include "nir.h"
25bf215546Sopenharmony_ci#include "GL/gl.h"
26bf215546Sopenharmony_ci#include "gl_nir.h"
27bf215546Sopenharmony_ci#include "gl_nir_linker.h"
28bf215546Sopenharmony_ci#include "linker_util.h"
29bf215546Sopenharmony_ci#include "main/shader_types.h"
30bf215546Sopenharmony_ci#include "main/consts_exts.h"
31bf215546Sopenharmony_ci#include "main/shaderobj.h"
32bf215546Sopenharmony_ci#include "ir_uniform.h" /* for gl_uniform_storage */
33bf215546Sopenharmony_ci
34bf215546Sopenharmony_ci/**
35bf215546Sopenharmony_ci * This file included general link methods, using NIR, instead of IR as
36bf215546Sopenharmony_ci * the counter-part glsl/linker.cpp
37bf215546Sopenharmony_ci */
38bf215546Sopenharmony_ci
39bf215546Sopenharmony_civoid
40bf215546Sopenharmony_cigl_nir_opts(nir_shader *nir)
41bf215546Sopenharmony_ci{
42bf215546Sopenharmony_ci   bool progress;
43bf215546Sopenharmony_ci
44bf215546Sopenharmony_ci   do {
45bf215546Sopenharmony_ci      progress = false;
46bf215546Sopenharmony_ci
47bf215546Sopenharmony_ci      NIR_PASS_V(nir, nir_lower_vars_to_ssa);
48bf215546Sopenharmony_ci
49bf215546Sopenharmony_ci      /* Linking deals with unused inputs/outputs, but here we can remove
50bf215546Sopenharmony_ci       * things local to the shader in the hopes that we can cleanup other
51bf215546Sopenharmony_ci       * things. This pass will also remove variables with only stores, so we
52bf215546Sopenharmony_ci       * might be able to make progress after it.
53bf215546Sopenharmony_ci       */
54bf215546Sopenharmony_ci      NIR_PASS(progress, nir, nir_remove_dead_variables,
55bf215546Sopenharmony_ci               nir_var_function_temp | nir_var_shader_temp |
56bf215546Sopenharmony_ci               nir_var_mem_shared,
57bf215546Sopenharmony_ci               NULL);
58bf215546Sopenharmony_ci
59bf215546Sopenharmony_ci      NIR_PASS(progress, nir, nir_opt_copy_prop_vars);
60bf215546Sopenharmony_ci      NIR_PASS(progress, nir, nir_opt_dead_write_vars);
61bf215546Sopenharmony_ci
62bf215546Sopenharmony_ci      if (nir->options->lower_to_scalar) {
63bf215546Sopenharmony_ci         NIR_PASS_V(nir, nir_lower_alu_to_scalar,
64bf215546Sopenharmony_ci                    nir->options->lower_to_scalar_filter, NULL);
65bf215546Sopenharmony_ci         NIR_PASS_V(nir, nir_lower_phis_to_scalar, false);
66bf215546Sopenharmony_ci      }
67bf215546Sopenharmony_ci
68bf215546Sopenharmony_ci      NIR_PASS_V(nir, nir_lower_alu);
69bf215546Sopenharmony_ci      NIR_PASS_V(nir, nir_lower_pack);
70bf215546Sopenharmony_ci      NIR_PASS(progress, nir, nir_copy_prop);
71bf215546Sopenharmony_ci      NIR_PASS(progress, nir, nir_opt_remove_phis);
72bf215546Sopenharmony_ci      NIR_PASS(progress, nir, nir_opt_dce);
73bf215546Sopenharmony_ci      if (nir_opt_trivial_continues(nir)) {
74bf215546Sopenharmony_ci         progress = true;
75bf215546Sopenharmony_ci         NIR_PASS(progress, nir, nir_copy_prop);
76bf215546Sopenharmony_ci         NIR_PASS(progress, nir, nir_opt_dce);
77bf215546Sopenharmony_ci      }
78bf215546Sopenharmony_ci      NIR_PASS(progress, nir, nir_opt_if, 0);
79bf215546Sopenharmony_ci      NIR_PASS(progress, nir, nir_opt_dead_cf);
80bf215546Sopenharmony_ci      NIR_PASS(progress, nir, nir_opt_cse);
81bf215546Sopenharmony_ci      NIR_PASS(progress, nir, nir_opt_peephole_select, 8, true, true);
82bf215546Sopenharmony_ci
83bf215546Sopenharmony_ci      NIR_PASS(progress, nir, nir_opt_phi_precision);
84bf215546Sopenharmony_ci      NIR_PASS(progress, nir, nir_opt_algebraic);
85bf215546Sopenharmony_ci      NIR_PASS(progress, nir, nir_opt_constant_folding);
86bf215546Sopenharmony_ci
87bf215546Sopenharmony_ci      if (!nir->info.flrp_lowered) {
88bf215546Sopenharmony_ci         unsigned lower_flrp =
89bf215546Sopenharmony_ci            (nir->options->lower_flrp16 ? 16 : 0) |
90bf215546Sopenharmony_ci            (nir->options->lower_flrp32 ? 32 : 0) |
91bf215546Sopenharmony_ci            (nir->options->lower_flrp64 ? 64 : 0);
92bf215546Sopenharmony_ci
93bf215546Sopenharmony_ci         if (lower_flrp) {
94bf215546Sopenharmony_ci            bool lower_flrp_progress = false;
95bf215546Sopenharmony_ci
96bf215546Sopenharmony_ci            NIR_PASS(lower_flrp_progress, nir, nir_lower_flrp,
97bf215546Sopenharmony_ci                     lower_flrp,
98bf215546Sopenharmony_ci                     false /* always_precise */);
99bf215546Sopenharmony_ci            if (lower_flrp_progress) {
100bf215546Sopenharmony_ci               NIR_PASS(progress, nir,
101bf215546Sopenharmony_ci                        nir_opt_constant_folding);
102bf215546Sopenharmony_ci               progress = true;
103bf215546Sopenharmony_ci            }
104bf215546Sopenharmony_ci         }
105bf215546Sopenharmony_ci
106bf215546Sopenharmony_ci         /* Nothing should rematerialize any flrps, so we only need to do this
107bf215546Sopenharmony_ci          * lowering once.
108bf215546Sopenharmony_ci          */
109bf215546Sopenharmony_ci         nir->info.flrp_lowered = true;
110bf215546Sopenharmony_ci      }
111bf215546Sopenharmony_ci
112bf215546Sopenharmony_ci      NIR_PASS(progress, nir, nir_opt_undef);
113bf215546Sopenharmony_ci      NIR_PASS(progress, nir, nir_opt_conditional_discard);
114bf215546Sopenharmony_ci      if (nir->options->max_unroll_iterations) {
115bf215546Sopenharmony_ci         NIR_PASS(progress, nir, nir_opt_loop_unroll);
116bf215546Sopenharmony_ci      }
117bf215546Sopenharmony_ci   } while (progress);
118bf215546Sopenharmony_ci}
119bf215546Sopenharmony_ci
120bf215546Sopenharmony_cistatic void
121bf215546Sopenharmony_cigl_nir_link_opts(nir_shader *producer, nir_shader *consumer)
122bf215546Sopenharmony_ci{
123bf215546Sopenharmony_ci   if (producer->options->lower_to_scalar) {
124bf215546Sopenharmony_ci      NIR_PASS_V(producer, nir_lower_io_to_scalar_early, nir_var_shader_out);
125bf215546Sopenharmony_ci      NIR_PASS_V(consumer, nir_lower_io_to_scalar_early, nir_var_shader_in);
126bf215546Sopenharmony_ci   }
127bf215546Sopenharmony_ci
128bf215546Sopenharmony_ci   nir_lower_io_arrays_to_elements(producer, consumer);
129bf215546Sopenharmony_ci
130bf215546Sopenharmony_ci   gl_nir_opts(producer);
131bf215546Sopenharmony_ci   gl_nir_opts(consumer);
132bf215546Sopenharmony_ci
133bf215546Sopenharmony_ci   if (nir_link_opt_varyings(producer, consumer))
134bf215546Sopenharmony_ci      gl_nir_opts(consumer);
135bf215546Sopenharmony_ci
136bf215546Sopenharmony_ci   NIR_PASS_V(producer, nir_remove_dead_variables, nir_var_shader_out, NULL);
137bf215546Sopenharmony_ci   NIR_PASS_V(consumer, nir_remove_dead_variables, nir_var_shader_in, NULL);
138bf215546Sopenharmony_ci
139bf215546Sopenharmony_ci   if (nir_remove_unused_varyings(producer, consumer)) {
140bf215546Sopenharmony_ci      NIR_PASS_V(producer, nir_lower_global_vars_to_local);
141bf215546Sopenharmony_ci      NIR_PASS_V(consumer, nir_lower_global_vars_to_local);
142bf215546Sopenharmony_ci
143bf215546Sopenharmony_ci      gl_nir_opts(producer);
144bf215546Sopenharmony_ci      gl_nir_opts(consumer);
145bf215546Sopenharmony_ci
146bf215546Sopenharmony_ci      /* Optimizations can cause varyings to become unused.
147bf215546Sopenharmony_ci       * nir_compact_varyings() depends on all dead varyings being removed so
148bf215546Sopenharmony_ci       * we need to call nir_remove_dead_variables() again here.
149bf215546Sopenharmony_ci       */
150bf215546Sopenharmony_ci      NIR_PASS_V(producer, nir_remove_dead_variables, nir_var_shader_out,
151bf215546Sopenharmony_ci                 NULL);
152bf215546Sopenharmony_ci      NIR_PASS_V(consumer, nir_remove_dead_variables, nir_var_shader_in,
153bf215546Sopenharmony_ci                 NULL);
154bf215546Sopenharmony_ci   }
155bf215546Sopenharmony_ci
156bf215546Sopenharmony_ci   nir_link_varying_precision(producer, consumer);
157bf215546Sopenharmony_ci}
158bf215546Sopenharmony_ci
159bf215546Sopenharmony_cistatic bool
160bf215546Sopenharmony_cican_remove_uniform(nir_variable *var, UNUSED void *data)
161bf215546Sopenharmony_ci{
162bf215546Sopenharmony_ci   /* Section 2.11.6 (Uniform Variables) of the OpenGL ES 3.0.3 spec
163bf215546Sopenharmony_ci    * says:
164bf215546Sopenharmony_ci    *
165bf215546Sopenharmony_ci    *     "All members of a named uniform block declared with a shared or
166bf215546Sopenharmony_ci    *     std140 layout qualifier are considered active, even if they are not
167bf215546Sopenharmony_ci    *     referenced in any shader in the program. The uniform block itself is
168bf215546Sopenharmony_ci    *     also considered active, even if no member of the block is
169bf215546Sopenharmony_ci    *     referenced."
170bf215546Sopenharmony_ci    *
171bf215546Sopenharmony_ci    * Although the spec doesn't state it std430 layouts are expect to behave
172bf215546Sopenharmony_ci    * the same way. If the variable is in a uniform block with one of those
173bf215546Sopenharmony_ci    * layouts, do not eliminate it.
174bf215546Sopenharmony_ci    */
175bf215546Sopenharmony_ci   if (nir_variable_is_in_block(var) &&
176bf215546Sopenharmony_ci       (glsl_get_ifc_packing(var->interface_type) !=
177bf215546Sopenharmony_ci        GLSL_INTERFACE_PACKING_PACKED))
178bf215546Sopenharmony_ci      return false;
179bf215546Sopenharmony_ci
180bf215546Sopenharmony_ci   if (glsl_get_base_type(glsl_without_array(var->type)) ==
181bf215546Sopenharmony_ci       GLSL_TYPE_SUBROUTINE)
182bf215546Sopenharmony_ci      return false;
183bf215546Sopenharmony_ci
184bf215546Sopenharmony_ci   /* Uniform initializers could get used by another stage. However if its a
185bf215546Sopenharmony_ci    * hidden uniform then it should be safe to remove as this was a constant
186bf215546Sopenharmony_ci    * variable that has been lowered to a uniform.
187bf215546Sopenharmony_ci    */
188bf215546Sopenharmony_ci   if (var->constant_initializer && var->data.how_declared != nir_var_hidden)
189bf215546Sopenharmony_ci      return false;
190bf215546Sopenharmony_ci
191bf215546Sopenharmony_ci   return true;
192bf215546Sopenharmony_ci}
193bf215546Sopenharmony_ci
194bf215546Sopenharmony_ci/**
195bf215546Sopenharmony_ci * Built-in / reserved GL variables names start with "gl_"
196bf215546Sopenharmony_ci */
197bf215546Sopenharmony_cistatic inline bool
198bf215546Sopenharmony_ciis_gl_identifier(const char *s)
199bf215546Sopenharmony_ci{
200bf215546Sopenharmony_ci   return s && s[0] == 'g' && s[1] == 'l' && s[2] == '_';
201bf215546Sopenharmony_ci}
202bf215546Sopenharmony_ci
203bf215546Sopenharmony_cistatic bool
204bf215546Sopenharmony_ciinout_has_same_location(const nir_variable *var, unsigned stage)
205bf215546Sopenharmony_ci{
206bf215546Sopenharmony_ci   if (!var->data.patch &&
207bf215546Sopenharmony_ci       ((var->data.mode == nir_var_shader_out &&
208bf215546Sopenharmony_ci         stage == MESA_SHADER_TESS_CTRL) ||
209bf215546Sopenharmony_ci        (var->data.mode == nir_var_shader_in &&
210bf215546Sopenharmony_ci         (stage == MESA_SHADER_TESS_CTRL || stage == MESA_SHADER_TESS_EVAL ||
211bf215546Sopenharmony_ci          stage == MESA_SHADER_GEOMETRY))))
212bf215546Sopenharmony_ci      return true;
213bf215546Sopenharmony_ci   else
214bf215546Sopenharmony_ci      return false;
215bf215546Sopenharmony_ci}
216bf215546Sopenharmony_ci
217bf215546Sopenharmony_ci/**
218bf215546Sopenharmony_ci * Create gl_shader_variable from nir_variable.
219bf215546Sopenharmony_ci */
220bf215546Sopenharmony_cistatic struct gl_shader_variable *
221bf215546Sopenharmony_cicreate_shader_variable(struct gl_shader_program *shProg,
222bf215546Sopenharmony_ci                       const nir_variable *in,
223bf215546Sopenharmony_ci                       const char *name, const struct glsl_type *type,
224bf215546Sopenharmony_ci                       const struct glsl_type *interface_type,
225bf215546Sopenharmony_ci                       bool use_implicit_location, int location,
226bf215546Sopenharmony_ci                       const struct glsl_type *outermost_struct_type)
227bf215546Sopenharmony_ci{
228bf215546Sopenharmony_ci   /* Allocate zero-initialized memory to ensure that bitfield padding
229bf215546Sopenharmony_ci    * is zero.
230bf215546Sopenharmony_ci    */
231bf215546Sopenharmony_ci   struct gl_shader_variable *out = rzalloc(shProg,
232bf215546Sopenharmony_ci                                            struct gl_shader_variable);
233bf215546Sopenharmony_ci   if (!out)
234bf215546Sopenharmony_ci      return NULL;
235bf215546Sopenharmony_ci
236bf215546Sopenharmony_ci   /* Since gl_VertexID may be lowered to gl_VertexIDMESA, but applications
237bf215546Sopenharmony_ci    * expect to see gl_VertexID in the program resource list.  Pretend.
238bf215546Sopenharmony_ci    */
239bf215546Sopenharmony_ci   if (in->data.mode == nir_var_system_value &&
240bf215546Sopenharmony_ci       in->data.location == SYSTEM_VALUE_VERTEX_ID_ZERO_BASE) {
241bf215546Sopenharmony_ci      out->name.string = ralloc_strdup(shProg, "gl_VertexID");
242bf215546Sopenharmony_ci   } else if ((in->data.mode == nir_var_shader_out &&
243bf215546Sopenharmony_ci               in->data.location == VARYING_SLOT_TESS_LEVEL_OUTER) ||
244bf215546Sopenharmony_ci              (in->data.mode == nir_var_system_value &&
245bf215546Sopenharmony_ci               in->data.location == SYSTEM_VALUE_TESS_LEVEL_OUTER)) {
246bf215546Sopenharmony_ci      out->name.string = ralloc_strdup(shProg, "gl_TessLevelOuter");
247bf215546Sopenharmony_ci      type = glsl_array_type(glsl_float_type(), 4, 0);
248bf215546Sopenharmony_ci   } else if ((in->data.mode == nir_var_shader_out &&
249bf215546Sopenharmony_ci               in->data.location == VARYING_SLOT_TESS_LEVEL_INNER) ||
250bf215546Sopenharmony_ci              (in->data.mode == nir_var_system_value &&
251bf215546Sopenharmony_ci               in->data.location == SYSTEM_VALUE_TESS_LEVEL_INNER)) {
252bf215546Sopenharmony_ci      out->name.string = ralloc_strdup(shProg, "gl_TessLevelInner");
253bf215546Sopenharmony_ci      type = glsl_array_type(glsl_float_type(), 2, 0);
254bf215546Sopenharmony_ci   } else {
255bf215546Sopenharmony_ci      out->name.string = ralloc_strdup(shProg, name);
256bf215546Sopenharmony_ci   }
257bf215546Sopenharmony_ci
258bf215546Sopenharmony_ci   resource_name_updated(&out->name);
259bf215546Sopenharmony_ci
260bf215546Sopenharmony_ci   if (!out->name.string)
261bf215546Sopenharmony_ci      return NULL;
262bf215546Sopenharmony_ci
263bf215546Sopenharmony_ci   /* The ARB_program_interface_query spec says:
264bf215546Sopenharmony_ci    *
265bf215546Sopenharmony_ci    *     "Not all active variables are assigned valid locations; the
266bf215546Sopenharmony_ci    *     following variables will have an effective location of -1:
267bf215546Sopenharmony_ci    *
268bf215546Sopenharmony_ci    *      * uniforms declared as atomic counters;
269bf215546Sopenharmony_ci    *
270bf215546Sopenharmony_ci    *      * members of a uniform block;
271bf215546Sopenharmony_ci    *
272bf215546Sopenharmony_ci    *      * built-in inputs, outputs, and uniforms (starting with "gl_"); and
273bf215546Sopenharmony_ci    *
274bf215546Sopenharmony_ci    *      * inputs or outputs not declared with a "location" layout
275bf215546Sopenharmony_ci    *        qualifier, except for vertex shader inputs and fragment shader
276bf215546Sopenharmony_ci    *        outputs."
277bf215546Sopenharmony_ci    */
278bf215546Sopenharmony_ci   if (glsl_get_base_type(in->type) == GLSL_TYPE_ATOMIC_UINT ||
279bf215546Sopenharmony_ci       is_gl_identifier(in->name) ||
280bf215546Sopenharmony_ci       !(in->data.explicit_location || use_implicit_location)) {
281bf215546Sopenharmony_ci      out->location = -1;
282bf215546Sopenharmony_ci   } else {
283bf215546Sopenharmony_ci      out->location = location;
284bf215546Sopenharmony_ci   }
285bf215546Sopenharmony_ci
286bf215546Sopenharmony_ci   out->type = type;
287bf215546Sopenharmony_ci   out->outermost_struct_type = outermost_struct_type;
288bf215546Sopenharmony_ci   out->interface_type = interface_type;
289bf215546Sopenharmony_ci   out->component = in->data.location_frac;
290bf215546Sopenharmony_ci   out->index = in->data.index;
291bf215546Sopenharmony_ci   out->patch = in->data.patch;
292bf215546Sopenharmony_ci   out->mode = in->data.mode;
293bf215546Sopenharmony_ci   out->interpolation = in->data.interpolation;
294bf215546Sopenharmony_ci   out->precision = in->data.precision;
295bf215546Sopenharmony_ci   out->explicit_location = in->data.explicit_location;
296bf215546Sopenharmony_ci
297bf215546Sopenharmony_ci   return out;
298bf215546Sopenharmony_ci}
299bf215546Sopenharmony_ci
300bf215546Sopenharmony_cistatic bool
301bf215546Sopenharmony_ciadd_shader_variable(const struct gl_constants *consts,
302bf215546Sopenharmony_ci                    struct gl_shader_program *shProg,
303bf215546Sopenharmony_ci                    struct set *resource_set,
304bf215546Sopenharmony_ci                    unsigned stage_mask,
305bf215546Sopenharmony_ci                    GLenum programInterface, nir_variable *var,
306bf215546Sopenharmony_ci                    const char *name, const struct glsl_type *type,
307bf215546Sopenharmony_ci                    bool use_implicit_location, int location,
308bf215546Sopenharmony_ci                    bool inouts_share_location,
309bf215546Sopenharmony_ci                    const struct glsl_type *outermost_struct_type)
310bf215546Sopenharmony_ci{
311bf215546Sopenharmony_ci   const struct glsl_type *interface_type = var->interface_type;
312bf215546Sopenharmony_ci
313bf215546Sopenharmony_ci   if (outermost_struct_type == NULL) {
314bf215546Sopenharmony_ci      if (var->data.from_named_ifc_block) {
315bf215546Sopenharmony_ci         const char *interface_name = glsl_get_type_name(interface_type);
316bf215546Sopenharmony_ci
317bf215546Sopenharmony_ci         if (glsl_type_is_array(interface_type)) {
318bf215546Sopenharmony_ci            /* Issue #16 of the ARB_program_interface_query spec says:
319bf215546Sopenharmony_ci             *
320bf215546Sopenharmony_ci             * "* If a variable is a member of an interface block without an
321bf215546Sopenharmony_ci             *    instance name, it is enumerated using just the variable name.
322bf215546Sopenharmony_ci             *
323bf215546Sopenharmony_ci             *  * If a variable is a member of an interface block with an
324bf215546Sopenharmony_ci             *    instance name, it is enumerated as "BlockName.Member", where
325bf215546Sopenharmony_ci             *    "BlockName" is the name of the interface block (not the
326bf215546Sopenharmony_ci             *    instance name) and "Member" is the name of the variable."
327bf215546Sopenharmony_ci             *
328bf215546Sopenharmony_ci             * In particular, it indicates that it should be "BlockName",
329bf215546Sopenharmony_ci             * not "BlockName[array length]".  The conformance suite and
330bf215546Sopenharmony_ci             * dEQP both require this behavior.
331bf215546Sopenharmony_ci             *
332bf215546Sopenharmony_ci             * Here, we unwrap the extra array level added by named interface
333bf215546Sopenharmony_ci             * block array lowering so we have the correct variable type.  We
334bf215546Sopenharmony_ci             * also unwrap the interface type when constructing the name.
335bf215546Sopenharmony_ci             *
336bf215546Sopenharmony_ci             * We leave interface_type the same so that ES 3.x SSO pipeline
337bf215546Sopenharmony_ci             * validation can enforce the rules requiring array length to
338bf215546Sopenharmony_ci             * match on interface blocks.
339bf215546Sopenharmony_ci             */
340bf215546Sopenharmony_ci            type = glsl_get_array_element(type);
341bf215546Sopenharmony_ci
342bf215546Sopenharmony_ci            interface_name =
343bf215546Sopenharmony_ci               glsl_get_type_name(glsl_get_array_element(interface_type));
344bf215546Sopenharmony_ci         }
345bf215546Sopenharmony_ci
346bf215546Sopenharmony_ci         name = ralloc_asprintf(shProg, "%s.%s", interface_name, name);
347bf215546Sopenharmony_ci      }
348bf215546Sopenharmony_ci   }
349bf215546Sopenharmony_ci
350bf215546Sopenharmony_ci   switch (glsl_get_base_type(type)) {
351bf215546Sopenharmony_ci   case GLSL_TYPE_STRUCT: {
352bf215546Sopenharmony_ci      /* The ARB_program_interface_query spec says:
353bf215546Sopenharmony_ci       *
354bf215546Sopenharmony_ci       *     "For an active variable declared as a structure, a separate entry
355bf215546Sopenharmony_ci       *     will be generated for each active structure member.  The name of
356bf215546Sopenharmony_ci       *     each entry is formed by concatenating the name of the structure,
357bf215546Sopenharmony_ci       *     the "."  character, and the name of the structure member.  If a
358bf215546Sopenharmony_ci       *     structure member to enumerate is itself a structure or array,
359bf215546Sopenharmony_ci       *     these enumeration rules are applied recursively."
360bf215546Sopenharmony_ci       */
361bf215546Sopenharmony_ci      if (outermost_struct_type == NULL)
362bf215546Sopenharmony_ci         outermost_struct_type = type;
363bf215546Sopenharmony_ci
364bf215546Sopenharmony_ci      unsigned field_location = location;
365bf215546Sopenharmony_ci      for (unsigned i = 0; i < glsl_get_length(type); i++) {
366bf215546Sopenharmony_ci         const struct glsl_type *field_type = glsl_get_struct_field(type, i);
367bf215546Sopenharmony_ci         const struct glsl_struct_field *field =
368bf215546Sopenharmony_ci            glsl_get_struct_field_data(type, i);
369bf215546Sopenharmony_ci
370bf215546Sopenharmony_ci         char *field_name = ralloc_asprintf(shProg, "%s.%s", name, field->name);
371bf215546Sopenharmony_ci         if (!add_shader_variable(consts, shProg, resource_set,
372bf215546Sopenharmony_ci                                  stage_mask, programInterface,
373bf215546Sopenharmony_ci                                  var, field_name, field_type,
374bf215546Sopenharmony_ci                                  use_implicit_location, field_location,
375bf215546Sopenharmony_ci                                  false, outermost_struct_type))
376bf215546Sopenharmony_ci            return false;
377bf215546Sopenharmony_ci
378bf215546Sopenharmony_ci         field_location += glsl_count_attribute_slots(field_type, false);
379bf215546Sopenharmony_ci      }
380bf215546Sopenharmony_ci      return true;
381bf215546Sopenharmony_ci   }
382bf215546Sopenharmony_ci
383bf215546Sopenharmony_ci   case GLSL_TYPE_ARRAY: {
384bf215546Sopenharmony_ci      /* The ARB_program_interface_query spec says:
385bf215546Sopenharmony_ci       *
386bf215546Sopenharmony_ci       *     "For an active variable declared as an array of basic types, a
387bf215546Sopenharmony_ci       *      single entry will be generated, with its name string formed by
388bf215546Sopenharmony_ci       *      concatenating the name of the array and the string "[0]"."
389bf215546Sopenharmony_ci       *
390bf215546Sopenharmony_ci       *     "For an active variable declared as an array of an aggregate data
391bf215546Sopenharmony_ci       *      type (structures or arrays), a separate entry will be generated
392bf215546Sopenharmony_ci       *      for each active array element, unless noted immediately below.
393bf215546Sopenharmony_ci       *      The name of each entry is formed by concatenating the name of
394bf215546Sopenharmony_ci       *      the array, the "[" character, an integer identifying the element
395bf215546Sopenharmony_ci       *      number, and the "]" character.  These enumeration rules are
396bf215546Sopenharmony_ci       *      applied recursively, treating each enumerated array element as a
397bf215546Sopenharmony_ci       *      separate active variable."
398bf215546Sopenharmony_ci       */
399bf215546Sopenharmony_ci      const struct glsl_type *array_type = glsl_get_array_element(type);
400bf215546Sopenharmony_ci      if (glsl_get_base_type(array_type) == GLSL_TYPE_STRUCT ||
401bf215546Sopenharmony_ci          glsl_get_base_type(array_type) == GLSL_TYPE_ARRAY) {
402bf215546Sopenharmony_ci         unsigned elem_location = location;
403bf215546Sopenharmony_ci         unsigned stride = inouts_share_location ? 0 :
404bf215546Sopenharmony_ci                           glsl_count_attribute_slots(array_type, false);
405bf215546Sopenharmony_ci         for (unsigned i = 0; i < glsl_get_length(type); i++) {
406bf215546Sopenharmony_ci            char *elem = ralloc_asprintf(shProg, "%s[%d]", name, i);
407bf215546Sopenharmony_ci            if (!add_shader_variable(consts, shProg, resource_set,
408bf215546Sopenharmony_ci                                     stage_mask, programInterface,
409bf215546Sopenharmony_ci                                     var, elem, array_type,
410bf215546Sopenharmony_ci                                     use_implicit_location, elem_location,
411bf215546Sopenharmony_ci                                     false, outermost_struct_type))
412bf215546Sopenharmony_ci               return false;
413bf215546Sopenharmony_ci            elem_location += stride;
414bf215546Sopenharmony_ci         }
415bf215546Sopenharmony_ci         return true;
416bf215546Sopenharmony_ci      }
417bf215546Sopenharmony_ci   }
418bf215546Sopenharmony_ci   FALLTHROUGH;
419bf215546Sopenharmony_ci
420bf215546Sopenharmony_ci   default: {
421bf215546Sopenharmony_ci      /* The ARB_program_interface_query spec says:
422bf215546Sopenharmony_ci       *
423bf215546Sopenharmony_ci       *     "For an active variable declared as a single instance of a basic
424bf215546Sopenharmony_ci       *     type, a single entry will be generated, using the variable name
425bf215546Sopenharmony_ci       *     from the shader source."
426bf215546Sopenharmony_ci       */
427bf215546Sopenharmony_ci      struct gl_shader_variable *sha_v =
428bf215546Sopenharmony_ci         create_shader_variable(shProg, var, name, type, interface_type,
429bf215546Sopenharmony_ci                                use_implicit_location, location,
430bf215546Sopenharmony_ci                                outermost_struct_type);
431bf215546Sopenharmony_ci      if (!sha_v)
432bf215546Sopenharmony_ci         return false;
433bf215546Sopenharmony_ci
434bf215546Sopenharmony_ci      return link_util_add_program_resource(shProg, resource_set,
435bf215546Sopenharmony_ci                                            programInterface, sha_v, stage_mask);
436bf215546Sopenharmony_ci   }
437bf215546Sopenharmony_ci   }
438bf215546Sopenharmony_ci}
439bf215546Sopenharmony_ci
440bf215546Sopenharmony_cistatic bool
441bf215546Sopenharmony_ciadd_vars_with_modes(const struct gl_constants *consts,
442bf215546Sopenharmony_ci                    struct gl_shader_program *prog, struct set *resource_set,
443bf215546Sopenharmony_ci                    nir_shader *nir, nir_variable_mode modes,
444bf215546Sopenharmony_ci                    unsigned stage, GLenum programInterface)
445bf215546Sopenharmony_ci{
446bf215546Sopenharmony_ci   nir_foreach_variable_with_modes(var, nir, modes) {
447bf215546Sopenharmony_ci      if (var->data.how_declared == nir_var_hidden)
448bf215546Sopenharmony_ci         continue;
449bf215546Sopenharmony_ci
450bf215546Sopenharmony_ci      int loc_bias = 0;
451bf215546Sopenharmony_ci      switch(var->data.mode) {
452bf215546Sopenharmony_ci      case nir_var_system_value:
453bf215546Sopenharmony_ci      case nir_var_shader_in:
454bf215546Sopenharmony_ci         if (programInterface != GL_PROGRAM_INPUT)
455bf215546Sopenharmony_ci            continue;
456bf215546Sopenharmony_ci         loc_bias = (stage == MESA_SHADER_VERTEX) ? VERT_ATTRIB_GENERIC0
457bf215546Sopenharmony_ci                                                  : VARYING_SLOT_VAR0;
458bf215546Sopenharmony_ci         break;
459bf215546Sopenharmony_ci      case nir_var_shader_out:
460bf215546Sopenharmony_ci         if (programInterface != GL_PROGRAM_OUTPUT)
461bf215546Sopenharmony_ci            continue;
462bf215546Sopenharmony_ci         loc_bias = (stage == MESA_SHADER_FRAGMENT) ? FRAG_RESULT_DATA0
463bf215546Sopenharmony_ci                                                    : VARYING_SLOT_VAR0;
464bf215546Sopenharmony_ci         break;
465bf215546Sopenharmony_ci      default:
466bf215546Sopenharmony_ci         continue;
467bf215546Sopenharmony_ci      }
468bf215546Sopenharmony_ci
469bf215546Sopenharmony_ci      if (var->data.patch)
470bf215546Sopenharmony_ci         loc_bias = VARYING_SLOT_PATCH0;
471bf215546Sopenharmony_ci
472bf215546Sopenharmony_ci      if (prog->data->spirv) {
473bf215546Sopenharmony_ci         struct gl_shader_variable *sh_var =
474bf215546Sopenharmony_ci            rzalloc(prog, struct gl_shader_variable);
475bf215546Sopenharmony_ci
476bf215546Sopenharmony_ci         /* In the ARB_gl_spirv spec, names are considered optional debug info, so
477bf215546Sopenharmony_ci          * the linker needs to work without them. Returning them is optional.
478bf215546Sopenharmony_ci          * For simplicity, we ignore names.
479bf215546Sopenharmony_ci          */
480bf215546Sopenharmony_ci         sh_var->name.string = NULL;
481bf215546Sopenharmony_ci         resource_name_updated(&sh_var->name);
482bf215546Sopenharmony_ci         sh_var->type = var->type;
483bf215546Sopenharmony_ci         sh_var->location = var->data.location - loc_bias;
484bf215546Sopenharmony_ci         sh_var->index = var->data.index;
485bf215546Sopenharmony_ci
486bf215546Sopenharmony_ci         if (!link_util_add_program_resource(prog, resource_set,
487bf215546Sopenharmony_ci                                             programInterface,
488bf215546Sopenharmony_ci                                             sh_var, 1 << stage)) {
489bf215546Sopenharmony_ci           return false;
490bf215546Sopenharmony_ci         }
491bf215546Sopenharmony_ci      } else {
492bf215546Sopenharmony_ci         /* Skip packed varyings, packed varyings are handled separately
493bf215546Sopenharmony_ci          * by add_packed_varyings in the GLSL IR
494bf215546Sopenharmony_ci          * build_program_resource_list() call.
495bf215546Sopenharmony_ci          * TODO: handle packed varyings here instead. We likely want a NIR
496bf215546Sopenharmony_ci          * based packing pass first.
497bf215546Sopenharmony_ci          */
498bf215546Sopenharmony_ci         if (strncmp(var->name, "packed:", 7) == 0)
499bf215546Sopenharmony_ci            continue;
500bf215546Sopenharmony_ci
501bf215546Sopenharmony_ci         const bool vs_input_or_fs_output =
502bf215546Sopenharmony_ci            (stage == MESA_SHADER_VERTEX &&
503bf215546Sopenharmony_ci             var->data.mode == nir_var_shader_in) ||
504bf215546Sopenharmony_ci            (stage == MESA_SHADER_FRAGMENT &&
505bf215546Sopenharmony_ci             var->data.mode == nir_var_shader_out);
506bf215546Sopenharmony_ci
507bf215546Sopenharmony_ci         if (!add_shader_variable(consts, prog, resource_set,
508bf215546Sopenharmony_ci                                  1 << stage, programInterface,
509bf215546Sopenharmony_ci                                  var, var->name, var->type,
510bf215546Sopenharmony_ci                                  vs_input_or_fs_output,
511bf215546Sopenharmony_ci                                  var->data.location - loc_bias,
512bf215546Sopenharmony_ci                                  inout_has_same_location(var, stage),
513bf215546Sopenharmony_ci                                  NULL))
514bf215546Sopenharmony_ci            return false;
515bf215546Sopenharmony_ci      }
516bf215546Sopenharmony_ci   }
517bf215546Sopenharmony_ci
518bf215546Sopenharmony_ci   return true;
519bf215546Sopenharmony_ci}
520bf215546Sopenharmony_ci
521bf215546Sopenharmony_cistatic bool
522bf215546Sopenharmony_ciadd_interface_variables(const struct gl_constants *consts,
523bf215546Sopenharmony_ci                        struct gl_shader_program *prog,
524bf215546Sopenharmony_ci                        struct set *resource_set,
525bf215546Sopenharmony_ci                        unsigned stage, GLenum programInterface)
526bf215546Sopenharmony_ci{
527bf215546Sopenharmony_ci   struct gl_linked_shader *sh = prog->_LinkedShaders[stage];
528bf215546Sopenharmony_ci   if (!sh)
529bf215546Sopenharmony_ci      return true;
530bf215546Sopenharmony_ci
531bf215546Sopenharmony_ci   nir_shader *nir = sh->Program->nir;
532bf215546Sopenharmony_ci   assert(nir);
533bf215546Sopenharmony_ci
534bf215546Sopenharmony_ci   switch (programInterface) {
535bf215546Sopenharmony_ci   case GL_PROGRAM_INPUT: {
536bf215546Sopenharmony_ci      return add_vars_with_modes(consts, prog, resource_set,
537bf215546Sopenharmony_ci                                 nir, nir_var_shader_in | nir_var_system_value,
538bf215546Sopenharmony_ci                                 stage, programInterface);
539bf215546Sopenharmony_ci   }
540bf215546Sopenharmony_ci   case GL_PROGRAM_OUTPUT:
541bf215546Sopenharmony_ci      return add_vars_with_modes(consts, prog, resource_set,
542bf215546Sopenharmony_ci                                 nir, nir_var_shader_out,
543bf215546Sopenharmony_ci                                 stage, programInterface);
544bf215546Sopenharmony_ci   default:
545bf215546Sopenharmony_ci      assert("!Should not get here");
546bf215546Sopenharmony_ci      break;
547bf215546Sopenharmony_ci   }
548bf215546Sopenharmony_ci
549bf215546Sopenharmony_ci   return false;
550bf215546Sopenharmony_ci}
551bf215546Sopenharmony_ci
552bf215546Sopenharmony_cibool
553bf215546Sopenharmony_cinir_add_packed_var_to_resource_list(const struct gl_constants *consts,
554bf215546Sopenharmony_ci                                    struct gl_shader_program *shProg,
555bf215546Sopenharmony_ci                                    struct set *resource_set,
556bf215546Sopenharmony_ci                                    nir_variable *var,
557bf215546Sopenharmony_ci                                    unsigned stage, GLenum type)
558bf215546Sopenharmony_ci{
559bf215546Sopenharmony_ci   if (!add_shader_variable(consts, shProg, resource_set, 1 << stage,
560bf215546Sopenharmony_ci                            type, var, var->name, var->type, false,
561bf215546Sopenharmony_ci                            var->data.location - VARYING_SLOT_VAR0,
562bf215546Sopenharmony_ci                            inout_has_same_location(var, stage), NULL))
563bf215546Sopenharmony_ci      return false;
564bf215546Sopenharmony_ci
565bf215546Sopenharmony_ci   return true;
566bf215546Sopenharmony_ci}
567bf215546Sopenharmony_ci
568bf215546Sopenharmony_ci/**
569bf215546Sopenharmony_ci * Initilise list of program resources that point to resource data.
570bf215546Sopenharmony_ci */
571bf215546Sopenharmony_civoid
572bf215546Sopenharmony_ciinit_program_resource_list(struct gl_shader_program *prog)
573bf215546Sopenharmony_ci{
574bf215546Sopenharmony_ci   /* Rebuild resource list. */
575bf215546Sopenharmony_ci   if (prog->data->ProgramResourceList) {
576bf215546Sopenharmony_ci      ralloc_free(prog->data->ProgramResourceList);
577bf215546Sopenharmony_ci      prog->data->ProgramResourceList = NULL;
578bf215546Sopenharmony_ci      prog->data->NumProgramResourceList = 0;
579bf215546Sopenharmony_ci   }
580bf215546Sopenharmony_ci}
581bf215546Sopenharmony_ci
582bf215546Sopenharmony_ci/* TODO: as we keep adding features, this method is becoming more and more
583bf215546Sopenharmony_ci * similar to its GLSL counterpart at linker.cpp. Eventually it would be good
584bf215546Sopenharmony_ci * to check if they could be refactored, and reduce code duplication somehow
585bf215546Sopenharmony_ci */
586bf215546Sopenharmony_civoid
587bf215546Sopenharmony_cinir_build_program_resource_list(const struct gl_constants *consts,
588bf215546Sopenharmony_ci                                struct gl_shader_program *prog,
589bf215546Sopenharmony_ci                                bool rebuild_resourse_list)
590bf215546Sopenharmony_ci{
591bf215546Sopenharmony_ci   /* Rebuild resource list. */
592bf215546Sopenharmony_ci   if (rebuild_resourse_list)
593bf215546Sopenharmony_ci      init_program_resource_list(prog);
594bf215546Sopenharmony_ci
595bf215546Sopenharmony_ci   int input_stage = MESA_SHADER_STAGES, output_stage = 0;
596bf215546Sopenharmony_ci
597bf215546Sopenharmony_ci   /* Determine first input and final output stage. These are used to
598bf215546Sopenharmony_ci    * detect which variables should be enumerated in the resource list
599bf215546Sopenharmony_ci    * for GL_PROGRAM_INPUT and GL_PROGRAM_OUTPUT.
600bf215546Sopenharmony_ci    */
601bf215546Sopenharmony_ci   for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) {
602bf215546Sopenharmony_ci      if (!prog->_LinkedShaders[i])
603bf215546Sopenharmony_ci         continue;
604bf215546Sopenharmony_ci      if (input_stage == MESA_SHADER_STAGES)
605bf215546Sopenharmony_ci         input_stage = i;
606bf215546Sopenharmony_ci      output_stage = i;
607bf215546Sopenharmony_ci   }
608bf215546Sopenharmony_ci
609bf215546Sopenharmony_ci   /* Empty shader, no resources. */
610bf215546Sopenharmony_ci   if (input_stage == MESA_SHADER_STAGES && output_stage == 0)
611bf215546Sopenharmony_ci      return;
612bf215546Sopenharmony_ci
613bf215546Sopenharmony_ci   struct set *resource_set = _mesa_pointer_set_create(NULL);
614bf215546Sopenharmony_ci
615bf215546Sopenharmony_ci   /* Add inputs and outputs to the resource list. */
616bf215546Sopenharmony_ci   if (!add_interface_variables(consts, prog, resource_set, input_stage,
617bf215546Sopenharmony_ci                                GL_PROGRAM_INPUT)) {
618bf215546Sopenharmony_ci      return;
619bf215546Sopenharmony_ci   }
620bf215546Sopenharmony_ci
621bf215546Sopenharmony_ci   if (!add_interface_variables(consts, prog, resource_set, output_stage,
622bf215546Sopenharmony_ci                                GL_PROGRAM_OUTPUT)) {
623bf215546Sopenharmony_ci      return;
624bf215546Sopenharmony_ci   }
625bf215546Sopenharmony_ci
626bf215546Sopenharmony_ci   /* Add transform feedback varyings and buffers. */
627bf215546Sopenharmony_ci   if (prog->last_vert_prog) {
628bf215546Sopenharmony_ci      struct gl_transform_feedback_info *linked_xfb =
629bf215546Sopenharmony_ci         prog->last_vert_prog->sh.LinkedTransformFeedback;
630bf215546Sopenharmony_ci
631bf215546Sopenharmony_ci      /* Add varyings. */
632bf215546Sopenharmony_ci      if (linked_xfb->NumVarying > 0) {
633bf215546Sopenharmony_ci         for (int i = 0; i < linked_xfb->NumVarying; i++) {
634bf215546Sopenharmony_ci            if (!link_util_add_program_resource(prog, resource_set,
635bf215546Sopenharmony_ci                                                GL_TRANSFORM_FEEDBACK_VARYING,
636bf215546Sopenharmony_ci                                                &linked_xfb->Varyings[i], 0))
637bf215546Sopenharmony_ci            return;
638bf215546Sopenharmony_ci         }
639bf215546Sopenharmony_ci      }
640bf215546Sopenharmony_ci
641bf215546Sopenharmony_ci      /* Add buffers. */
642bf215546Sopenharmony_ci      for (unsigned i = 0; i < consts->MaxTransformFeedbackBuffers; i++) {
643bf215546Sopenharmony_ci         if ((linked_xfb->ActiveBuffers >> i) & 1) {
644bf215546Sopenharmony_ci            linked_xfb->Buffers[i].Binding = i;
645bf215546Sopenharmony_ci            if (!link_util_add_program_resource(prog, resource_set,
646bf215546Sopenharmony_ci                                                GL_TRANSFORM_FEEDBACK_BUFFER,
647bf215546Sopenharmony_ci                                                &linked_xfb->Buffers[i], 0))
648bf215546Sopenharmony_ci            return;
649bf215546Sopenharmony_ci         }
650bf215546Sopenharmony_ci      }
651bf215546Sopenharmony_ci   }
652bf215546Sopenharmony_ci
653bf215546Sopenharmony_ci   /* Add uniforms
654bf215546Sopenharmony_ci    *
655bf215546Sopenharmony_ci    * Here, it is expected that nir_link_uniforms() has already been
656bf215546Sopenharmony_ci    * called, so that UniformStorage table is already available.
657bf215546Sopenharmony_ci    */
658bf215546Sopenharmony_ci   int top_level_array_base_offset = -1;
659bf215546Sopenharmony_ci   int top_level_array_size_in_bytes = -1;
660bf215546Sopenharmony_ci   int second_element_offset = -1;
661bf215546Sopenharmony_ci   int block_index = -1;
662bf215546Sopenharmony_ci   for (unsigned i = 0; i < prog->data->NumUniformStorage; i++) {
663bf215546Sopenharmony_ci      struct gl_uniform_storage *uniform = &prog->data->UniformStorage[i];
664bf215546Sopenharmony_ci
665bf215546Sopenharmony_ci      if (uniform->hidden) {
666bf215546Sopenharmony_ci         for (int j = MESA_SHADER_VERTEX; j < MESA_SHADER_STAGES; j++) {
667bf215546Sopenharmony_ci            if (!uniform->opaque[j].active ||
668bf215546Sopenharmony_ci                glsl_get_base_type(uniform->type) != GLSL_TYPE_SUBROUTINE)
669bf215546Sopenharmony_ci               continue;
670bf215546Sopenharmony_ci
671bf215546Sopenharmony_ci            GLenum type =
672bf215546Sopenharmony_ci               _mesa_shader_stage_to_subroutine_uniform((gl_shader_stage)j);
673bf215546Sopenharmony_ci            /* add shader subroutines */
674bf215546Sopenharmony_ci            if (!link_util_add_program_resource(prog, resource_set,
675bf215546Sopenharmony_ci                                                type, uniform, 0))
676bf215546Sopenharmony_ci               return;
677bf215546Sopenharmony_ci         }
678bf215546Sopenharmony_ci
679bf215546Sopenharmony_ci         continue;
680bf215546Sopenharmony_ci      }
681bf215546Sopenharmony_ci
682bf215546Sopenharmony_ci      if (!link_util_should_add_buffer_variable(prog, uniform,
683bf215546Sopenharmony_ci                                                top_level_array_base_offset,
684bf215546Sopenharmony_ci                                                top_level_array_size_in_bytes,
685bf215546Sopenharmony_ci                                                second_element_offset, block_index))
686bf215546Sopenharmony_ci         continue;
687bf215546Sopenharmony_ci
688bf215546Sopenharmony_ci
689bf215546Sopenharmony_ci      if (prog->data->UniformStorage[i].offset >= second_element_offset) {
690bf215546Sopenharmony_ci         top_level_array_base_offset =
691bf215546Sopenharmony_ci            prog->data->UniformStorage[i].offset;
692bf215546Sopenharmony_ci
693bf215546Sopenharmony_ci         top_level_array_size_in_bytes =
694bf215546Sopenharmony_ci            prog->data->UniformStorage[i].top_level_array_size *
695bf215546Sopenharmony_ci            prog->data->UniformStorage[i].top_level_array_stride;
696bf215546Sopenharmony_ci
697bf215546Sopenharmony_ci         /* Set or reset the second element offset. For non arrays this
698bf215546Sopenharmony_ci          * will be set to -1.
699bf215546Sopenharmony_ci          */
700bf215546Sopenharmony_ci         second_element_offset = top_level_array_size_in_bytes ?
701bf215546Sopenharmony_ci            top_level_array_base_offset +
702bf215546Sopenharmony_ci            prog->data->UniformStorage[i].top_level_array_stride : -1;
703bf215546Sopenharmony_ci      }
704bf215546Sopenharmony_ci      block_index = uniform->block_index;
705bf215546Sopenharmony_ci
706bf215546Sopenharmony_ci
707bf215546Sopenharmony_ci      GLenum interface = uniform->is_shader_storage ? GL_BUFFER_VARIABLE : GL_UNIFORM;
708bf215546Sopenharmony_ci      if (!link_util_add_program_resource(prog, resource_set, interface, uniform,
709bf215546Sopenharmony_ci                                          uniform->active_shader_mask)) {
710bf215546Sopenharmony_ci         return;
711bf215546Sopenharmony_ci      }
712bf215546Sopenharmony_ci   }
713bf215546Sopenharmony_ci
714bf215546Sopenharmony_ci
715bf215546Sopenharmony_ci   for (unsigned i = 0; i < prog->data->NumUniformBlocks; i++) {
716bf215546Sopenharmony_ci      if (!link_util_add_program_resource(prog, resource_set, GL_UNIFORM_BLOCK,
717bf215546Sopenharmony_ci                                          &prog->data->UniformBlocks[i],
718bf215546Sopenharmony_ci                                          prog->data->UniformBlocks[i].stageref))
719bf215546Sopenharmony_ci         return;
720bf215546Sopenharmony_ci   }
721bf215546Sopenharmony_ci
722bf215546Sopenharmony_ci   for (unsigned i = 0; i < prog->data->NumShaderStorageBlocks; i++) {
723bf215546Sopenharmony_ci      if (!link_util_add_program_resource(prog, resource_set, GL_SHADER_STORAGE_BLOCK,
724bf215546Sopenharmony_ci                                          &prog->data->ShaderStorageBlocks[i],
725bf215546Sopenharmony_ci                                          prog->data->ShaderStorageBlocks[i].stageref))
726bf215546Sopenharmony_ci         return;
727bf215546Sopenharmony_ci   }
728bf215546Sopenharmony_ci
729bf215546Sopenharmony_ci   /* Add atomic counter buffers. */
730bf215546Sopenharmony_ci   for (unsigned i = 0; i < prog->data->NumAtomicBuffers; i++) {
731bf215546Sopenharmony_ci      if (!link_util_add_program_resource(prog, resource_set, GL_ATOMIC_COUNTER_BUFFER,
732bf215546Sopenharmony_ci                                          &prog->data->AtomicBuffers[i], 0))
733bf215546Sopenharmony_ci         return;
734bf215546Sopenharmony_ci   }
735bf215546Sopenharmony_ci
736bf215546Sopenharmony_ci   unsigned mask = prog->data->linked_stages;
737bf215546Sopenharmony_ci   while (mask) {
738bf215546Sopenharmony_ci      const int i = u_bit_scan(&mask);
739bf215546Sopenharmony_ci      struct gl_program *p = prog->_LinkedShaders[i]->Program;
740bf215546Sopenharmony_ci
741bf215546Sopenharmony_ci      GLuint type = _mesa_shader_stage_to_subroutine((gl_shader_stage)i);
742bf215546Sopenharmony_ci      for (unsigned j = 0; j < p->sh.NumSubroutineFunctions; j++) {
743bf215546Sopenharmony_ci         if (!link_util_add_program_resource(prog, resource_set,
744bf215546Sopenharmony_ci                                             type,
745bf215546Sopenharmony_ci                                             &p->sh.SubroutineFunctions[j],
746bf215546Sopenharmony_ci                                             0))
747bf215546Sopenharmony_ci            return;
748bf215546Sopenharmony_ci      }
749bf215546Sopenharmony_ci   }
750bf215546Sopenharmony_ci
751bf215546Sopenharmony_ci   _mesa_set_destroy(resource_set, NULL);
752bf215546Sopenharmony_ci}
753bf215546Sopenharmony_ci
754bf215546Sopenharmony_cibool
755bf215546Sopenharmony_cigl_nir_link_spirv(const struct gl_constants *consts,
756bf215546Sopenharmony_ci                  struct gl_shader_program *prog,
757bf215546Sopenharmony_ci                  const struct gl_nir_linker_options *options)
758bf215546Sopenharmony_ci{
759bf215546Sopenharmony_ci   struct gl_linked_shader *linked_shader[MESA_SHADER_STAGES];
760bf215546Sopenharmony_ci   unsigned num_shaders = 0;
761bf215546Sopenharmony_ci
762bf215546Sopenharmony_ci   for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) {
763bf215546Sopenharmony_ci      if (prog->_LinkedShaders[i])
764bf215546Sopenharmony_ci         linked_shader[num_shaders++] = prog->_LinkedShaders[i];
765bf215546Sopenharmony_ci   }
766bf215546Sopenharmony_ci
767bf215546Sopenharmony_ci   /* Linking the stages in the opposite order (from fragment to vertex)
768bf215546Sopenharmony_ci    * ensures that inter-shader outputs written to in an earlier stage
769bf215546Sopenharmony_ci    * are eliminated if they are (transitively) not used in a later
770bf215546Sopenharmony_ci    * stage.
771bf215546Sopenharmony_ci    */
772bf215546Sopenharmony_ci   for (int i = num_shaders - 2; i >= 0; i--) {
773bf215546Sopenharmony_ci      gl_nir_link_opts(linked_shader[i]->Program->nir,
774bf215546Sopenharmony_ci                       linked_shader[i + 1]->Program->nir);
775bf215546Sopenharmony_ci   }
776bf215546Sopenharmony_ci
777bf215546Sopenharmony_ci   for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) {
778bf215546Sopenharmony_ci      struct gl_linked_shader *shader = prog->_LinkedShaders[i];
779bf215546Sopenharmony_ci      if (shader) {
780bf215546Sopenharmony_ci         const nir_remove_dead_variables_options opts = {
781bf215546Sopenharmony_ci            .can_remove_var = can_remove_uniform,
782bf215546Sopenharmony_ci         };
783bf215546Sopenharmony_ci         nir_remove_dead_variables(shader->Program->nir,
784bf215546Sopenharmony_ci                                   nir_var_uniform | nir_var_image,
785bf215546Sopenharmony_ci                                   &opts);
786bf215546Sopenharmony_ci      }
787bf215546Sopenharmony_ci   }
788bf215546Sopenharmony_ci
789bf215546Sopenharmony_ci   if (!gl_nir_link_uniform_blocks(prog))
790bf215546Sopenharmony_ci      return false;
791bf215546Sopenharmony_ci
792bf215546Sopenharmony_ci   if (!gl_nir_link_uniforms(consts, prog, options->fill_parameters))
793bf215546Sopenharmony_ci      return false;
794bf215546Sopenharmony_ci
795bf215546Sopenharmony_ci   gl_nir_link_assign_atomic_counter_resources(consts, prog);
796bf215546Sopenharmony_ci   gl_nir_link_assign_xfb_resources(consts, prog);
797bf215546Sopenharmony_ci
798bf215546Sopenharmony_ci   return true;
799bf215546Sopenharmony_ci}
800bf215546Sopenharmony_ci
801bf215546Sopenharmony_ci/**
802bf215546Sopenharmony_ci * Validate shader image resources.
803bf215546Sopenharmony_ci */
804bf215546Sopenharmony_cistatic void
805bf215546Sopenharmony_cicheck_image_resources(const struct gl_constants *consts,
806bf215546Sopenharmony_ci                      const struct gl_extensions *exts,
807bf215546Sopenharmony_ci                      struct gl_shader_program *prog)
808bf215546Sopenharmony_ci{
809bf215546Sopenharmony_ci   unsigned total_image_units = 0;
810bf215546Sopenharmony_ci   unsigned fragment_outputs = 0;
811bf215546Sopenharmony_ci   unsigned total_shader_storage_blocks = 0;
812bf215546Sopenharmony_ci
813bf215546Sopenharmony_ci   if (!exts->ARB_shader_image_load_store)
814bf215546Sopenharmony_ci      return;
815bf215546Sopenharmony_ci
816bf215546Sopenharmony_ci   for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) {
817bf215546Sopenharmony_ci      struct gl_linked_shader *sh = prog->_LinkedShaders[i];
818bf215546Sopenharmony_ci      if (!sh)
819bf215546Sopenharmony_ci         continue;
820bf215546Sopenharmony_ci
821bf215546Sopenharmony_ci      total_image_units += sh->Program->info.num_images;
822bf215546Sopenharmony_ci      total_shader_storage_blocks += sh->Program->info.num_ssbos;
823bf215546Sopenharmony_ci   }
824bf215546Sopenharmony_ci
825bf215546Sopenharmony_ci   if (total_image_units > consts->MaxCombinedImageUniforms)
826bf215546Sopenharmony_ci      linker_error(prog, "Too many combined image uniforms\n");
827bf215546Sopenharmony_ci
828bf215546Sopenharmony_ci   struct gl_linked_shader *frag_sh =
829bf215546Sopenharmony_ci      prog->_LinkedShaders[MESA_SHADER_FRAGMENT];
830bf215546Sopenharmony_ci   if (frag_sh) {
831bf215546Sopenharmony_ci      uint64_t frag_outputs_written = frag_sh->Program->info.outputs_written;
832bf215546Sopenharmony_ci      fragment_outputs = util_bitcount64(frag_outputs_written);
833bf215546Sopenharmony_ci   }
834bf215546Sopenharmony_ci
835bf215546Sopenharmony_ci   if (total_image_units + fragment_outputs + total_shader_storage_blocks >
836bf215546Sopenharmony_ci       consts->MaxCombinedShaderOutputResources)
837bf215546Sopenharmony_ci      linker_error(prog, "Too many combined image uniforms, shader storage "
838bf215546Sopenharmony_ci                         " buffers and fragment outputs\n");
839bf215546Sopenharmony_ci}
840bf215546Sopenharmony_ci
841bf215546Sopenharmony_cistatic bool
842bf215546Sopenharmony_ciis_sampler_array_accessed_indirectly(nir_deref_instr *deref)
843bf215546Sopenharmony_ci{
844bf215546Sopenharmony_ci   for (nir_deref_instr *d = deref; d; d = nir_deref_instr_parent(d)) {
845bf215546Sopenharmony_ci      if (d->deref_type != nir_deref_type_array)
846bf215546Sopenharmony_ci         continue;
847bf215546Sopenharmony_ci
848bf215546Sopenharmony_ci      if (nir_src_is_const(d->arr.index))
849bf215546Sopenharmony_ci         continue;
850bf215546Sopenharmony_ci
851bf215546Sopenharmony_ci      return true;
852bf215546Sopenharmony_ci   }
853bf215546Sopenharmony_ci
854bf215546Sopenharmony_ci   return false;
855bf215546Sopenharmony_ci}
856bf215546Sopenharmony_ci
857bf215546Sopenharmony_ci/**
858bf215546Sopenharmony_ci * This check is done to make sure we allow only constant expression
859bf215546Sopenharmony_ci * indexing and "constant-index-expression" (indexing with an expression
860bf215546Sopenharmony_ci * that includes loop induction variable).
861bf215546Sopenharmony_ci */
862bf215546Sopenharmony_cistatic bool
863bf215546Sopenharmony_civalidate_sampler_array_indexing(const struct gl_constants *consts,
864bf215546Sopenharmony_ci                                struct gl_shader_program *prog)
865bf215546Sopenharmony_ci{
866bf215546Sopenharmony_ci   for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) {
867bf215546Sopenharmony_ci      if (prog->_LinkedShaders[i] == NULL)
868bf215546Sopenharmony_ci         continue;
869bf215546Sopenharmony_ci
870bf215546Sopenharmony_ci      bool no_dynamic_indexing =
871bf215546Sopenharmony_ci         consts->ShaderCompilerOptions[i].NirOptions->force_indirect_unrolling_sampler;
872bf215546Sopenharmony_ci
873bf215546Sopenharmony_ci      bool uses_indirect_sampler_array_indexing = false;
874bf215546Sopenharmony_ci      nir_foreach_function(function, prog->_LinkedShaders[i]->Program->nir) {
875bf215546Sopenharmony_ci         nir_foreach_block(block, function->impl) {
876bf215546Sopenharmony_ci            nir_foreach_instr(instr, block) {
877bf215546Sopenharmony_ci               /* Check if a sampler array is accessed indirectly */
878bf215546Sopenharmony_ci               if (instr->type == nir_instr_type_tex) {
879bf215546Sopenharmony_ci                  nir_tex_instr *tex_instr = nir_instr_as_tex(instr);
880bf215546Sopenharmony_ci                  int sampler_idx =
881bf215546Sopenharmony_ci                     nir_tex_instr_src_index(tex_instr, nir_tex_src_sampler_deref);
882bf215546Sopenharmony_ci                  if (sampler_idx >= 0) {
883bf215546Sopenharmony_ci                     nir_deref_instr *deref =
884bf215546Sopenharmony_ci                        nir_instr_as_deref(tex_instr->src[sampler_idx].src.ssa->parent_instr);
885bf215546Sopenharmony_ci                     if (is_sampler_array_accessed_indirectly(deref)) {
886bf215546Sopenharmony_ci                        uses_indirect_sampler_array_indexing = true;
887bf215546Sopenharmony_ci                        break;
888bf215546Sopenharmony_ci                     }
889bf215546Sopenharmony_ci                  }
890bf215546Sopenharmony_ci               }
891bf215546Sopenharmony_ci            }
892bf215546Sopenharmony_ci
893bf215546Sopenharmony_ci            if (uses_indirect_sampler_array_indexing)
894bf215546Sopenharmony_ci               break;
895bf215546Sopenharmony_ci         }
896bf215546Sopenharmony_ci         if (uses_indirect_sampler_array_indexing)
897bf215546Sopenharmony_ci            break;
898bf215546Sopenharmony_ci      }
899bf215546Sopenharmony_ci
900bf215546Sopenharmony_ci      if (uses_indirect_sampler_array_indexing) {
901bf215546Sopenharmony_ci         const char *msg = "sampler arrays indexed with non-constant "
902bf215546Sopenharmony_ci                           "expressions is forbidden in GLSL %s %u";
903bf215546Sopenharmony_ci         /* Backend has indicated that it has no dynamic indexing support. */
904bf215546Sopenharmony_ci         if (no_dynamic_indexing) {
905bf215546Sopenharmony_ci            linker_error(prog, msg, prog->IsES ? "ES" : "",
906bf215546Sopenharmony_ci                         prog->data->Version);
907bf215546Sopenharmony_ci            return false;
908bf215546Sopenharmony_ci         } else {
909bf215546Sopenharmony_ci            linker_warning(prog, msg, prog->IsES ? "ES" : "",
910bf215546Sopenharmony_ci                           prog->data->Version);
911bf215546Sopenharmony_ci         }
912bf215546Sopenharmony_ci      }
913bf215546Sopenharmony_ci   }
914bf215546Sopenharmony_ci
915bf215546Sopenharmony_ci   return true;
916bf215546Sopenharmony_ci}
917bf215546Sopenharmony_ci
918bf215546Sopenharmony_cibool
919bf215546Sopenharmony_cigl_nir_link_glsl(const struct gl_constants *consts,
920bf215546Sopenharmony_ci                 const struct gl_extensions *exts,
921bf215546Sopenharmony_ci                 gl_api api,
922bf215546Sopenharmony_ci                 struct gl_shader_program *prog)
923bf215546Sopenharmony_ci{
924bf215546Sopenharmony_ci   if (prog->NumShaders == 0)
925bf215546Sopenharmony_ci      return true;
926bf215546Sopenharmony_ci
927bf215546Sopenharmony_ci   if (!gl_nir_link_varyings(consts, exts, api, prog))
928bf215546Sopenharmony_ci      return false;
929bf215546Sopenharmony_ci
930bf215546Sopenharmony_ci   /* Validation for special cases where we allow sampler array indexing
931bf215546Sopenharmony_ci    * with loop induction variable. This check emits a warning or error
932bf215546Sopenharmony_ci    * depending if backend can handle dynamic indexing.
933bf215546Sopenharmony_ci    */
934bf215546Sopenharmony_ci   if ((!prog->IsES && prog->data->Version < 130) ||
935bf215546Sopenharmony_ci       (prog->IsES && prog->data->Version < 300)) {
936bf215546Sopenharmony_ci      if (!validate_sampler_array_indexing(consts, prog))
937bf215546Sopenharmony_ci         return false;
938bf215546Sopenharmony_ci   }
939bf215546Sopenharmony_ci
940bf215546Sopenharmony_ci   if (prog->data->LinkStatus == LINKING_FAILURE)
941bf215546Sopenharmony_ci      return false;
942bf215546Sopenharmony_ci
943bf215546Sopenharmony_ci   struct gl_linked_shader *linked_shader[MESA_SHADER_STAGES];
944bf215546Sopenharmony_ci   unsigned num_shaders = 0;
945bf215546Sopenharmony_ci
946bf215546Sopenharmony_ci   for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) {
947bf215546Sopenharmony_ci      if (prog->_LinkedShaders[i])
948bf215546Sopenharmony_ci         linked_shader[num_shaders++] = prog->_LinkedShaders[i];
949bf215546Sopenharmony_ci   }
950bf215546Sopenharmony_ci
951bf215546Sopenharmony_ci   /* Linking the stages in the opposite order (from fragment to vertex)
952bf215546Sopenharmony_ci    * ensures that inter-shader outputs written to in an earlier stage
953bf215546Sopenharmony_ci    * are eliminated if they are (transitively) not used in a later
954bf215546Sopenharmony_ci    * stage.
955bf215546Sopenharmony_ci    */
956bf215546Sopenharmony_ci   for (int i = num_shaders - 2; i >= 0; i--) {
957bf215546Sopenharmony_ci      gl_nir_link_opts(linked_shader[i]->Program->nir,
958bf215546Sopenharmony_ci                       linked_shader[i + 1]->Program->nir);
959bf215546Sopenharmony_ci   }
960bf215546Sopenharmony_ci
961bf215546Sopenharmony_ci   /* Tidy up any left overs from the linking process for single shaders.
962bf215546Sopenharmony_ci    * For example varying arrays that get packed may have dead elements that
963bf215546Sopenharmony_ci    * can be now be eliminated now that array access has been lowered.
964bf215546Sopenharmony_ci    */
965bf215546Sopenharmony_ci   if (num_shaders == 1)
966bf215546Sopenharmony_ci      gl_nir_opts(linked_shader[0]->Program->nir);
967bf215546Sopenharmony_ci
968bf215546Sopenharmony_ci   for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) {
969bf215546Sopenharmony_ci      struct gl_linked_shader *shader = prog->_LinkedShaders[i];
970bf215546Sopenharmony_ci      if (shader) {
971bf215546Sopenharmony_ci         if (consts->GLSLLowerConstArrays) {
972bf215546Sopenharmony_ci            nir_lower_const_arrays_to_uniforms(shader->Program->nir,
973bf215546Sopenharmony_ci                                               consts->Program[i].MaxUniformComponents);
974bf215546Sopenharmony_ci         }
975bf215546Sopenharmony_ci
976bf215546Sopenharmony_ci         const nir_remove_dead_variables_options opts = {
977bf215546Sopenharmony_ci            .can_remove_var = can_remove_uniform,
978bf215546Sopenharmony_ci         };
979bf215546Sopenharmony_ci         nir_remove_dead_variables(shader->Program->nir,
980bf215546Sopenharmony_ci                                   nir_var_uniform | nir_var_image,
981bf215546Sopenharmony_ci                                   &opts);
982bf215546Sopenharmony_ci      }
983bf215546Sopenharmony_ci   }
984bf215546Sopenharmony_ci
985bf215546Sopenharmony_ci   if (!gl_nir_link_uniforms(consts, prog, true))
986bf215546Sopenharmony_ci      return false;
987bf215546Sopenharmony_ci
988bf215546Sopenharmony_ci   link_util_calculate_subroutine_compat(prog);
989bf215546Sopenharmony_ci   link_util_check_uniform_resources(consts, prog);
990bf215546Sopenharmony_ci   link_util_check_subroutine_resources(prog);
991bf215546Sopenharmony_ci   check_image_resources(consts, exts, prog);
992bf215546Sopenharmony_ci   gl_nir_link_assign_atomic_counter_resources(consts, prog);
993bf215546Sopenharmony_ci   gl_nir_link_check_atomic_counter_resources(consts, prog);
994bf215546Sopenharmony_ci
995bf215546Sopenharmony_ci   if (prog->data->LinkStatus == LINKING_FAILURE)
996bf215546Sopenharmony_ci      return false;
997bf215546Sopenharmony_ci
998bf215546Sopenharmony_ci   return true;
999bf215546Sopenharmony_ci}
1000