1 /*
2  * Copyright © 2018 Intel Corporation
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21  * IN THE SOFTWARE.
22  *
23  */
24 #include "main/mtypes.h"
25 #include "glsl_types.h"
26 #include "linker_util.h"
27 #include "util/bitscan.h"
28 #include "util/set.h"
29 #include "ir_uniform.h" /* for gl_uniform_storage */
30 
31 /* Utility methods shared between the GLSL IR and the NIR */
32 
33 /* From the OpenGL 4.6 specification, 7.3.1.1 Naming Active Resources:
34  *
35  *    "For an active shader storage block member declared as an array of an
36  *     aggregate type, an entry will be generated only for the first array
37  *     element, regardless of its type. Such block members are referred to as
38  *     top-level arrays. If the block member is an aggregate type, the
39  *     enumeration rules are then applied recursively."
40  */
41 bool
link_util_should_add_buffer_variable(struct gl_shader_program * prog,struct gl_uniform_storage * uniform,int top_level_array_base_offset,int top_level_array_size_in_bytes,int second_element_offset,int block_index)42 link_util_should_add_buffer_variable(struct gl_shader_program *prog,
43                                      struct gl_uniform_storage *uniform,
44                                      int top_level_array_base_offset,
45                                      int top_level_array_size_in_bytes,
46                                      int second_element_offset,
47                                      int block_index)
48 {
49    /* If the uniform is not a shader storage buffer or is not an array return
50     * true.
51     */
52    if (!uniform->is_shader_storage || top_level_array_size_in_bytes == 0)
53       return true;
54 
55    int after_top_level_array = top_level_array_base_offset +
56       top_level_array_size_in_bytes;
57 
58    /* Check for a new block, or that we are not dealing with array elements of
59     * a top member array other than the first element.
60     */
61    if (block_index != uniform->block_index ||
62        uniform->offset >= after_top_level_array ||
63        uniform->offset < second_element_offset) {
64       return true;
65    }
66 
67    return false;
68 }
69 
70 bool
link_util_add_program_resource(struct gl_shader_program * prog,struct set * resource_set,GLenum type,const void * data,uint8_t stages)71 link_util_add_program_resource(struct gl_shader_program *prog,
72                                struct set *resource_set,
73                                GLenum type, const void *data, uint8_t stages)
74 {
75    assert(data);
76 
77    /* If resource already exists, do not add it again. */
78    if (_mesa_set_search(resource_set, data))
79       return true;
80 
81    prog->data->ProgramResourceList =
82       reralloc(prog->data,
83                prog->data->ProgramResourceList,
84                gl_program_resource,
85                prog->data->NumProgramResourceList + 1);
86 
87    if (!prog->data->ProgramResourceList) {
88       linker_error(prog, "Out of memory during linking.\n");
89       return false;
90    }
91 
92    struct gl_program_resource *res =
93       &prog->data->ProgramResourceList[prog->data->NumProgramResourceList];
94 
95    res->Type = type;
96    res->Data = data;
97    res->StageReferences = stages;
98 
99    prog->data->NumProgramResourceList++;
100 
101    _mesa_set_add(resource_set, data);
102 
103    return true;
104 }
105 
106 /**
107  * Search through the list of empty blocks to find one that fits the current
108  * uniform.
109  */
110 int
link_util_find_empty_block(struct gl_shader_program * prog,struct gl_uniform_storage * uniform)111 link_util_find_empty_block(struct gl_shader_program *prog,
112                            struct gl_uniform_storage *uniform)
113 {
114    const unsigned entries = MAX2(1, uniform->array_elements);
115 
116    foreach_list_typed(struct empty_uniform_block, block, link,
117                       &prog->EmptyUniformLocations) {
118       /* Found a block with enough slots to fit the uniform */
119       if (block->slots == entries) {
120          unsigned start = block->start;
121          exec_node_remove(&block->link);
122          ralloc_free(block);
123 
124          return start;
125       /* Found a block with more slots than needed. It can still be used. */
126       } else if (block->slots > entries) {
127          unsigned start = block->start;
128          block->start += entries;
129          block->slots -= entries;
130 
131          return start;
132       }
133    }
134 
135    return -1;
136 }
137 
138 void
link_util_update_empty_uniform_locations(struct gl_shader_program * prog)139 link_util_update_empty_uniform_locations(struct gl_shader_program *prog)
140 {
141    struct empty_uniform_block *current_block = NULL;
142 
143    for (unsigned i = 0; i < prog->NumUniformRemapTable; i++) {
144       /* We found empty space in UniformRemapTable. */
145       if (prog->UniformRemapTable[i] == NULL) {
146          /* We've found the beginning of a new continous block of empty slots */
147          if (!current_block || current_block->start + current_block->slots != i) {
148             current_block = rzalloc(prog, struct empty_uniform_block);
149             current_block->start = i;
150             exec_list_push_tail(&prog->EmptyUniformLocations,
151                                 &current_block->link);
152          }
153 
154          /* The current block continues, so we simply increment its slots */
155          current_block->slots++;
156       }
157    }
158 }
159 
160 void
link_util_check_subroutine_resources(struct gl_shader_program * prog)161 link_util_check_subroutine_resources(struct gl_shader_program *prog)
162 {
163    unsigned mask = prog->data->linked_stages;
164    while (mask) {
165       const int i = u_bit_scan(&mask);
166       struct gl_program *p = prog->_LinkedShaders[i]->Program;
167 
168       if (p->sh.NumSubroutineUniformRemapTable > MAX_SUBROUTINE_UNIFORM_LOCATIONS) {
169          linker_error(prog, "Too many %s shader subroutine uniforms\n",
170                       _mesa_shader_stage_to_string(i));
171       }
172    }
173 }
174 
175 /**
176  * Validate uniform resources used by a program versus the implementation limits
177  */
178 void
link_util_check_uniform_resources(struct gl_context * ctx,struct gl_shader_program * prog)179 link_util_check_uniform_resources(struct gl_context *ctx,
180                                   struct gl_shader_program *prog)
181 {
182    unsigned total_uniform_blocks = 0;
183    unsigned total_shader_storage_blocks = 0;
184 
185    for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) {
186       struct gl_linked_shader *sh = prog->_LinkedShaders[i];
187 
188       if (sh == NULL)
189          continue;
190 
191       if (sh->num_uniform_components >
192           ctx->Const.Program[i].MaxUniformComponents) {
193          if (ctx->Const.GLSLSkipStrictMaxUniformLimitCheck) {
194             linker_warning(prog, "Too many %s shader default uniform block "
195                            "components, but the driver will try to optimize "
196                            "them out; this is non-portable out-of-spec "
197                            "behavior\n",
198                            _mesa_shader_stage_to_string(i));
199          } else {
200             linker_error(prog, "Too many %s shader default uniform block "
201                          "components\n",
202                          _mesa_shader_stage_to_string(i));
203          }
204       }
205 
206       if (sh->num_combined_uniform_components >
207           ctx->Const.Program[i].MaxCombinedUniformComponents) {
208          if (ctx->Const.GLSLSkipStrictMaxUniformLimitCheck) {
209             linker_warning(prog, "Too many %s shader uniform components, "
210                            "but the driver will try to optimize them out; "
211                            "this is non-portable out-of-spec behavior\n",
212                            _mesa_shader_stage_to_string(i));
213          } else {
214             linker_error(prog, "Too many %s shader uniform components\n",
215                          _mesa_shader_stage_to_string(i));
216          }
217       }
218 
219       total_shader_storage_blocks += sh->Program->info.num_ssbos;
220       total_uniform_blocks += sh->Program->info.num_ubos;
221    }
222 
223    if (total_uniform_blocks > ctx->Const.MaxCombinedUniformBlocks) {
224       linker_error(prog, "Too many combined uniform blocks (%d/%d)\n",
225                    total_uniform_blocks, ctx->Const.MaxCombinedUniformBlocks);
226    }
227 
228    if (total_shader_storage_blocks > ctx->Const.MaxCombinedShaderStorageBlocks) {
229       linker_error(prog, "Too many combined shader storage blocks (%d/%d)\n",
230                    total_shader_storage_blocks,
231                    ctx->Const.MaxCombinedShaderStorageBlocks);
232    }
233 
234    for (unsigned i = 0; i < prog->data->NumUniformBlocks; i++) {
235       if (prog->data->UniformBlocks[i].UniformBufferSize >
236           ctx->Const.MaxUniformBlockSize) {
237          linker_error(prog, "Uniform block %s too big (%d/%d)\n",
238                       prog->data->UniformBlocks[i].Name,
239                       prog->data->UniformBlocks[i].UniformBufferSize,
240                       ctx->Const.MaxUniformBlockSize);
241       }
242    }
243 
244    for (unsigned i = 0; i < prog->data->NumShaderStorageBlocks; i++) {
245       if (prog->data->ShaderStorageBlocks[i].UniformBufferSize >
246           ctx->Const.MaxShaderStorageBlockSize) {
247          linker_error(prog, "Shader storage block %s too big (%d/%d)\n",
248                       prog->data->ShaderStorageBlocks[i].Name,
249                       prog->data->ShaderStorageBlocks[i].UniformBufferSize,
250                       ctx->Const.MaxShaderStorageBlockSize);
251       }
252    }
253 }
254 
255 void
link_util_calculate_subroutine_compat(struct gl_shader_program * prog)256 link_util_calculate_subroutine_compat(struct gl_shader_program *prog)
257 {
258    unsigned mask = prog->data->linked_stages;
259    while (mask) {
260       const int i = u_bit_scan(&mask);
261       struct gl_program *p = prog->_LinkedShaders[i]->Program;
262 
263       for (unsigned j = 0; j < p->sh.NumSubroutineUniformRemapTable; j++) {
264          if (p->sh.SubroutineUniformRemapTable[j] == INACTIVE_UNIFORM_EXPLICIT_LOCATION)
265             continue;
266 
267          struct gl_uniform_storage *uni = p->sh.SubroutineUniformRemapTable[j];
268 
269          if (!uni)
270             continue;
271 
272          int count = 0;
273          if (p->sh.NumSubroutineFunctions == 0) {
274             linker_error(prog, "subroutine uniform %s defined but no valid functions found\n", uni->type->name);
275             continue;
276          }
277          for (unsigned f = 0; f < p->sh.NumSubroutineFunctions; f++) {
278             struct gl_subroutine_function *fn = &p->sh.SubroutineFunctions[f];
279             for (int k = 0; k < fn->num_compat_types; k++) {
280                if (fn->types[k] == uni->type) {
281                   count++;
282                   break;
283                }
284             }
285          }
286          uni->num_compatible_subroutines = count;
287       }
288    }
289 }
290