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