glsl-1.10: test mesa bug conflict between globals
[piglit.git] / generated_tests / random_ubo.py
blobf36b8b310cb473289a99c6a032042253e4343d31
1 #!/usr/bin/env python3
2 # coding=utf-8
4 # Copyright (c) 2014 Intel Corporation
6 # Permission is hereby granted, free of charge, to any person obtaining a copy
7 # of this software and associated documentation files (the "Software"), to deal
8 # in the Software without restriction, including without limitation the rights
9 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 # copies of the Software, and to permit persons to whom the Software is
11 # furnished to do so, subject to the following conditions:
13 # The above copyright notice and this permission notice shall be included in
14 # all copies or substantial portions of the Software.
16 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 # SOFTWARE.
24 import random
25 import abc
26 import collections
27 import struct
28 import sys
30 from textwrap import dedent
31 from mako.template import Template
33 # Module-local global variable that tracks all of the structure types that
34 # have been generated since ever.
35 struct_types = dict()
37 ALL130_TYPES = [
38 "float", "vec2", "vec3", "vec4",
39 "int", "ivec2", "ivec3", "ivec4",
40 "uint", "uvec2", "uvec3", "uvec4",
41 "bool", "bvec2", "bvec3", "bvec4",
43 "mat2", "mat2x3", "mat2x4",
44 "mat3x2", "mat3", "mat3x4",
45 "mat4x2", "mat4x3", "mat4"
48 DOUBLE_TYPES = [
49 "double", "dvec2", "dvec3", "dvec4",
51 "dmat2", "dmat2x3", "dmat2x4",
52 "dmat3x2", "dmat3", "dmat3x4",
53 "dmat4x2", "dmat4x3", "dmat4"
56 INT64_TYPES = [
57 "int64_t", "uint64_t",
58 "i64vec2", "i64vec3", "i64vec4",
59 "u64vec2", "u64vec3", "u64vec4"
62 ALL400_TYPES = ALL130_TYPES + DOUBLE_TYPES
64 # All known types, including the redundant NxN matrix types.
65 ALL_TYPES = [ "mat2x2", "mat3x3", "mat4x4",
66 "dmat2x2", "dmat3x3", "dmat4x4"] + ALL400_TYPES + INT64_TYPES
68 def align(offset, alignment):
69 return ((offset + alignment - 1) // alignment) * alignment
72 def isscalar(type):
73 """Return true if the type is a known scalar type from any GLSL version."""
74 return type in ["float", "bool", "int", "uint", "double", "int64_t",
75 "uint64_t"]
78 def isvector(type):
79 """Return true if the type is a known vector type from any GLSL version."""
80 return type in ["vec2", "vec3", "vec4",
81 "ivec2", "ivec3", "ivec4",
82 "uvec2", "uvec3", "uvec4",
83 "bvec2", "bvec3", "bvec4",
84 "dvec2", "dvec3", "dvec4",
85 "i64vec2", "i64vec3", "i64vec4",
86 "u64vec2", "u64vec3", "u64vec4"]
89 def ismatrix(type):
90 """Return true if the type is a known matrix type from any GLSL version."""
91 return type in ["mat2", "mat3", "mat4",
92 "mat2x2", "mat2x3", "mat2x4",
93 "mat3x2", "mat3x3", "mat3x4",
94 "mat4x2", "mat4x3", "mat4x4",
95 "dmat2", "dmat3", "dmat4",
96 "dmat2x2", "dmat2x3", "dmat2x4",
97 "dmat3x2", "dmat3x3", "dmat3x4",
98 "dmat4x2", "dmat4x3", "dmat4x4"]
101 def isarray(type):
102 """Return true if the type name appears to be an array type."""
103 return "[" in type
106 def isstructure(type):
107 """Return true if the type name appears to be a structure type.
109 This function works by process of elimination. If the named type is not a
110 scalar, vector, matrix, or array, then it must be a structure.
112 NOTE: If the type is an array-of-structure type, this function will return
113 false.
115 return not (isscalar(type) or isvector(type) or ismatrix(type) or
116 isarray(type))
119 def vector_size(type):
120 """Return the number of elements in a vector type."""
121 if isvector(type):
122 return int(type[-1:])
124 raise Exception("Non-vector type {}".format(type))
127 def matrix_dimensions(type):
128 """Return the dimensions of an array type.
130 The tuple returned is (columns, rows).
132 if not ismatrix(type):
133 raise Exception("Non-matrix type {}".format(type))
135 if "x" in type:
136 s = type[-3:].split("x")
137 return int(s[0]), int(s[1])
138 else:
139 d = int(type[-1:])
140 return d, d
143 def array_elements(type):
144 """Return the number of elements in an array type.
146 For non-array types zero is returned.
148 if "[" not in type:
149 return 0
151 # Is there a better way to do this?
152 return int(type.split("[")[1].split("]")[0])
154 def basic_machine_units(type):
155 """Return the size in 'basic machine units' of a scalar type."""
156 if type in ["float", "bool", "int", "uint"]:
157 return 4
159 if type in ["double", "int64_t", "uint64_t"]:
160 return 8
162 raise Exception("Non-scalar type {}".format(type))
165 def array_base_type(type):
166 """Return the type of an element from an array type."""
167 if not isarray(type):
168 raise Exception("Non-array type {}".format(type))
170 return type[:type.index("[")] + type[type.index("]")+1:]
172 def without_array(type):
173 """Return the type of an element with all arrays removed."""
174 if not isarray(type):
175 raise Exception("Non-array type {}".format(type))
177 return type.split("[")[0]
179 def arrays_of_arrays_size(type):
180 """Return the total number of elements in an array of arrays."""
181 if not isarray(type):
182 raise Exception("Non-array type {}".format(type))
184 size = 1
185 base_type = type
186 while (isarray(base_type)):
187 size = size * array_elements(base_type)
188 base_type = array_base_type(base_type)
190 return size
192 def vector_base_type(type):
193 """Return the type of an element from a vector."""
194 if not isvector(type):
195 raise Exception("Non-vector type {}".format(type))
197 if type[0:1] == "i6":
198 return "int64_t"
199 elif type[0:1] == "u6":
200 return "uint64_t"
201 elif type[0] == 'v':
202 return "float"
203 elif type[0] == 'i':
204 return "int"
205 elif type[0] == 'u':
206 return "uint"
207 elif type[0] == 'b':
208 return "bool"
209 elif type[0] == 'd':
210 return "double"
211 else:
212 raise Exception("Unknown vector type {}".format(type))
215 def iterate_structures(fields, types_seen=[], types_yielded=[]):
216 """Given a list of fields, yields the structures in the fields in proper
217 declaration order. Detects recurrsion in the types and raises an
218 exception.
220 for (type, name) in fields:
221 if isarray(type):
222 type = without_array(type)
224 if not isstructure(type):
225 continue
227 if type in types_seen:
228 raise Exception("Type recurrsion involving {}".format(type))
230 for t in iterate_structures(struct_types[type],
231 types_seen + [type],
232 types_yielded):
233 yield t
235 if type not in types_yielded:
236 types_yielded.append(type)
237 yield type
240 def select_basic_type(types, names):
241 """Return a random type with a matching field name.
243 From the list of supplied types, picks a random type. Using supplied
244 unique_name_dict, a name is also chosen. The two are returned as a tuple.
246 t = random.choice(types)
247 return t, names.get_name(t)
250 def generate_struct_of_basic_types(types, names):
251 """Return a sequence of random types with unique field names."""
252 return [select_basic_type(types, names)
253 for i in range(0, random.randint(1,12))]
256 def generate_member_from_description(description, builtin_types, names):
257 """Generate a single block member for a list of required attributes.
259 The list of required attributes is a sequence of 'struct' and 'array'
260 perhaps terminated with the name of a GLSL basic type. In addition to any
261 required subfields, structures generated in the sequence will be populated
262 with a random selection of available GLSL types named in builtin_types.
264 A matrix orientation can also be listed as the first requirement.
265 However, that is not handled by this function, and it will be ignored.
267 The tuple returned is (member_type, member_name).
269 if len(description) == 0:
270 return select_basic_type(builtin_types, names)
272 item = description[0]
273 if item == "array":
274 base_type, name = generate_member_from_description(
275 description[1:],
276 builtin_types,
277 names)
279 # If we're making an array of something that can be "big," try to make
280 # the array a little smaller.
282 if ismatrix(base_type) or isarray(base_type) or isstructure(base_type):
283 size = random.choice([2, 3, 5, 7])
284 else:
285 size = random.choice([3, 5, 7, 11, 13])
287 t = "{}[{}]".format(base_type, size)
288 return t, name
289 elif item == "struct":
290 fields = generate_struct_of_basic_types(builtin_types, names)
291 random.shuffle(fields)
293 # Peek ahead. If the next item in the description is a built-in type,
294 # then all of the remaining items must be built-in types. Generate a
295 # list of these.
297 if len(description) > 1 and description[1] in ALL_TYPES:
298 required_fields = [generate_member_from_description([i],
299 builtin_types,
300 names)
301 for i in description[1:]]
303 else:
304 required_fields = [generate_member_from_description(
305 description[1:],
306 builtin_types,
307 names)]
309 # Pick a random spot in the list of "common" fields and insert all of
310 # the required fields there.
312 j = random.randint(0, len(fields))
313 f = fields[:j] + required_fields + fields[j:]
315 struct_name = "S{}".format(len(struct_types) + 1)
316 struct_types[struct_name] = f
318 field_name = names.get_name(struct_name)
319 return struct_name, field_name
320 elif item in ALL_TYPES:
321 return item, names.get_name(item)
322 elif item in ["row_major", "column_major", "#column_major"]:
323 # While "row_major" and "column_major" are valid requirements, they
324 # are not processed here. Just skip over them for now.
325 return generate_member_from_description(description[1:],
326 builtin_types,
327 names)
329 raise Exception("Invalid UBO member description {}".format(item))
332 def generate_ubo(description_list, builtin_types):
333 """Generate a uniform block for a list of requirements.
335 Each member of description_list is taken to be a sequence of requirements
336 for a single field in the uniform block. These are processed by
337 generate_member_from_description.
339 In addition to the list of required fields, the uniform block is also
340 populated with a random selection of available GLSL types named in
341 builtin_types.
343 layouts = dict()
344 names = unique_name_dict()
346 fields = []
348 for desc in description_list:
349 m = generate_member_from_description(desc, builtin_types, names)
350 fields.append(m)
352 if desc[0] in ["row_major", "column_major", "#column_major"]:
353 layouts[m[1]] = desc[0]
355 fields.extend(generate_struct_of_basic_types(builtin_types, names))
356 random.shuffle(fields)
358 required_layouts = []
359 for (field_type, field_name) in fields:
360 if field_name in layouts:
361 required_layouts.append(layouts[field_name])
362 else:
363 required_layouts.append(None)
365 return fields, required_layouts
368 def generate_layouts(fields, required_layouts, allow_row_major_structure):
369 """Generate a directed random sequence of layout qualifiers.
371 Elements in requred_layouts that are non-None will have the same value in
372 the final sequence. Remaining elements matching entries in fields that
373 are either structure or matrix types will have random layouts assigned.
375 If allow_row_major_structure is not set, only matrix types will have
376 random layout assignments. Explicit layouts in required_layouts are
377 unaffected.
379 if required_layouts is None:
380 required_layouts = [None] * len(fields)
382 layouts = []
383 for ((type, name), lay) in zip(fields, required_layouts):
384 if isarray(type):
385 type = without_array(type)
387 if lay:
388 layouts.append(lay)
389 elif isstructure(type) and not allow_row_major_structure:
390 # This would work-around a bug in NVIDIA closed source drivers.
391 # They do not propagate row-major down into structures.
393 layouts.append("#column_major")
394 elif ismatrix(type) or isstructure(type):
395 # Choose a random matrix orientation. The #column_major are
396 # ignored when the UBO is emitted, but when a the UBO is
397 # re-emitted with a default row-major layout, these become
398 # "column_major".
400 layouts.append(random.choice(["#column_major",
401 "#column_major",
402 "#column_major",
403 "row_major",
404 "row_major",
405 "column_major"]))
406 else:
407 layouts.append("")
408 return layouts
411 def relayout_for_default_row_major(l):
412 """Return a new layout for an assumed default layout of row-major."""
413 if l == "row_major":
414 return "#row_major"
415 elif l == "column_major" or l == "#column_major":
416 return "column_major"
417 elif l == "":
418 return ""
419 else:
420 raise Exception("Invalid layout {}".format(l))
423 def fields_to_glsl_struct(type):
424 """From a name structure type, generate a GLSL definition of that
425 structure.
427 # The longest type name will have the form 'dmatCxR[##]' for 11
428 # characters. Use this to set the spacing between the field type and the
429 # field name.
431 structure_template = Template(dedent("""\
432 struct ${struct_name} {
433 % for (field_type, field_name) in fields:
434 ${"{:<11}".format(field_type)} ${field_name};
435 % endfor
437 """))
439 return structure_template.render(struct_name=type, fields=struct_types[type])
441 def iterate_struct_array_recursive(field_type,
442 name_from_API,
443 name_from_shader,
444 packing,
445 offset,
446 row_major,
447 field_row_major,
448 explicit_layout):
450 astride = packing.array_stride(field_type, field_row_major)
451 array_member_align = packing.base_alignment(field_type, field_row_major)
453 element_t = array_base_type(field_type)
455 for i in range(array_elements(field_type)):
456 name_from_API_with_index = "{}[{}]".format(name_from_API, i)
457 name_from_shader_with_index = "{}[{}]".format(name_from_shader, i)
459 if isarray(element_t):
460 inner_aoa_size = arrays_of_arrays_size(element_t)
461 o = align(offset, array_member_align) + (astride * i * inner_aoa_size)
463 for x in iterate_struct_array_recursive(element_t,
464 name_from_API_with_index,
465 name_from_shader_with_index,
466 packing,
468 row_major,
469 field_row_major,
470 explicit_layout):
471 yield x
473 a = packing.base_alignment(x.GLSL_type, row_major)
474 o = align(o, a) + packing.size(x.GLSL_type, row_major)
475 else:
476 o = align(offset, array_member_align) + (astride * i)
477 yield block_member(
478 name_from_shader_with_index,
479 name_from_API_with_index,
480 element_t,
481 explicit_layout,
483 field_row_major)
484 for x in iterate_all_recursive(struct_types[element_t],
485 None,
486 name_from_API_with_index,
487 name_from_shader_with_index,
488 packing,
490 field_row_major):
491 yield x
493 a = packing.base_alignment(x.GLSL_type, row_major)
494 o = align(o, a) + packing.size(x.GLSL_type, row_major)
496 def iterate_all_recursive(fields,
497 field_layouts,
498 name_from_API_base,
499 name_from_shader_base,
500 packing,
501 offset,
502 row_major):
503 """In-order recursive iteration of all subfields of a structure type
505 fields -- List of fields in the uniform block or structure
506 field_layouts -- Layout for each field in the uniform block (None for
507 structures).
508 name_from_API_base -- Base name of the member as it would be accessed via
509 the GL API.
510 name_from_shader_base -- Base name of the member as it would be accessed via
511 the GLSL shader.
512 packing -- Packing rules used to layout the type
513 offset -- Aligned base offset of the member
514 row_major -- True if the current matrix orientation is row-major
516 At each step of the iteration will yield a block_member object
517 representing the member.
519 Basic GLSL types will be visited once. Arrays of basic GLSL types will
520 also be visited once.
522 A structure will be visited once, then each field in the structure will be
523 visited.
525 An array of structures will be visited once, then each element of the
526 array will be visited. Since each element is a structure, each field will
527 be visited.
529 Consider the following structure:
531 struct S2 {
532 int i;
533 float f[2];
536 struct S1 {
537 S2 s[2];
540 If name_from_API_base is "x", the members would be visited in the
541 following order: "x.s", "x.s[0]", "x.s[0].i", "x.s[0].f[0]", "x.s[1]",
542 "x.s[1].i", "x.s[1].f[0]".
544 See also iterate_all_block_members.
546 if field_layouts is None:
547 field_layouts = [""] * len(fields)
549 if len(name_from_shader_base) > 0:
550 fmt = "{base}.{field}"
551 else:
552 fmt = "{field}"
554 for ((field_type, field_name), explicit_layout) in zip(fields,
555 field_layouts):
556 name_from_shader = fmt.format(
557 base=name_from_shader_base,
558 field=field_name)
559 name_from_API = fmt.format(
560 base=name_from_API_base,
561 field=field_name)
563 if explicit_layout == "row_major":
564 field_row_major = True
565 elif explicit_layout == "column_major":
566 field_row_major = False
567 else:
568 field_row_major = row_major
570 if isarray(field_type):
571 base_type = without_array(field_type)
573 if isstructure(base_type):
574 yield block_member(
575 name_from_shader,
576 name_from_API,
577 field_type,
578 explicit_layout,
579 offset,
580 field_row_major)
582 for x in iterate_struct_array_recursive(field_type,
583 name_from_API,
584 name_from_shader,
585 packing,
586 offset,
587 row_major,
588 field_row_major,
589 explicit_layout):
590 yield x
592 elif ismatrix(base_type):
593 yield block_member(
594 name_from_shader,
595 name_from_API,
596 field_type,
597 explicit_layout,
598 offset,
599 field_row_major)
600 else:
601 yield block_member(
602 name_from_shader,
603 name_from_API,
604 field_type,
606 offset,
607 False)
608 elif isstructure(field_type):
609 yield block_member(
610 name_from_shader,
611 name_from_API,
612 field_type,
613 explicit_layout,
614 offset,
615 field_row_major)
617 a = packing.base_alignment(field_type, field_row_major)
619 for x in iterate_all_recursive(struct_types[field_type],
620 None,
621 name_from_API,
622 name_from_shader,
623 packing,
624 align(offset, a),
625 field_row_major):
626 yield x
628 elif ismatrix(field_type):
629 yield block_member(
630 name_from_shader,
631 name_from_API,
632 field_type,
633 explicit_layout,
634 offset,
635 field_row_major)
636 elif isvector(field_type) or isscalar(field_type):
637 yield block_member(
638 name_from_shader,
639 name_from_API,
640 field_type,
642 offset,
643 False)
644 else:
645 raise Exception("Malformed type name {}".format(field_type))
647 a = packing.base_alignment(field_type, field_row_major)
648 offset = align(offset, a) + packing.size(field_type, field_row_major)
651 def iterate_all_block_members(fields,
652 field_layouts,
653 block_name,
654 instance_name,
655 packing,
656 row_major):
657 """In-order recursive iteration of all subfields of a block
659 fields -- List of fields in the uniform block
660 field_layouts -- Layout for each field in the uniform block
661 block_name - Name of the uniform block
662 instance_name - Instance name associated with the block. May be None.
663 packing -- Packing rules used to layout the type
664 row_major -- True if the default block matrix orientation is row-major
666 At each step of the iteration will yield a block_member object
667 representing the member.
669 Basic GLSL types will be visited once. Arrays of basic GLSL types will
670 also be visited once.
672 A structure will be visited once, then each field in the structure will be
673 visited.
675 An array of structures will be visited once, then each element of the
676 array will be visited. Since each element is a structure, each field will
677 be visited.
679 Consider the following block:
681 struct S {
682 int i;
683 float f[2];
686 uniform U {
687 S s[2];
690 The members would be visited in the following order: s, s[0], s[0].i,
691 s[0].f[0], s[1], s[1].i, s[1].f[0].
693 for x in iterate_all_recursive(fields,
694 field_layouts,
695 block_name,
696 instance_name,
697 packing,
699 row_major):
700 yield x
703 def hash_string(string):
704 """The djb2 string hash algorithm from the old comp.lang.c days. Not a
705 terrific hash, but we just need a pseudorandom number based on the string.
706 This will do.
708 This is used instead of the built-in hash function so that the results
709 will be consistent on other systems. See
710 http://stackoverflow.com/questions/793761/built-in-python-hash-function.
712 h = 5381
714 for c in string:
715 h = h * 33 + ord(c)
717 return h & 0x0ffffffff
720 def random_data(type, name, offset):
721 """Generate pseudorandom data.
723 The data generated is based on the type, name of the field, and offset of
724 the member in the UBO.
726 if isscalar(type):
727 h = hash_string("{}@{}".format(offset, name))
729 if type == "int" or type == "int64_t":
730 return str(h - 0x7fffffff)
731 elif type == "uint" or type == "uint64_t":
732 return str(h)
733 elif type == "bool":
734 return str(int((h & 8) == 0))
735 elif type == "float" or type == "double":
736 return str(float(h - 0x7fffffff) / 65535.0)
737 else:
738 raise Exception("Unknown scalar type {}".format(type))
740 if isvector(type):
741 scalar = vector_base_type(type)
743 x = [random_data(scalar, name, offset + (i * 3))
744 for i in range(vector_size(type))]
745 return " ".join(x)
747 if ismatrix(type):
748 r, c = matrix_dimensions(type)
750 x = [random_data("float", name, offset + (i * 7))
751 for i in range(r * c)]
752 return " ".join(x)
755 def generate_test_vectors(fields,
756 field_layouts,
757 block_name,
758 instance_name,
759 packing,
760 row_major):
761 test_vectors = []
763 for m in iterate_all_block_members(fields,
764 field_layouts,
765 block_name,
766 instance_name,
767 packing,
768 row_major):
769 a = packing.base_alignment(m.GLSL_type, m.row_major)
771 if isarray(m.GLSL_type):
772 size = array_elements(m.GLSL_type)
773 base_type = array_base_type(m.GLSL_type)
774 astride = packing.array_stride(m.GLSL_type, m.row_major)
775 name = m.API_name + "[0]"
776 while(isarray(base_type)):
777 size = array_elements(base_type)
778 base_type = array_base_type(base_type)
779 name = name + "[0]"
780 else:
781 base_type = m.GLSL_type
782 astride = 0
783 name = m.API_name
784 size = m.size
786 if ismatrix(base_type):
787 test_vectors.append((
788 name,
789 m.API_type,
790 size,
791 align(m.offset, a),
792 astride,
793 packing.matrix_stride(base_type, m.row_major),
794 int(m.row_major)))
795 elif isvector(base_type) or isscalar(base_type):
796 test_vectors.append((
797 name,
798 m.API_type,
799 size,
800 align(m.offset, a),
801 astride,
805 return test_vectors
808 def scalar_derp(type, name, data):
809 """Return a GLSL code string to compare a scalar with its expected value."""
810 if type == "bool":
811 if int(data) == 0:
812 return name
813 else:
814 return "!" + name
815 elif type == "uint":
816 return "{} != {}u".format(name, data)
817 elif type == "int":
818 return "{} != {}".format(name, data)
819 elif type == "uint64_t":
820 return "{} != {}ul".format(name, data)
821 elif type == "int64_t":
822 return "{} != {}l".format(name, data)
823 elif type == "float":
824 # Not all implementations support the bit-cast operators that are used
825 # to do bit-exact comparisons. For this reason float_match needs the
826 # float data and the bit-exact data.
828 bits = bit_exact_data(data, "float")
829 return "!float_match({}, {}, {}u)".format(name, data, bits)
830 elif type == "double":
831 bits = bit_exact_data(data, "double")
833 # 0xHHHHHHHHLLLLLLLL
834 # 012345678901234567
836 hi = "0x" + bits[2:10]
837 lo = "0x" + bits[10:18]
839 return "!double_match({}, uvec2({}, {}))".format(name, lo, hi)
840 else:
841 raise Exception("Unknown scalar type {}".format(type))
844 def vector_derp(type, name, data):
845 """Return a list of GLSL code strings that compare each field of a vector
846 its expected value.
848 scalar = vector_base_type(type)
849 components = ["x", "y", "z", "w"]
851 return [scalar_derp(scalar,
852 "{}.{}".format(name, "xyzw"[i]),
853 data[i])
854 for i in range(vector_size(type))]
857 def matrix_derp(type, name, data):
858 """Return a list of GLSL code strings that compare each field of a matrix
859 its expected value.
861 c, r = matrix_dimensions(type)
863 if type[0] == 'd':
864 column_type = "dvec{}".format(r)
865 else:
866 column_type = "vec{}".format(r)
868 data_pairs = []
870 for i in range(c):
871 data_pairs.extend(vector_derp(
872 column_type,
873 "{}[{}]".format(name, i),
874 data[(i * r):(i * r) + r]))
876 return data_pairs
879 def fudge_type_for_setter(type):
880 """Return the correct type for the GL API to set the uniform.
882 Most GLSL data types are set using a the enum name for the actual type.
883 The sole exception is bool and related vector types. For bool types, the
884 same-sized (scalar or vector) integer type is used.
886 if type[0] == 'b':
887 if type == "bool":
888 return "int"
889 else:
890 return "i" + type[1:]
891 else:
892 return type
895 def bit_exact_data(raw_data, type):
896 """Several places in the test want bit-exact data for all types.
897 For integer types, this is just the raw data. For floating point (both
898 single and double precision) types, the bit-exact data is the hex
899 representation of the IEEE 754 encoding.
901 if type in ["float", "vec2", "vec3", "vec4",
902 "mat2", "mat2x2", "mat2x3", "mat2x4",
903 "mat3", "mat3x2", "mat3x3", "mat3x4",
904 "mat4", "mat4x2", "mat4x3", "mat4x4"]:
905 exact_data = []
907 for d in raw_data.split(" "):
908 p = struct.pack('!f', float(d))
909 u = struct.unpack('!I', p)[0]
910 exact_data.append(hex(u))
912 return " ".join(exact_data)
913 elif type in ["double", "dvec2", "dvec3", "dvec4",
914 "dmat2", "dmat2x2", "dmat2x3", "dmat2x4",
915 "dmat3", "dmat3x2", "dmat3x3", "dmat3x4",
916 "dmat4", "dmat4x2", "dmat4x3", "dmat4x4"]:
917 exact_data = []
919 for d in raw_data.split(" "):
920 p = struct.pack('!d', float(d))
921 u = struct.unpack('!Q', p)[0]
923 # Sometimes the hex() generates a spurious "L" at the end of the
924 # string. Only take the first 18 characters to omit the unwanted
925 # "L". I believe this occurs when bit 63 is set.
927 exact_data.append(hex(u)[0:18])
929 return " ".join(exact_data)
930 else:
931 return raw_data
933 def generate_array_data_pairs(name, api_name, element_type, row_major, offset, packing, setters, checkers):
934 base_type = array_base_type(element_type)
936 astride = packing.array_stride(element_type, row_major)
938 for i in range(array_elements(element_type)):
940 name_with_index = "{}[{}]".format(name, i)
941 api_name_with_index = "{}[{}]".format(api_name, i)
943 if isarray(base_type):
944 offset = offset + (i * arrays_of_arrays_size(base_type) * astride)
945 generate_array_data_pairs(name_with_index, api_name_with_index, base_type, row_major, offset, packing, setters, checkers)
946 else:
947 offset = offset + (i * astride)
948 raw_data = random_data(base_type, name_with_index, offset)
949 setters.append(
950 (fudge_type_for_setter(base_type),
951 api_name_with_index,
952 bit_exact_data(raw_data, base_type)))
954 data = raw_data.split(" ")
956 if isscalar(base_type):
957 checkers.append(scalar_derp(base_type,
958 name_with_index,
959 data[0]))
960 elif isvector(base_type):
961 checkers.extend(vector_derp(base_type,
962 name_with_index,
963 data))
964 elif ismatrix(base_type):
965 checkers.extend(matrix_derp(base_type,
966 name_with_index,
967 data))
969 def generate_data_pairs(uniform_blocks, packing):
970 """Return GLSL code to test values and shader_runner code to set them.
972 For each element in each uniform block, two lists are generated, and these
973 lists are returned in a tuple of (checkers, setters). The "checkers" list
974 is a list of GLSL comparisons that return true if the contents of the
975 uniform block element DOES NOT match the expected value.
977 The "setters" list is a list of shader_runner "uniform" statements to set
978 each uniform block member to an expected value.
980 checkers = []
981 setters = []
983 for (block_name,
984 instance_name,
985 global_layout,
986 block_layout,
987 fields,
988 field_layouts) in uniform_blocks:
989 for m in iterate_all_block_members(
990 fields,
991 field_layouts,
992 block_name,
993 instance_name,
994 packing,
995 block_row_major_default(global_layout, block_layout)):
997 if m.API_type:
998 if isarray(m.GLSL_type):
999 generate_array_data_pairs(m.GLSL_name, m.API_name, m.GLSL_type, m.row_major, m.offset, packing, setters, checkers)
1000 else:
1001 raw_data = random_data(m.GLSL_type, m.GLSL_name, m.offset)
1002 setters.append((fudge_type_for_setter(m.GLSL_type),
1003 m.API_name,
1004 bit_exact_data(raw_data, m.GLSL_type)))
1006 data = raw_data.split(" ")
1008 if isscalar(m.GLSL_type):
1009 checkers.append(scalar_derp(m.GLSL_type,
1010 m.GLSL_name,
1011 data[0]))
1012 elif isvector(m.GLSL_type):
1013 checkers.extend(vector_derp(m.GLSL_type,
1014 m.GLSL_name,
1015 data))
1016 elif ismatrix(m.GLSL_type):
1017 checkers.extend(matrix_derp(m.GLSL_type,
1018 m.GLSL_name,
1019 data))
1021 return checkers, setters
1024 def pretty_format_type_data(packing, type, offset, row_major):
1025 """Return a string describing the layout of the type
1027 This string is intended to be a comment embedded in the GLSL shader code
1028 that is generated.
1030 a = packing.base_alignment(type, row_major)
1031 aligned_offset = align(offset, a)
1032 size = packing.size(type, row_major)
1034 row_major_str = "-"
1035 mstride = "-"
1036 astride = "-"
1038 if isarray(type):
1039 astride = packing.array_stride(type, row_major)
1041 base_type = without_array(type)
1042 if ismatrix(base_type) and row_major:
1043 if row_major:
1044 row_major_str = "yes"
1045 else:
1046 row_major_str = "no"
1048 mstride = packing.matrix_stride(base_type, row_major)
1049 else:
1050 if ismatrix(type):
1051 if row_major:
1052 row_major_str = "yes"
1053 else:
1054 row_major_str = "no"
1056 mstride = packing.matrix_stride(type, row_major)
1058 return "{base_align:>3} {base_offset:>4} {aligned_offset:>5} {padded_size:>6} {row_major:^5} {array_stride:>6} {matrix_stride:>6}".format(
1059 base_align=a,
1060 base_offset=offset,
1061 aligned_offset=aligned_offset,
1062 padded_size=size,
1063 row_major=row_major_str,
1064 array_stride=astride,
1065 matrix_stride=mstride
1069 def pretty_format_member(m, packing):
1070 """Return a string of GLSL code to declare the member.
1072 m -- a block_member object
1073 packing -- packing rules
1075 If the member is "nested" inside a structure, the string returned will be
1076 a comment simply describing the layout of the submember.
1078 # If the name ends in an array subscript, emit a special line to note that
1079 # the following fields are the contents of an element of an array of
1080 # structures.
1081 if m.GLSL_name[-1] == "]":
1082 n = m.struct_nesting() + 1
1083 indent = "// " + (" " * n)
1085 return "{indent}{index}".format(indent=indent,
1086 index=m.GLSL_name[m.GLSL_name.index("["):])
1088 # Strip off everything before the last period.
1089 name = m.GLSL_name.split(".")[-1]
1091 n = m.struct_nesting()
1092 if n > 0:
1093 indent = "// " + (" " * n)
1094 field_str = "{indent}{type:<11} {name:<20}".format(
1095 indent=indent,
1096 type=m.GLSL_type,
1097 name=name)[0:31]
1098 else:
1099 field_str = " {type:<11}{name};{padding}// ".format(
1100 type=m.GLSL_type,
1101 name=name,
1102 padding=" "[len(name):])
1104 data_str = pretty_format_type_data(
1105 packing,
1106 m.GLSL_type,
1107 m.offset,
1108 m.row_major)
1110 # If there is an explicit layout for the member, prepend it to the member
1111 # declaration. This also means that the member must be contained directly
1112 # in the UBO (i.e., not nested in a struct), so no additional indentation
1113 # is necessary.
1115 if m.explicit_layout and "#" not in m.explicit_layout:
1116 return " layout({layout})\n{field}{data}".format(
1117 layout=m.explicit_layout,
1118 field=field_str,
1119 data=data_str)
1120 else:
1121 return "{field}{data}".format(field=field_str, data=data_str)
1124 def block_row_major_default(global_layout, block_layout):
1125 """Return true if the default matrix layout for the block is row-major."""
1126 row_major = global_layout is not None and "row_major" in global_layout
1128 if block_layout:
1129 if "row_major" in block_layout:
1130 row_major = True
1131 elif "column_major" in block_layout:
1132 # The block layout can override a previous global layout.
1133 row_major = False
1135 return row_major
1138 def generate_block_list(glsl_version, packing, ubo_fields, layouts):
1139 """Return list of uniform blocks to be passed to emit_shader_test.
1141 The supplied ubo_fields and layouts are reformatted as an element in a
1142 list of blocks that can be consumed by emit_shader_test. Depending on the
1143 value of glsl_version, additional blocks may be added to the list. The
1144 new blocks will have the same layout as the original, but the layout will
1145 be specified in different ways (e.g., by using a global layout qualifier).
1148 blocks = [("UB1", "", None, packing.layout_string(), ubo_fields, layouts)]
1150 # If the GLSL version is at least 1.50, UBO functionality is significantly
1151 # extended.
1153 # 1. Uniform blocks can have instance names. The existence of the name
1154 # changes the way the block is queried through the API (with the block
1155 # name) and the way it is accessed by the shader (with the instance
1156 # name).
1158 # 2. Uniform blocks can be grouped in arrays. UBO arrays must have an
1159 # instance name.
1161 # This is used to make the tests dramatically more complex. Each UBO is
1162 # emitted three times.
1164 # 1. Without an instance name.
1166 # 2. With an instance name and the per-block matrix layout switched to
1167 # row_major. The declared layout of the individual fields is modified
1168 # so that this block has the same layout as the previous block.
1170 # 3. With an instance name and an array size. The per-block matrix layout
1171 # is empty, but the global matrix layout is changed to row_major. This
1172 # block should have the same layout as the previous two.
1174 if glsl_version >= 150:
1175 inverted_layouts = [relayout_for_default_row_major(l) for l in layouts]
1177 blocks.append(("UB2",
1178 "ub2",
1179 None,
1180 packing.layout_string() + ", row_major",
1181 ubo_fields,
1182 inverted_layouts))
1184 blocks.append(("UB3",
1185 "ub3",
1186 # Disabled to work around Mesa bug #83508.
1187 # "ub3[2]",
1188 packing.layout_string() + ", row_major",
1189 None,
1190 ubo_fields,
1191 inverted_layouts))
1193 return blocks
1196 def emit_shader_test(blocks, packing, glsl_version, extensions):
1197 structures = []
1198 test_vectors = []
1200 for (block_name,
1201 instance_name,
1202 global_layout,
1203 block_layout,
1204 fields,
1205 field_layouts) in blocks:
1207 structures.extend([s for s in iterate_structures(fields)])
1209 test_vectors.extend(generate_test_vectors(
1210 fields,
1211 field_layouts,
1212 block_name,
1213 instance_name,
1214 packing,
1215 block_row_major_default(global_layout, block_layout)))
1218 checkers, setters = generate_data_pairs(blocks, packing)
1220 # If the GLSL version is at least 1.40, UBOs are already supported, and we
1221 # don't need to enable the extension.
1223 if glsl_version >= 140 and "GL_ARB_uniform_buffer_object" in extensions:
1224 extensions.remove("GL_ARB_uniform_buffer_object")
1226 t = Template(dedent("""\
1227 [require]
1228 GLSL >= ${glsl_version // 100}.${glsl_version % 100}
1229 % for ext in extensions:
1230 ${ext}
1231 % endfor
1233 # Do NOT edit the following lines.
1234 # GLSL ${glsl_version}
1235 # EXTENSIONS ${extensions}
1236 # PACKING ${packing.layout_string()}
1237 % for s in structures:
1238 # STRUCT ("${s}", ${struct_types[s]})
1239 % endfor
1240 % for b in uniform_blocks:
1241 # UBO ${b}
1242 % endfor
1243 # DATA END
1245 [vertex shader]
1246 % for ext in extensions:
1247 #extension ${ext}: require
1248 % endfor
1249 #extension GL_ARB_shader_bit_encoding: enable
1250 #extension GL_ARB_gpu_shader5: enable
1252 precision highp float;
1253 % for s in structures:
1255 struct ${s} {
1256 % for (field_type, field_name) in struct_types[s]:
1257 ${"{:<11}".format(field_type)} ${field_name};
1258 % endfor
1260 % endfor
1262 % for (block_name, instance_name, global_layout, block_layout, fields, field_layouts) in uniform_blocks:
1263 % if global_layout:
1264 layout(${global_layout}) uniform;
1266 % endif
1267 % if block_layout:
1268 layout(${block_layout})
1269 % endif
1270 uniform ${block_name} {
1271 // base base align padded row- array matrix
1272 // align off. off. size major stride stride
1273 % for m in iterate_all_block_members(fields, field_layouts, block_name, instance_name, packing, block_row_major_default(global_layout, block_layout)):
1274 ${pretty_format_member(m, packing)}
1275 % endfor
1276 } ${instance_name};
1277 % endfor
1279 flat out int vertex_pass;
1280 in vec4 piglit_vertex;
1282 #if defined(GL_ARB_shader_bit_encoding) || defined(GL_ARB_gpu_shader5) || __VERSION__ >= 430
1283 bool float_match(float u, float f, uint bits) { return floatBitsToUint(u) == bits; }
1284 #else
1285 bool float_match(float u, float f, uint bits) { return u == f; }
1286 #endif
1287 % if glsl_version >= 400 or "GL_ARB_gpu_shader_fp64" in extensions:
1289 bool double_match(double u, uvec2 bits) { return unpackDouble2x32(u) == bits; }
1290 %endif
1292 void main()
1294 /* std140 (or shared) layout prevents any fields or blocks from being
1295 * eliminated. Section 2.11.6 of the OpenGL ES 3.0 spec makes this
1296 * explicit, but desktop GL specs only imply it.
1298 bool pass = true;
1300 % for i in range(len(checkers)):
1301 % if i % 5 == 0:
1302 if (${checkers[i]})
1303 pass = false;
1304 % endif
1305 % endfor
1307 vertex_pass = int(pass);
1308 gl_Position = piglit_vertex;
1311 [fragment shader]
1312 precision highp float;
1314 out vec4 piglit_fragcolor;
1315 flat in int vertex_pass;
1317 void main()
1319 piglit_fragcolor = bool(vertex_pass) ? vec4(0, 1, 0, 1) : vec4(1, 0, 0, 1);
1322 [test]
1323 link success
1324 % for (name, type, size, offset, astride, mstride, row_major) in test_vectors:
1326 active uniform ${name} GL_UNIFORM_TYPE ${type}
1327 active uniform ${name} GL_UNIFORM_SIZE ${size}
1328 % if packing.fixed_offsets():
1329 active uniform ${name} GL_UNIFORM_OFFSET ${offset}
1330 active uniform ${name} GL_UNIFORM_ARRAY_STRIDE ${astride}
1331 active uniform ${name} GL_UNIFORM_MATRIX_STRIDE ${mstride}
1332 % endif
1333 active uniform ${name} GL_UNIFORM_IS_ROW_MAJOR ${row_major}
1334 % endfor
1336 % for (type, name, data) in setters:
1337 uniform ${type} ${name} ${data}
1338 % endfor
1340 draw rect -1 -1 2 2
1341 probe all rgba 0.0 1.0 0.0 1.0"""))
1343 return t.render(glsl_version=glsl_version,
1344 extensions=extensions,
1345 structures=structures,
1346 test_vectors=test_vectors,
1347 uniform_blocks=blocks,
1348 packing=packing,
1349 iterate_all_block_members=iterate_all_block_members,
1350 pretty_format_member=pretty_format_member,
1351 block_row_major_default=block_row_major_default,
1352 struct_types=struct_types,
1353 checkers=checkers,
1354 setters=setters)
1357 def generate_file_name(requirements, packing):
1358 """Based on the required UBO elements and the packing, generate a
1359 plausible file name for the test case.
1361 prefix = packing.layout_string() + "-"
1362 suffix = ".shader_test"
1364 body = "-and-".join(["-".join(req) for req in requirements])
1366 return prefix + body + suffix
1369 class packing_rules(object):
1370 __metaclass__ = abc.ABCMeta
1372 @abc.abstractproperty
1373 def layout_string(self):
1374 """Get the string used in a layout qualifier to select this set of
1375 layout rules.
1378 @abc.abstractproperty
1379 def fixed_offsets(self):
1380 """Return true if fields in this layout have fixed locations (e.g.,
1381 std140) or false if they can vary among implementations (e.g., shared
1382 or packed)?
1385 @abc.abstractmethod
1386 def base_alignment(self, type, row_major):
1387 """Determine the base alignment, in bytes, of the named type"""
1389 @abc.abstractmethod
1390 def matrix_stride(self, type, row_major):
1391 """Determine the stride, in bytes, from one indexable vector of the
1392 matrix (column or row depending on the orientation) to the next.
1395 @abc.abstractmethod
1396 def array_stride(self, type, row_major):
1397 """Determine the stride, in bytes, from one array element to the next.
1398 If the type is not an array type, zero is returned.
1401 def size(self, type, row_major):
1402 """Determine the size, in bytes, of the specified type.
1404 Applying the packing rules and the row-major setting, determine the
1405 size, in bytes, of the entire data type. This will include padded
1406 after the data element as required by the GLSL specification.
1408 if isarray(type):
1409 return self.array_stride(type, row_major) * arrays_of_arrays_size(type)
1411 if type in ["float", "bool", "int", "uint"]:
1412 return 4
1414 if type in ["double", "int64_t", "uint64_t"]:
1415 return 8
1417 if type in ["vec2", "bvec2", "ivec2", "uvec2"]:
1418 return 2 * 4
1420 if type in ["dvec2", "i64vec2", "u64vec2"]:
1421 return 2 * 8
1423 if type in ["vec3", "bvec3", "ivec3", "uvec3"]:
1424 return 3 * 4
1426 if type in ["dvec3", "i64vec3", "u64vec3"]:
1427 return 3 * 8
1429 if type in ["vec4", "bvec4", "ivec4", "uvec4"]:
1430 return 4 * 4
1432 if type in ["dvec4", "i64vec4", "u64vec4"]:
1433 return 4 * 8
1435 if "mat" in type:
1436 c, r = matrix_dimensions(type)
1437 if not row_major:
1438 return c * self.matrix_stride(type, row_major)
1439 else:
1440 return r * self.matrix_stride(type, row_major)
1442 if type not in struct_types:
1443 raise Exception("Unknown type {}".format(type))
1445 s = 0
1446 fields = struct_types[type]
1447 for (t, n) in fields:
1448 a = self.base_alignment(t, row_major)
1450 s = align(s, a) + self.size(t, row_major)
1452 s = align(s, self.base_alignment(type, row_major))
1453 return s
1456 class std140_packing_rules(packing_rules):
1457 def layout_string(self):
1458 return "std140"
1460 def fixed_offsets(self):
1461 return True
1463 def base_alignment(self, type, row_major):
1464 # (4) If the member is an array of scalars or vectors, the base
1465 # alignment and array stride are set to match the base alignment
1466 # of a single array element, according to rules (1), (2), and (3),
1467 # and rounded up to the base alignment of a vec4. The array may
1468 # have padding at the end; the base offset of the member following
1469 # the array is rounded up to the next multiple of the base
1470 # alignment.
1472 if isarray(type):
1473 return max(16,
1474 self.base_alignment(array_base_type(type), row_major))
1476 # (1) If the member is a scalar consuming <N> basic machine units, the
1477 # base alignment is <N>.
1479 if isscalar(type):
1480 return basic_machine_units(type)
1482 if isvector(type):
1483 # (2) If the member is a two- or four-component vector with
1484 # components consuming <N> basic machine units, the base
1485 # alignment is 2<N> or 4<N>, respectively.
1487 # (3) If the member is a three-component vector with components
1488 # consuming <N> basic machine units, the base alignment is
1489 # 4<N>.
1491 components = vector_size(type)
1492 if components == 2 or components == 4:
1493 return components * basic_machine_units(vector_base_type(type))
1494 elif components == 3:
1495 return 4 * basic_machine_units(vector_base_type(type))
1497 raise Exception("Invalid vector size {} for type {}".format(
1498 components,
1499 type))
1500 elif ismatrix(type):
1501 return self.matrix_stride(type, row_major)
1503 if type not in struct_types:
1504 raise Exception("Unknown type {}".format(type))
1506 # (9) If the member is a structure, the base alignment of the
1507 # structure is <N>, where <N> is the largest base alignment value
1508 # of any of its members, and rounded up to the base alignment of a
1509 # vec4. The individual members of this sub-structure are then
1510 # assigned offsets by applying this set of rules recursively,
1511 # where the base offset of the first member of the sub-structure
1512 # is equal to the aligned offset of the structure. The structure
1513 # may have padding at the end; the base offset of the member
1514 # following the sub-structure is rounded up to the next multiple
1515 # of the base alignment of the structure.
1517 a = 16
1518 fields = struct_types[type]
1519 for (field_type, field_name) in fields:
1520 a = max(a, self.base_alignment(field_type, row_major))
1522 return a
1524 def matrix_stride(self, type, row_major):
1525 c, r = matrix_dimensions(type)
1526 if not row_major:
1527 # (4) If the member is an array of scalars or vectors, the base
1528 # alignment and array stride are set to match the base
1529 # alignment of a single array element, according to rules (1),
1530 # (2), and (3), and rounded up to the base alignment of a
1531 # vec4. The array may have padding at the end; the base offset
1532 # of the member following the array is rounded up to the next
1533 # multiple of the base alignment.
1535 # (5) If the member is a column-major matrix with <C> columns and
1536 # <R> rows, the matrix is stored identically to an array of
1537 # <C> column vectors with <R> components each, according to
1538 # rule (4).
1540 if type[0] == 'd':
1541 return max(16, self.base_alignment("dvec{}".format(r), False))
1542 else:
1543 return max(16, self.base_alignment("vec{}".format(r), False))
1544 else:
1545 # (7) If the member is a row-major matrix with <C> columns and <R>
1546 # rows, the matrix is stored identically to an array of <R>
1547 # row vectors with <C> components each, according to rule (4).
1549 if type[0] == 'd':
1550 return max(16, self.base_alignment("dvec{}".format(c), False))
1551 else:
1552 return max(16, self.base_alignment("vec{}".format(c), False))
1554 def array_stride(self, type, row_major):
1555 base_type = without_array(type)
1557 if not isstructure(base_type):
1558 # (4) If the member is an array of scalars or vectors, the base
1559 # alignment and array stride are set to match the base
1560 # alignment of a single array element, according to rules (1),
1561 # (2), and (3), and rounded up to the base alignment of a
1562 # vec4. The array may have padding at the end; the base offset
1563 # of the member following the array is rounded up to the next
1564 # multiple of the base alignment.
1565 return max(16,
1566 max(self.base_alignment(base_type, row_major),
1567 self.size(base_type, row_major)))
1568 else:
1569 # (9) If the member is a structure, the base alignment of the
1570 # structure is <N>, where <N> is the largest base alignment
1571 # value of any of its members, and rounded up to the base
1572 # alignment of a vec4. The individual members of this
1573 # sub-structure are then assigned offsets by applying this set
1574 # of rules recursively, where the base offset of the first
1575 # member of the sub-structure is equal to the aligned offset
1576 # of the structure. The structure may have padding at the end;
1577 # the base offset of the member following the sub-structure is
1578 # rounded up to the next multiple of the base alignment of the
1579 # structure.
1581 # (10) If the member is an array of <S> structures, the <S> elements
1582 # of the array are laid out in order, according to rule (9).
1584 return align(self.size(base_type, row_major),
1585 self.base_alignment(base_type, row_major))
1588 class shared_packing_rules(std140_packing_rules):
1589 def layout_string(self):
1590 return "shared"
1592 def fixed_offsets(self):
1593 return False
1596 class unique_name_dict:
1597 """Helper class to generate a unique name for each field.
1599 Fields for each particular type have names based on the type. Each name
1600 is suffixed by a number, and the number is incremented each time a field
1601 of that type is created. For example, the first int field will be named
1602 "i1", and the second will be named "i2".
1605 def __init__(self):
1606 self.names = {}
1608 def trim_name(self, type):
1609 """Internal method to reduce a type name to a canonical form
1611 These names are used to track the type in the self.names dict.
1613 Array types have the arrayness stripped. Vector types have vector
1614 count stripped. Matrix types are converted to canonical "mat#x#"
1615 form. All other type names are unmodified.
1617 if isarray(type):
1618 t = without_array(type)
1619 else:
1620 t = type
1622 if ismatrix(t):
1623 # Canonicalize matrix type names.
1624 c, r = matrix_dimensions(t)
1626 name = "mat{}x{}".format(c, r)
1627 if t[0] == "d":
1628 name = "d" + name
1630 return name
1631 elif isscalar(t):
1632 return t
1633 elif isvector:
1634 return t.strip("1234")
1635 else:
1636 # Assume it must be a structure.
1637 return t
1639 def add_type(self, type):
1640 """Internal method to add a previously unknown type to the dictionary
1642 type -- Actual GLSL type name
1644 Generates the base name for fields of this type. Adds a tuple to dict
1645 (indexed by "type") of (base_name, 1).
1647 if isarray(type):
1648 t = without_array(type)
1649 else:
1650 t = type
1652 if isvector(t):
1653 base = "{}v".format(vector_base_type(t)[0])
1654 elif ismatrix(t):
1655 c, r = matrix_dimensions(t)
1657 if t[0] == 'd':
1658 base = "dm{}{}_".format(c, r)
1659 else:
1660 base = "m{}{}_".format(c, r)
1661 elif isscalar(t):
1662 base = t[0]
1663 elif t[0] == "S":
1664 base = "s{}_".format(t[1:])
1665 else:
1666 raise Exception("Malformed type name {}".format(t))
1668 self.names[self.trim_name(t)] = (base, 1)
1669 return
1671 def get_name(self, type):
1672 """Return a unique name for a field of the specified type."""
1673 t = self.trim_name(type)
1674 if t not in self.names:
1675 self.add_type(type)
1677 base, count = self.names[t]
1678 self.names[t] = (base, count + 1)
1680 return "{}{}".format(base, count)
1683 class block_member(object):
1684 """Helper class to track all of the layout information for a single
1685 (sub-)member of a uniform block."""
1687 TYPE_ENUM = {
1688 'float': "GL_FLOAT",
1689 'vec2': "GL_FLOAT_VEC2",
1690 'vec3': "GL_FLOAT_VEC3",
1691 'vec4': "GL_FLOAT_VEC4",
1693 'double': "GL_DOUBLE",
1694 'dvec2': "GL_DOUBLE_VEC2",
1695 'dvec3': "GL_DOUBLE_VEC3",
1696 'dvec4': "GL_DOUBLE_VEC4",
1698 'int': "GL_INT",
1699 'ivec2': "GL_INT_VEC2",
1700 'ivec3': "GL_INT_VEC3",
1701 'ivec4': "GL_INT_VEC4",
1703 'int64_t': "GL_INT64_ARB",
1704 'i64vec2': "GL_INT64_VEC2_ARB",
1705 'i64vec3': "GL_INT64_VEC3_ARB",
1706 'i64vec4': "GL_INT64_VEC4_ARB",
1708 'uint': "GL_UNSIGNED_INT",
1709 'uvec2': "GL_UNSIGNED_INT_VEC2",
1710 'uvec3': "GL_UNSIGNED_INT_VEC3",
1711 'uvec4': "GL_UNSIGNED_INT_VEC4",
1713 'uint64_t': "GL_UNSIGNED_INT64_ARB",
1714 'u64vec2': "GL_UNSIGNED_INT64_VEC2_ARB",
1715 'u64vec3': "GL_UNSIGNED_INT64_VEC3_ARB",
1716 'u64vec4': "GL_UNSIGNED_INT64_VEC4_ARB",
1718 'bool': "GL_BOOL",
1719 'bvec2': "GL_BOOL_VEC2",
1720 'bvec3': "GL_BOOL_VEC3",
1721 'bvec4': "GL_BOOL_VEC4",
1723 'mat2': "GL_FLOAT_MAT2",
1724 'mat2x2': "GL_FLOAT_MAT2",
1725 'mat2x3': "GL_FLOAT_MAT2x3",
1726 'mat2x4': "GL_FLOAT_MAT2x4",
1728 'mat3': "GL_FLOAT_MAT3",
1729 'mat3x2': "GL_FLOAT_MAT3x2",
1730 'mat3x3': "GL_FLOAT_MAT3",
1731 'mat3x4': "GL_FLOAT_MAT3x4",
1733 'mat4': "GL_FLOAT_MAT4",
1734 'mat4x2': "GL_FLOAT_MAT4x2",
1735 'mat4x3': "GL_FLOAT_MAT4x3",
1736 'mat4x4': "GL_FLOAT_MAT4",
1738 'dmat2': "GL_DOUBLE_MAT2",
1739 'dmat2x2': "GL_DOUBLE_MAT2",
1740 'dmat2x3': "GL_DOUBLE_MAT2x3",
1741 'dmat2x4': "GL_DOUBLE_MAT2x4",
1743 'dmat3': "GL_DOUBLE_MAT3",
1744 'dmat3x2': "GL_DOUBLE_MAT3x2",
1745 'dmat3x3': "GL_DOUBLE_MAT3",
1746 'dmat3x4': "GL_DOUBLE_MAT3x4",
1748 'dmat4': "GL_DOUBLE_MAT4",
1749 'dmat4x2': "GL_DOUBLE_MAT4x2",
1750 'dmat4x3': "GL_DOUBLE_MAT4x3",
1751 'dmat4x4': "GL_DOUBLE_MAT4"
1754 def __init__(self,
1755 GLSL_name,
1756 API_name,
1757 GLSL_type,
1758 explicit_layout,
1759 offset,
1760 row_major):
1761 self.GLSL_name = GLSL_name
1762 self.GLSL_type = GLSL_type
1764 self.API_name = API_name
1766 self.explicit_layout = explicit_layout
1767 self.offset = offset
1768 self.row_major = row_major
1770 if isarray(GLSL_type):
1771 base_type = without_array(GLSL_type)
1772 if isstructure(base_type):
1773 self.API_type = None
1774 else:
1775 self.API_type = self.TYPE_ENUM[base_type];
1777 self.size = array_elements(GLSL_type)
1778 elif isstructure(GLSL_type):
1779 self.API_type = None
1780 self.size = 1
1781 else:
1782 self.API_type = self.TYPE_ENUM[GLSL_type];
1783 self.size = 1
1785 def struct_nesting(self):
1786 if "." in self.GLSL_name:
1787 # If the block has an instance name, the API name will use the
1788 # block name instead of the instance name. As a result,
1789 # GLSL_name and API_name will be different.
1791 # The first "." is for the block instance name, so it does not count
1792 # as structure nesting.
1794 if self.GLSL_name != self.API_name:
1795 return collections.Counter(self.GLSL_name)["."] - 1
1796 else:
1797 return collections.Counter(self.GLSL_name)["."]
1798 else:
1799 return 0
1802 if __name__ == "__main__":
1803 if len(sys.argv) > 1:
1804 max_glsl_version = int(sys.argv[1])
1805 else:
1806 max_glsl_version = 130
1808 if len(sys.argv) > 2:
1809 extensions = sys.argv[2:]
1810 else:
1811 extensions = []
1813 # Pick a random GLSL version from the available set of possible versions.
1814 glsl_version = random.choice([v for v in [130, 140, 150, 400, 430]
1815 if v <= max_glsl_version])
1817 # Use the GLSL version filter out some extensions that are redundant.
1818 if glsl_version >= 140 and "GL_ARB_uniform_buffer_object" in extensions:
1819 extensions.remove("GL_ARB_uniform_buffer_object")
1821 if glsl_version >= 400 and "GL_ARB_gpu_shader_fp64" in extensions:
1822 extensions.remove("GL_ARB_gpu_shader_fp64")
1824 if glsl_version >= 430 and "GL_ARB_arrays_of_arrays" in extensions:
1825 extensions.remove("GL_ARB_arrays_of_arrays")
1827 # Pick a random subset of the remaining extensions.
1828 num_ext = len(extensions)
1829 if num_ext > 0:
1830 random.shuffle(extensions)
1831 r = random.randint(0, num_ext)
1832 extensions = extensions[:r]
1834 # Based on the GLSL version and the set of extensions, pick the set of
1835 # possible data types.
1836 if glsl_version < 400:
1837 types = ALL130_TYPES
1838 else:
1839 types = ALL400_TYPES
1841 if "GL_ARB_gpu_shader_fp64" in extensions:
1842 types.extend(DOUBLE_TYPES)
1844 # Based on the GLSL version, pick a set of packing rules
1845 # FINISHME: Add support for std430_packing_rules() soon.
1846 packing = random.choice([std140_packing_rules(), shared_packing_rules()])
1848 # Based on the GLSL version and the set of available extensions, pick
1849 # some required combinations of data structures to include in the UBO.
1850 arrays_of_arrays = (glsl_version >= 430 or
1851 "GL_ARB_arrays_of_arrays" in extensions)
1853 allow_row_major_structure = glsl_version >= 150
1855 requirements = []
1856 for i in [1, 2]:
1857 x = [random.choice(["array", "struct"])]
1859 for j in [1, 2, 3]:
1860 # If arrays-of-arrays are not supported, don't allow "array" to be
1861 # picked twice in a row.
1863 if x[-1] == "array" and not arrays_of_arrays:
1864 x.append("struct")
1865 else:
1866 x.append(random.choice(["array", "struct"]))
1868 if "struct" in x and allow_row_major_structure:
1869 ordering = random.choice([None,
1870 None,
1871 None,
1872 None,
1873 "column_major",
1874 "#column_major",
1875 "row_major",
1876 "row_major"])
1877 if ordering:
1878 x = [ordering] + x
1880 requirements.append(x)
1882 if glsl_version < 140:
1883 extensions.append("GL_ARB_uniform_buffer_object")
1885 # Generate the test!
1886 fields, required_layouts = generate_ubo(requirements, types)
1888 layouts = generate_layouts(
1889 fields,
1890 required_layouts,
1891 allow_row_major_structure)
1893 blocks = generate_block_list(
1894 glsl_version,
1895 packing,
1896 fields,
1897 layouts)
1899 print(emit_shader_test(
1900 blocks,
1901 packing,
1902 glsl_version,
1903 extensions))