blob: 0c07b6d35f5952b8660eb2a9de6e69b2a4938ae6 [file] [log] [blame]
Ian Romanick832dfa52010-06-17 15:04:20 -07001/*
2 * Copyright © 2010 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
21 * DEALINGS IN THE SOFTWARE.
22 */
23
24/**
25 * \file linker.cpp
26 * GLSL linker implementation
27 *
28 * Given a set of shaders that are to be linked to generate a final program,
29 * there are three distinct stages.
30 *
31 * In the first stage shaders are partitioned into groups based on the shader
32 * type. All shaders of a particular type (e.g., vertex shaders) are linked
33 * together.
34 *
35 * - Undefined references in each shader are resolve to definitions in
36 * another shader.
37 * - Types and qualifiers of uniforms, outputs, and global variables defined
38 * in multiple shaders with the same name are verified to be the same.
39 * - Initializers for uniforms and global variables defined
40 * in multiple shaders with the same name are verified to be the same.
41 *
42 * The result, in the terminology of the GLSL spec, is a set of shader
43 * executables for each processing unit.
44 *
45 * After the first stage is complete, a series of semantic checks are performed
46 * on each of the shader executables.
47 *
48 * - Each shader executable must define a \c main function.
49 * - Each vertex shader executable must write to \c gl_Position.
50 * - Each fragment shader executable must write to either \c gl_FragData or
51 * \c gl_FragColor.
52 *
53 * In the final stage individual shader executables are linked to create a
54 * complete exectuable.
55 *
56 * - Types of uniforms defined in multiple shader stages with the same name
57 * are verified to be the same.
58 * - Initializers for uniforms defined in multiple shader stages with the
59 * same name are verified to be the same.
60 * - Types and qualifiers of outputs defined in one stage are verified to
61 * be the same as the types and qualifiers of inputs defined with the same
62 * name in a later stage.
63 *
64 * \author Ian Romanick <ian.d.romanick@intel.com>
65 */
66#include <cstdlib>
67#include <cstdio>
68
69#include "glsl_symbol_table.h"
70#include "glsl_parser_extras.h"
71#include "ir.h"
Ian Romanick019a59b2010-06-21 16:10:42 -070072#include "ir_optimization.h"
Ian Romanick832dfa52010-06-17 15:04:20 -070073#include "program.h"
Ian Romanick019a59b2010-06-21 16:10:42 -070074#include "hash_table.h"
Ian Romanick832dfa52010-06-17 15:04:20 -070075
76/**
77 * Visitor that determines whether or not a variable is ever written.
78 */
79class find_assignment_visitor : public ir_hierarchical_visitor {
80public:
81 find_assignment_visitor(const char *name)
82 : name(name), found(false)
83 {
84 /* empty */
85 }
86
87 virtual ir_visitor_status visit_enter(ir_assignment *ir)
88 {
89 ir_variable *const var = ir->lhs->variable_referenced();
90
91 if (strcmp(name, var->name) == 0) {
92 found = true;
93 return visit_stop;
94 }
95
96 return visit_continue_with_parent;
97 }
98
99 bool variable_found()
100 {
101 return found;
102 }
103
104private:
105 const char *name; /**< Find writes to a variable with this name. */
106 bool found; /**< Was a write to the variable found? */
107};
108
Ian Romanickc93b8f12010-06-17 15:20:22 -0700109
110/**
111 * Verify that a vertex shader executable meets all semantic requirements
112 *
113 * \param shader Vertex shader executable to be verified
114 */
Ian Romanick832dfa52010-06-17 15:04:20 -0700115bool
116validate_vertex_shader_executable(struct glsl_shader *shader)
117{
118 if (shader == NULL)
119 return true;
120
121 if (!shader->symbols->get_function("main")) {
122 printf("error: vertex shader lacks `main'\n");
123 return false;
124 }
125
126 find_assignment_visitor find("gl_Position");
127 find.run(&shader->ir);
128 if (!find.variable_found()) {
129 printf("error: vertex shader does not write to `gl_Position'\n");
130 return false;
131 }
132
133 return true;
134}
135
136
Ian Romanickc93b8f12010-06-17 15:20:22 -0700137/**
138 * Verify that a fragment shader executable meets all semantic requirements
139 *
140 * \param shader Fragment shader executable to be verified
141 */
Ian Romanick832dfa52010-06-17 15:04:20 -0700142bool
143validate_fragment_shader_executable(struct glsl_shader *shader)
144{
145 if (shader == NULL)
146 return true;
147
148 if (!shader->symbols->get_function("main")) {
149 printf("error: fragment shader lacks `main'\n");
150 return false;
151 }
152
153 find_assignment_visitor frag_color("gl_FragColor");
154 find_assignment_visitor frag_data("gl_FragData");
155
156 frag_color.run(&shader->ir);
157 frag_data.run(&shader->ir);
158
159 if (!frag_color.variable_found() && !frag_data.variable_found()) {
160 printf("error: fragment shader does not write to `gl_FragColor' or "
161 "`gl_FragData'\n");
162 return false;
163 }
164
165 if (frag_color.variable_found() && frag_data.variable_found()) {
166 printf("error: fragment shader write to both `gl_FragColor' and "
167 "`gl_FragData'\n");
168 return false;
169 }
170
171 return true;
172}
173
174
Ian Romanickcc22c5a2010-06-18 17:13:42 -0700175/**
176 * Perform validation of uniforms used across multiple shader stages
177 */
178bool
179cross_validate_uniforms(struct glsl_shader **shaders, unsigned num_shaders)
180{
181 /* Examine all of the uniforms in all of the shaders and cross validate
182 * them.
183 */
184 glsl_symbol_table uniforms;
185 for (unsigned i = 0; i < num_shaders; i++) {
186 foreach_list(node, &shaders[i]->ir) {
187 ir_variable *const var = ((ir_instruction *) node)->as_variable();
188
189 if ((var == NULL) || (var->mode != ir_var_uniform))
190 continue;
191
192 /* If a uniform with this name has already been seen, verify that the
193 * new instance has the same type. In addition, if the uniforms have
194 * initializers, the values of the initializers must be the same.
195 */
196 ir_variable *const existing = uniforms.get_variable(var->name);
197 if (existing != NULL) {
198 if (var->type != existing->type) {
199 printf("error: uniform `%s' declared as type `%s' and "
200 "type `%s'\n",
201 var->name, var->type->name, existing->type->name);
202 return false;
203 }
204
205 if (var->constant_value != NULL) {
206 if (existing->constant_value != NULL) {
207 if (!var->constant_value->has_value(existing->constant_value)) {
208 printf("error: initializers for uniform `%s' have "
209 "differing values\n",
210 var->name);
211 return false;
212 }
213 } else
214 /* If the first-seen instance of a particular uniform did not
215 * have an initializer but a later instance does, copy the
216 * initializer to the version stored in the symbol table.
217 */
218 existing->constant_value = var->constant_value->clone();
219 }
220 } else
221 uniforms.add_variable(var->name, var);
222 }
223 }
224
225 return true;
226}
227
228
Ian Romanick37101922010-06-18 19:02:10 -0700229/**
230 * Validate that outputs from one stage match inputs of another
231 */
232bool
233cross_validate_outputs_to_inputs(glsl_shader *producer, glsl_shader *consumer)
234{
235 glsl_symbol_table parameters;
236 /* FINISHME: Figure these out dynamically. */
237 const char *const producer_stage = "vertex";
238 const char *const consumer_stage = "fragment";
239
240 /* Find all shader outputs in the "producer" stage.
241 */
242 foreach_list(node, &producer->ir) {
243 ir_variable *const var = ((ir_instruction *) node)->as_variable();
244
245 /* FINISHME: For geometry shaders, this should also look for inout
246 * FINISHME: variables.
247 */
248 if ((var == NULL) || (var->mode != ir_var_out))
249 continue;
250
251 parameters.add_variable(var->name, var);
252 }
253
254
255 /* Find all shader inputs in the "consumer" stage. Any variables that have
256 * matching outputs already in the symbol table must have the same type and
257 * qualifiers.
258 */
259 foreach_list(node, &consumer->ir) {
260 ir_variable *const input = ((ir_instruction *) node)->as_variable();
261
262 /* FINISHME: For geometry shaders, this should also look for inout
263 * FINISHME: variables.
264 */
265 if ((input == NULL) || (input->mode != ir_var_in))
266 continue;
267
268 ir_variable *const output = parameters.get_variable(input->name);
269 if (output != NULL) {
270 /* Check that the types match between stages.
271 */
272 if (input->type != output->type) {
273 printf("error: %s shader output `%s' delcared as type `%s', but "
274 "%s shader input declared as type `%s'\n",
275 producer_stage, output->name, output->type->name,
276 consumer_stage, input->type->name);
277 return false;
278 }
279
280 /* Check that all of the qualifiers match between stages.
281 */
282 if (input->centroid != output->centroid) {
283 printf("error: %s shader output `%s' %s centroid qualifier, but "
284 "%s shader input %s centroid qualifier\n",
285 producer_stage,
286 output->name,
287 (output->centroid) ? "has" : "lacks",
288 consumer_stage,
289 (input->centroid) ? "has" : "lacks");
290 return false;
291 }
292
293 if (input->invariant != output->invariant) {
294 printf("error: %s shader output `%s' %s invariant qualifier, but "
295 "%s shader input %s invariant qualifier\n",
296 producer_stage,
297 output->name,
298 (output->invariant) ? "has" : "lacks",
299 consumer_stage,
300 (input->invariant) ? "has" : "lacks");
301 return false;
302 }
303
304 if (input->interpolation != output->interpolation) {
305 printf("error: %s shader output `%s' specifies %s interpolation "
306 "qualifier, "
307 "but %s shader input specifies %s interpolation "
308 "qualifier\n",
309 producer_stage,
310 output->name,
311 output->interpolation_string(),
312 consumer_stage,
313 input->interpolation_string());
314 return false;
315 }
316 }
317 }
318
319 return true;
320}
321
322
Ian Romanick019a59b2010-06-21 16:10:42 -0700323struct uniform_node {
324 exec_node link;
325 struct gl_uniform *u;
326 unsigned slots;
327};
328
329struct gl_uniform_list *
330assign_uniform_locations(struct glsl_shader **shaders, unsigned num_shaders)
331{
332 /* */
333 exec_list uniforms;
334 unsigned total_uniforms = 0;
335 hash_table *ht = hash_table_ctor(32, hash_table_string_hash,
336 hash_table_string_compare);
337
338 for (unsigned i = 0; i < num_shaders; i++) {
339 unsigned next_position = 0;
340
341 foreach_list(node, &shaders[i]->ir) {
342 ir_variable *const var = ((ir_instruction *) node)->as_variable();
343
344 if ((var == NULL) || (var->mode != ir_var_uniform))
345 continue;
346
347 const unsigned vec4_slots = (var->component_slots() + 3) / 4;
348 assert(vec4_slots != 0);
349
350 uniform_node *n = (uniform_node *) hash_table_find(ht, var->name);
351 if (n == NULL) {
352 n = (uniform_node *) calloc(1, sizeof(struct uniform_node));
353 n->u = (gl_uniform *) calloc(vec4_slots, sizeof(struct gl_uniform));
354 n->slots = vec4_slots;
355
356 n->u[0].Name = strdup(var->name);
357 for (unsigned j = 1; j < vec4_slots; j++)
358 n->u[j].Name = n->u[0].Name;
359
360 hash_table_insert(ht, n, n->u[0].Name);
361 uniforms.push_tail(& n->link);
362 total_uniforms += vec4_slots;
363 }
364
365 if (var->constant_value != NULL)
366 for (unsigned j = 0; j < vec4_slots; j++)
367 n->u[j].Initialized = true;
368
369 var->location = next_position;
370
371 for (unsigned j = 0; j < vec4_slots; j++) {
372 switch (shaders[i]->Type) {
373 case GL_VERTEX_SHADER:
374 n->u[j].VertPos = next_position;
375 break;
376 case GL_FRAGMENT_SHADER:
377 n->u[j].FragPos = next_position;
378 break;
379 case GL_GEOMETRY_SHADER:
380 /* FINISHME: Support geometry shaders. */
381 assert(shaders[i]->Type != GL_GEOMETRY_SHADER);
382 break;
383 }
384
385 next_position++;
386 }
387 }
388 }
389
390 gl_uniform_list *ul = (gl_uniform_list *)
391 calloc(1, sizeof(gl_uniform_list));
392
393 ul->Size = total_uniforms;
394 ul->NumUniforms = total_uniforms;
395 ul->Uniforms = (gl_uniform *) calloc(total_uniforms, sizeof(gl_uniform));
396
397 unsigned idx = 0;
398 uniform_node *next;
399 for (uniform_node *node = (uniform_node *) uniforms.head
400 ; node->link.next != NULL
401 ; node = next) {
402 next = (uniform_node *) node->link.next;
403
404 node->link.remove();
405 memcpy(&ul->Uniforms[idx], node->u, sizeof(gl_uniform) * node->slots);
406 idx += node->slots;
407
408 free(node->u);
409 free(node);
410 }
411
412 hash_table_dtor(ht);
413
414 return ul;
415}
416
417
Ian Romanick832dfa52010-06-17 15:04:20 -0700418void
419link_shaders(struct glsl_program *prog)
420{
421 prog->LinkStatus = false;
422 prog->Validated = false;
423 prog->_Used = false;
424
425 /* Separate the shaders into groups based on their type.
426 */
427 struct glsl_shader **vert_shader_list;
428 unsigned num_vert_shaders = 0;
429 struct glsl_shader **frag_shader_list;
430 unsigned num_frag_shaders = 0;
431
432 vert_shader_list = (struct glsl_shader **)
Kenneth Graunkec186b3f2010-06-17 15:37:26 -0700433 calloc(2 * prog->NumShaders, sizeof(struct glsl_shader *));
Ian Romanick832dfa52010-06-17 15:04:20 -0700434 frag_shader_list = &vert_shader_list[prog->NumShaders];
435
436 for (unsigned i = 0; i < prog->NumShaders; i++) {
437 switch (prog->Shaders[i]->Type) {
438 case GL_VERTEX_SHADER:
439 vert_shader_list[num_vert_shaders] = prog->Shaders[i];
440 num_vert_shaders++;
441 break;
442 case GL_FRAGMENT_SHADER:
443 frag_shader_list[num_frag_shaders] = prog->Shaders[i];
444 num_frag_shaders++;
445 break;
446 case GL_GEOMETRY_SHADER:
447 /* FINISHME: Support geometry shaders. */
448 assert(prog->Shaders[i]->Type != GL_GEOMETRY_SHADER);
449 break;
450 }
451 }
452
453 /* FINISHME: Implement intra-stage linking. */
454 assert(num_vert_shaders <= 1);
455 assert(num_frag_shaders <= 1);
456
457 /* Verify that each of the per-target executables is valid.
458 */
459 if (!validate_vertex_shader_executable(vert_shader_list[0])
460 || !validate_fragment_shader_executable(frag_shader_list[0]))
461 goto done;
462
463
464 /* FINISHME: Perform inter-stage linking. */
Ian Romanickcc22c5a2010-06-18 17:13:42 -0700465 glsl_shader *shader_executables[2];
466 unsigned num_shader_executables;
Ian Romanick832dfa52010-06-17 15:04:20 -0700467
Ian Romanickcc22c5a2010-06-18 17:13:42 -0700468 num_shader_executables = 0;
469 if (num_vert_shaders > 0) {
470 shader_executables[num_shader_executables] = vert_shader_list[0];
471 num_shader_executables++;
472 }
473
474 if (num_frag_shaders > 0) {
475 shader_executables[num_shader_executables] = frag_shader_list[0];
476 num_shader_executables++;
477 }
478
Ian Romanick37101922010-06-18 19:02:10 -0700479 if (cross_validate_uniforms(shader_executables, num_shader_executables)) {
480 /* Validate the inputs of each stage with the output of the preceeding
481 * stage.
482 */
483 for (unsigned i = 1; i < num_shader_executables; i++) {
484 if (!cross_validate_outputs_to_inputs(shader_executables[i - 1],
485 shader_executables[i]))
486 goto done;
487 }
488
Ian Romanickcc22c5a2010-06-18 17:13:42 -0700489 prog->LinkStatus = true;
Ian Romanick37101922010-06-18 19:02:10 -0700490 }
Ian Romanick832dfa52010-06-17 15:04:20 -0700491
Ian Romanick13e10e42010-06-21 12:03:24 -0700492 /* FINISHME: Perform whole-program optimization here. */
493
Ian Romanick019a59b2010-06-21 16:10:42 -0700494 prog->Uniforms = assign_uniform_locations(shader_executables,
495 num_shader_executables);
Ian Romanick13e10e42010-06-21 12:03:24 -0700496
497 /* FINISHME: Assign vertex shader input locations. */
498
499 /* FINISHME: Assign vertex shader output / fragment shader input
500 * FINISHME: locations.
501 */
502
503 /* FINISHME: Assign fragment shader output locations. */
504
505 /* FINISHME: Generate code here. */
506
Ian Romanick832dfa52010-06-17 15:04:20 -0700507done:
508 free(vert_shader_list);
509}