glsl: add validation for out layout qualifiers
[mesa.git] / src / compiler / glsl / ast_type.cpp
1 /*
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 #include "ast.h"
25
26 void
27 ast_type_specifier::print(void) const
28 {
29 if (structure) {
30 structure->print();
31 } else {
32 printf("%s ", type_name);
33 }
34
35 if (array_specifier) {
36 array_specifier->print();
37 }
38 }
39
40 bool
41 ast_fully_specified_type::has_qualifiers(_mesa_glsl_parse_state *state) const
42 {
43 /* 'subroutine' isnt a real qualifier. */
44 ast_type_qualifier subroutine_only;
45 subroutine_only.flags.i = 0;
46 subroutine_only.flags.q.subroutine = 1;
47 subroutine_only.flags.q.subroutine_def = 1;
48 if (state->has_explicit_uniform_location()) {
49 subroutine_only.flags.q.explicit_index = 1;
50 }
51 return (this->qualifier.flags.i & ~subroutine_only.flags.i) != 0;
52 }
53
54 bool ast_type_qualifier::has_interpolation() const
55 {
56 return this->flags.q.smooth
57 || this->flags.q.flat
58 || this->flags.q.noperspective;
59 }
60
61 bool
62 ast_type_qualifier::has_layout() const
63 {
64 return this->flags.q.origin_upper_left
65 || this->flags.q.pixel_center_integer
66 || this->flags.q.depth_any
67 || this->flags.q.depth_greater
68 || this->flags.q.depth_less
69 || this->flags.q.depth_unchanged
70 || this->flags.q.std140
71 || this->flags.q.std430
72 || this->flags.q.shared
73 || this->flags.q.column_major
74 || this->flags.q.row_major
75 || this->flags.q.packed
76 || this->flags.q.explicit_align
77 || this->flags.q.explicit_location
78 || this->flags.q.explicit_image_format
79 || this->flags.q.explicit_index
80 || this->flags.q.explicit_binding
81 || this->flags.q.explicit_offset
82 || this->flags.q.explicit_stream;
83 }
84
85 bool
86 ast_type_qualifier::has_storage() const
87 {
88 return this->flags.q.constant
89 || this->flags.q.attribute
90 || this->flags.q.varying
91 || this->flags.q.in
92 || this->flags.q.out
93 || this->flags.q.uniform
94 || this->flags.q.buffer
95 || this->flags.q.shared_storage;
96 }
97
98 bool
99 ast_type_qualifier::has_auxiliary_storage() const
100 {
101 return this->flags.q.centroid
102 || this->flags.q.sample
103 || this->flags.q.patch;
104 }
105
106 /**
107 * This function merges both duplicate identifies within a single layout and
108 * multiple layout qualifiers on a single variable declaration. The
109 * is_single_layout_merge param is used differentiate between the two.
110 */
111 bool
112 ast_type_qualifier::merge_qualifier(YYLTYPE *loc,
113 _mesa_glsl_parse_state *state,
114 const ast_type_qualifier &q,
115 bool is_single_layout_merge)
116 {
117 ast_type_qualifier ubo_mat_mask;
118 ubo_mat_mask.flags.i = 0;
119 ubo_mat_mask.flags.q.row_major = 1;
120 ubo_mat_mask.flags.q.column_major = 1;
121
122 ast_type_qualifier ubo_layout_mask;
123 ubo_layout_mask.flags.i = 0;
124 ubo_layout_mask.flags.q.std140 = 1;
125 ubo_layout_mask.flags.q.packed = 1;
126 ubo_layout_mask.flags.q.shared = 1;
127 ubo_layout_mask.flags.q.std430 = 1;
128
129 ast_type_qualifier ubo_binding_mask;
130 ubo_binding_mask.flags.i = 0;
131 ubo_binding_mask.flags.q.explicit_binding = 1;
132 ubo_binding_mask.flags.q.explicit_offset = 1;
133
134 ast_type_qualifier stream_layout_mask;
135 stream_layout_mask.flags.i = 0;
136 stream_layout_mask.flags.q.stream = 1;
137
138 /* FIXME: We should probably do interface and function param validation
139 * separately.
140 */
141 ast_type_qualifier input_layout_mask;
142 input_layout_mask.flags.i = 0;
143 input_layout_mask.flags.q.centroid = 1;
144 /* Function params can have constant */
145 input_layout_mask.flags.q.constant = 1;
146 input_layout_mask.flags.q.explicit_location = 1;
147 input_layout_mask.flags.q.flat = 1;
148 input_layout_mask.flags.q.in = 1;
149 input_layout_mask.flags.q.invariant = 1;
150 input_layout_mask.flags.q.noperspective = 1;
151 input_layout_mask.flags.q.origin_upper_left = 1;
152 /* Function params 'inout' will set this */
153 input_layout_mask.flags.q.out = 1;
154 input_layout_mask.flags.q.patch = 1;
155 input_layout_mask.flags.q.pixel_center_integer = 1;
156 input_layout_mask.flags.q.precise = 1;
157 input_layout_mask.flags.q.sample = 1;
158 input_layout_mask.flags.q.smooth = 1;
159
160 /* Uniform block layout qualifiers get to overwrite each
161 * other (rightmost having priority), while all other
162 * qualifiers currently don't allow duplicates.
163 */
164 ast_type_qualifier allowed_duplicates_mask;
165 allowed_duplicates_mask.flags.i =
166 ubo_mat_mask.flags.i |
167 ubo_layout_mask.flags.i |
168 ubo_binding_mask.flags.i;
169
170 /* Geometry shaders can have several layout qualifiers
171 * assigning different stream values.
172 */
173 if (state->stage == MESA_SHADER_GEOMETRY)
174 allowed_duplicates_mask.flags.i |=
175 stream_layout_mask.flags.i;
176
177 if (is_single_layout_merge && !state->has_enhanced_layouts() &&
178 (this->flags.i & q.flags.i & ~allowed_duplicates_mask.flags.i) != 0) {
179 _mesa_glsl_error(loc, state,
180 "duplicate layout qualifiers used");
181 return false;
182 }
183
184 if (q.flags.q.prim_type) {
185 if (this->flags.q.prim_type && this->prim_type != q.prim_type) {
186 _mesa_glsl_error(loc, state,
187 "conflicting primitive type qualifiers used");
188 return false;
189 }
190 this->prim_type = q.prim_type;
191 }
192
193 if (q.flags.q.max_vertices) {
194 if (this->max_vertices) {
195 this->max_vertices->merge_qualifier(q.max_vertices);
196 } else {
197 this->max_vertices = q.max_vertices;
198 }
199 }
200
201 if (q.flags.q.subroutine_def) {
202 if (this->flags.q.subroutine_def) {
203 _mesa_glsl_error(loc, state,
204 "conflicting subroutine qualifiers used");
205 } else {
206 this->subroutine_list = q.subroutine_list;
207 }
208 }
209
210 if (q.flags.q.invocations) {
211 if (this->invocations) {
212 this->invocations->merge_qualifier(q.invocations);
213 } else {
214 this->invocations = q.invocations;
215 }
216 }
217
218 if (state->stage == MESA_SHADER_GEOMETRY &&
219 state->has_explicit_attrib_stream()) {
220 if (!this->flags.q.explicit_stream) {
221 if (q.flags.q.stream) {
222 this->flags.q.stream = 1;
223 this->stream = q.stream;
224 } else if (!this->flags.q.stream && this->flags.q.out) {
225 /* Assign default global stream value */
226 this->flags.q.stream = 1;
227 this->stream = state->out_qualifier->stream;
228 }
229 }
230 }
231
232 if (state->has_enhanced_layouts()) {
233 if (!this->flags.q.explicit_xfb_buffer) {
234 if (q.flags.q.xfb_buffer) {
235 this->flags.q.xfb_buffer = 1;
236 this->xfb_buffer = q.xfb_buffer;
237 } else if (!this->flags.q.xfb_buffer && this->flags.q.out) {
238 /* Assign global xfb_buffer value */
239 this->flags.q.xfb_buffer = 1;
240 this->xfb_buffer = state->out_qualifier->xfb_buffer;
241 }
242 }
243
244 if (q.flags.q.explicit_xfb_stride)
245 this->xfb_stride = q.xfb_stride;
246
247 /* Merge all we xfb_stride qualifiers into the global out */
248 if (q.flags.q.explicit_xfb_stride || this->flags.q.xfb_stride) {
249
250 /* Set xfb_stride flag to 0 to avoid adding duplicates every time
251 * there is a merge.
252 */
253 this->flags.q.xfb_stride = 0;
254
255 unsigned buff_idx;
256 if (process_qualifier_constant(state, loc, "xfb_buffer",
257 this->xfb_buffer, &buff_idx)) {
258 if (state->out_qualifier->out_xfb_stride[buff_idx]) {
259 state->out_qualifier->out_xfb_stride[buff_idx]->merge_qualifier(
260 new(state) ast_layout_expression(*loc, this->xfb_stride));
261 } else {
262 state->out_qualifier->out_xfb_stride[buff_idx] =
263 new(state) ast_layout_expression(*loc, this->xfb_stride);
264 }
265 }
266 }
267 }
268
269 if (q.flags.q.vertices) {
270 if (this->vertices) {
271 this->vertices->merge_qualifier(q.vertices);
272 } else {
273 this->vertices = q.vertices;
274 }
275 }
276
277 if (q.flags.q.vertex_spacing) {
278 if (this->flags.q.vertex_spacing && this->vertex_spacing != q.vertex_spacing) {
279 _mesa_glsl_error(loc, state,
280 "conflicting vertex spacing used");
281 return false;
282 }
283 this->vertex_spacing = q.vertex_spacing;
284 }
285
286 if (q.flags.q.ordering) {
287 if (this->flags.q.ordering && this->ordering != q.ordering) {
288 _mesa_glsl_error(loc, state,
289 "conflicting ordering used");
290 return false;
291 }
292 this->ordering = q.ordering;
293 }
294
295 if (q.flags.q.point_mode) {
296 if (this->flags.q.point_mode && this->point_mode != q.point_mode) {
297 _mesa_glsl_error(loc, state,
298 "conflicting point mode used");
299 return false;
300 }
301 this->point_mode = q.point_mode;
302 }
303
304 if ((q.flags.i & ubo_mat_mask.flags.i) != 0)
305 this->flags.i &= ~ubo_mat_mask.flags.i;
306 if ((q.flags.i & ubo_layout_mask.flags.i) != 0)
307 this->flags.i &= ~ubo_layout_mask.flags.i;
308
309 for (int i = 0; i < 3; i++) {
310 if (q.flags.q.local_size & (1 << i)) {
311 if (this->local_size[i]) {
312 this->local_size[i]->merge_qualifier(q.local_size[i]);
313 } else {
314 this->local_size[i] = q.local_size[i];
315 }
316 }
317 }
318
319 this->flags.i |= q.flags.i;
320
321 if (this->flags.q.in &&
322 (this->flags.i & ~input_layout_mask.flags.i) != 0) {
323 _mesa_glsl_error(loc, state,
324 "invalid input layout qualifier used");
325 return false;
326 }
327
328 if (q.flags.q.explicit_align)
329 this->align = q.align;
330
331 if (q.flags.q.explicit_location)
332 this->location = q.location;
333
334 if (q.flags.q.explicit_index)
335 this->index = q.index;
336
337 if (q.flags.q.explicit_binding)
338 this->binding = q.binding;
339
340 if (q.flags.q.explicit_offset || q.flags.q.explicit_xfb_offset)
341 this->offset = q.offset;
342
343 if (q.precision != ast_precision_none)
344 this->precision = q.precision;
345
346 if (q.flags.q.explicit_image_format) {
347 this->image_format = q.image_format;
348 this->image_base_type = q.image_base_type;
349 }
350
351 return true;
352 }
353
354 bool
355 ast_type_qualifier::merge_out_qualifier(YYLTYPE *loc,
356 _mesa_glsl_parse_state *state,
357 const ast_type_qualifier &q,
358 ast_node* &node, bool create_node)
359 {
360 void *mem_ctx = state;
361 const bool r = this->merge_qualifier(loc, state, q, false);
362 ast_type_qualifier valid_out_mask;
363 valid_out_mask.flags.i = 0;
364
365 if (state->stage == MESA_SHADER_GEOMETRY) {
366 if (q.flags.q.prim_type) {
367 /* Make sure this is a valid output primitive type. */
368 switch (q.prim_type) {
369 case GL_POINTS:
370 case GL_LINE_STRIP:
371 case GL_TRIANGLE_STRIP:
372 break;
373 default:
374 _mesa_glsl_error(loc, state, "invalid geometry shader output "
375 "primitive type");
376 break;
377 }
378 }
379
380 /* Allow future assigments of global out's stream id value */
381 this->flags.q.explicit_stream = 0;
382
383 valid_out_mask.flags.q.stream = 1;
384 valid_out_mask.flags.q.explicit_stream = 1;
385 valid_out_mask.flags.q.explicit_xfb_buffer = 1;
386 valid_out_mask.flags.q.xfb_buffer = 1;
387 valid_out_mask.flags.q.explicit_xfb_stride = 1;
388 valid_out_mask.flags.q.xfb_stride = 1;
389 valid_out_mask.flags.q.max_vertices = 1;
390 valid_out_mask.flags.q.prim_type = 1;
391 } else if (state->stage == MESA_SHADER_TESS_CTRL) {
392 if (create_node) {
393 node = new(mem_ctx) ast_tcs_output_layout(*loc);
394 }
395 valid_out_mask.flags.q.vertices = 1;
396 valid_out_mask.flags.q.explicit_xfb_buffer = 1;
397 valid_out_mask.flags.q.xfb_buffer = 1;
398 valid_out_mask.flags.q.explicit_xfb_stride = 1;
399 valid_out_mask.flags.q.xfb_stride = 1;
400 } else if (state->stage == MESA_SHADER_TESS_EVAL ||
401 state->stage == MESA_SHADER_VERTEX) {
402 valid_out_mask.flags.q.explicit_xfb_buffer = 1;
403 valid_out_mask.flags.q.xfb_buffer = 1;
404 valid_out_mask.flags.q.explicit_xfb_stride = 1;
405 valid_out_mask.flags.q.xfb_stride = 1;
406 } else {
407 _mesa_glsl_error(loc, state, "out layout qualifiers only valid in "
408 "geometry, tessellation and vertex shaders");
409 return false;
410 }
411
412 /* Allow future assigments of global out's */
413 this->flags.q.explicit_xfb_buffer = 0;
414 this->flags.q.explicit_xfb_stride = 0;
415
416 /* Generate an error when invalid input layout qualifiers are used. */
417 if ((q.flags.i & ~valid_out_mask.flags.i) != 0) {
418 _mesa_glsl_error(loc, state,
419 "invalid output layout qualifiers used");
420 return false;
421 }
422
423 return r;
424 }
425
426 bool
427 ast_type_qualifier::merge_in_qualifier(YYLTYPE *loc,
428 _mesa_glsl_parse_state *state,
429 const ast_type_qualifier &q,
430 ast_node* &node, bool create_node)
431 {
432 void *mem_ctx = state;
433 bool create_gs_ast = false;
434 bool create_cs_ast = false;
435 ast_type_qualifier valid_in_mask;
436 valid_in_mask.flags.i = 0;
437
438 switch (state->stage) {
439 case MESA_SHADER_TESS_EVAL:
440 if (q.flags.q.prim_type) {
441 /* Make sure this is a valid input primitive type. */
442 switch (q.prim_type) {
443 case GL_TRIANGLES:
444 case GL_QUADS:
445 case GL_ISOLINES:
446 break;
447 default:
448 _mesa_glsl_error(loc, state,
449 "invalid tessellation evaluation "
450 "shader input primitive type");
451 break;
452 }
453 }
454
455 valid_in_mask.flags.q.prim_type = 1;
456 valid_in_mask.flags.q.vertex_spacing = 1;
457 valid_in_mask.flags.q.ordering = 1;
458 valid_in_mask.flags.q.point_mode = 1;
459 break;
460 case MESA_SHADER_GEOMETRY:
461 if (q.flags.q.prim_type) {
462 /* Make sure this is a valid input primitive type. */
463 switch (q.prim_type) {
464 case GL_POINTS:
465 case GL_LINES:
466 case GL_LINES_ADJACENCY:
467 case GL_TRIANGLES:
468 case GL_TRIANGLES_ADJACENCY:
469 break;
470 default:
471 _mesa_glsl_error(loc, state,
472 "invalid geometry shader input primitive type");
473 break;
474 }
475 }
476
477 create_gs_ast |=
478 q.flags.q.prim_type &&
479 !state->in_qualifier->flags.q.prim_type;
480
481 valid_in_mask.flags.q.prim_type = 1;
482 valid_in_mask.flags.q.invocations = 1;
483 break;
484 case MESA_SHADER_FRAGMENT:
485 valid_in_mask.flags.q.early_fragment_tests = 1;
486 break;
487 case MESA_SHADER_COMPUTE:
488 create_cs_ast |=
489 q.flags.q.local_size != 0 &&
490 state->in_qualifier->flags.q.local_size == 0;
491
492 valid_in_mask.flags.q.local_size = 7;
493 break;
494 default:
495 _mesa_glsl_error(loc, state,
496 "input layout qualifiers only valid in "
497 "geometry, fragment and compute shaders");
498 break;
499 }
500
501 /* Generate an error when invalid input layout qualifiers are used. */
502 if ((q.flags.i & ~valid_in_mask.flags.i) != 0) {
503 _mesa_glsl_error(loc, state,
504 "invalid input layout qualifiers used");
505 return false;
506 }
507
508 /* Input layout qualifiers can be specified multiple
509 * times in separate declarations, as long as they match.
510 */
511 if (this->flags.q.prim_type) {
512 if (q.flags.q.prim_type &&
513 this->prim_type != q.prim_type) {
514 _mesa_glsl_error(loc, state,
515 "conflicting input primitive %s specified",
516 state->stage == MESA_SHADER_GEOMETRY ?
517 "type" : "mode");
518 }
519 } else if (q.flags.q.prim_type) {
520 state->in_qualifier->flags.q.prim_type = 1;
521 state->in_qualifier->prim_type = q.prim_type;
522 }
523
524 if (q.flags.q.invocations) {
525 this->flags.q.invocations = 1;
526 if (this->invocations) {
527 this->invocations->merge_qualifier(q.invocations);
528 } else {
529 this->invocations = q.invocations;
530 }
531 }
532
533 if (q.flags.q.early_fragment_tests) {
534 state->fs_early_fragment_tests = true;
535 }
536
537 if (this->flags.q.vertex_spacing) {
538 if (q.flags.q.vertex_spacing &&
539 this->vertex_spacing != q.vertex_spacing) {
540 _mesa_glsl_error(loc, state,
541 "conflicting vertex spacing specified");
542 }
543 } else if (q.flags.q.vertex_spacing) {
544 this->flags.q.vertex_spacing = 1;
545 this->vertex_spacing = q.vertex_spacing;
546 }
547
548 if (this->flags.q.ordering) {
549 if (q.flags.q.ordering &&
550 this->ordering != q.ordering) {
551 _mesa_glsl_error(loc, state,
552 "conflicting ordering specified");
553 }
554 } else if (q.flags.q.ordering) {
555 this->flags.q.ordering = 1;
556 this->ordering = q.ordering;
557 }
558
559 if (this->flags.q.point_mode) {
560 if (q.flags.q.point_mode &&
561 this->point_mode != q.point_mode) {
562 _mesa_glsl_error(loc, state,
563 "conflicting point mode specified");
564 }
565 } else if (q.flags.q.point_mode) {
566 this->flags.q.point_mode = 1;
567 this->point_mode = q.point_mode;
568 }
569
570 if (create_node) {
571 if (create_gs_ast) {
572 node = new(mem_ctx) ast_gs_input_layout(*loc, q.prim_type);
573 } else if (create_cs_ast) {
574 node = new(mem_ctx) ast_cs_input_layout(*loc, q.local_size);
575 }
576 }
577
578 return true;
579 }
580
581 bool
582 ast_layout_expression::process_qualifier_constant(struct _mesa_glsl_parse_state *state,
583 const char *qual_indentifier,
584 unsigned *value,
585 bool can_be_zero)
586 {
587 int min_value = 0;
588 bool first_pass = true;
589 *value = 0;
590
591 if (!can_be_zero)
592 min_value = 1;
593
594 for (exec_node *node = layout_const_expressions.head;
595 !node->is_tail_sentinel(); node = node->next) {
596
597 exec_list dummy_instructions;
598 ast_node *const_expression = exec_node_data(ast_node, node, link);
599
600 ir_rvalue *const ir = const_expression->hir(&dummy_instructions, state);
601
602 ir_constant *const const_int = ir->constant_expression_value();
603 if (const_int == NULL || !const_int->type->is_integer()) {
604 YYLTYPE loc = const_expression->get_location();
605 _mesa_glsl_error(&loc, state, "%s must be an integral constant "
606 "expression", qual_indentifier);
607 return false;
608 }
609
610 if (const_int->value.i[0] < min_value) {
611 YYLTYPE loc = const_expression->get_location();
612 _mesa_glsl_error(&loc, state, "%s layout qualifier is invalid "
613 "(%d < %d)", qual_indentifier,
614 const_int->value.i[0], min_value);
615 return false;
616 }
617
618 if (!first_pass && *value != const_int->value.u[0]) {
619 YYLTYPE loc = const_expression->get_location();
620 _mesa_glsl_error(&loc, state, "%s layout qualifier does not "
621 "match previous declaration (%d vs %d)",
622 qual_indentifier, *value, const_int->value.i[0]);
623 return false;
624 } else {
625 first_pass = false;
626 *value = const_int->value.u[0];
627 }
628
629 /* If the location is const (and we've verified that
630 * it is) then no instructions should have been emitted
631 * when we converted it to HIR. If they were emitted,
632 * then either the location isn't const after all, or
633 * we are emitting unnecessary instructions.
634 */
635 assert(dummy_instructions.is_empty());
636 }
637
638 return true;
639 }
640
641 bool
642 process_qualifier_constant(struct _mesa_glsl_parse_state *state,
643 YYLTYPE *loc,
644 const char *qual_indentifier,
645 ast_expression *const_expression,
646 unsigned *value)
647 {
648 exec_list dummy_instructions;
649
650 if (const_expression == NULL) {
651 *value = 0;
652 return true;
653 }
654
655 ir_rvalue *const ir = const_expression->hir(&dummy_instructions, state);
656
657 ir_constant *const const_int = ir->constant_expression_value();
658 if (const_int == NULL || !const_int->type->is_integer()) {
659 _mesa_glsl_error(loc, state, "%s must be an integral constant "
660 "expression", qual_indentifier);
661 return false;
662 }
663
664 if (const_int->value.i[0] < 0) {
665 _mesa_glsl_error(loc, state, "%s layout qualifier is invalid (%d < 0)",
666 qual_indentifier, const_int->value.u[0]);
667 return false;
668 }
669
670 /* If the location is const (and we've verified that
671 * it is) then no instructions should have been emitted
672 * when we converted it to HIR. If they were emitted,
673 * then either the location isn't const after all, or
674 * we are emitting unnecessary instructions.
675 */
676 assert(dummy_instructions.is_empty());
677
678 *value = const_int->value.u[0];
679 return true;
680 }