summary/html: escape html
[piglit.git] / generated_tests / random_ubo.py
blob042b8b7a7db9ac00faf2b7f2cea4746010c4dc9f
1 #!/usr/bin/env python2
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 from __future__ import print_function
25 import random
26 import abc
27 import collections
28 import struct
29 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 ALL400_TYPES = ALL130_TYPES + DOUBLE_TYPES
58 # All known types, including the redundant NxN matrix types.
59 ALL_TYPES = [ "mat2x2", "mat3x3", "mat4x4",
60 "dmat2x2", "dmat3x3", "dmat4x4"] + ALL400_TYPES
62 def align(offset, alignment):
63 return ((offset + alignment - 1) / alignment) * alignment
66 def isscalar(type):
67 """Return true if the type is a known scalar type from any GLSL version."""
68 return type in ["float", "bool", "int", "uint", "double"]
71 def isvector(type):
72 """Return true if the type is a known vector type from any GLSL version."""
73 return type in ["vec2", "vec3", "vec4",
74 "ivec2", "ivec3", "ivec4",
75 "uvec2", "uvec3", "uvec4",
76 "bvec2", "bvec3", "bvec4",
77 "dvec2", "dvec3", "dvec4"]
80 def ismatrix(type):
81 """Return true if the type is a known matrix type from any GLSL version."""
82 return type in ["mat2", "mat3", "mat4",
83 "mat2x2", "mat2x3", "mat2x4",
84 "mat3x2", "mat3x3", "mat3x4",
85 "mat4x2", "mat4x3", "mat4x4",
86 "dmat2", "dmat3", "dmat4",
87 "dmat2x2", "dmat2x3", "dmat2x4",
88 "dmat3x2", "dmat3x3", "dmat3x4",
89 "dmat4x2", "dmat4x3", "dmat4x4"]
92 def isarray(type):
93 """Return true if the type name appears to be an array type."""
94 return "[" in type
97 def isstructure(type):
98 """Return true if the type name appears to be a structure type.
100 This function works by process of elimination. If the named type is not a
101 scalar, vector, matrix, or array, then it must be a structure.
103 NOTE: If the type is an array-of-structure type, this function will return
104 false.
106 return not (isscalar(type) or isvector(type) or ismatrix(type) or
107 isarray(type))
110 def vector_size(type):
111 """Return the number of elements in a vector type."""
112 if isvector(type):
113 return int(type[-1:])
115 raise Exception("Non-vector type {}".format(type))
118 def matrix_dimensions(type):
119 """Return the dimensions of an array type.
121 The tuple returned is (columns, rows).
123 if not ismatrix(type):
124 raise Exception("Non-matrix type {}".format(type))
126 if "x" in type:
127 s = type[-3:].split("x")
128 return int(s[0]), int(s[1])
129 else:
130 d = int(type[-1:])
131 return d, d
134 def array_elements(type):
135 """Return the number of elements in an array type.
137 For non-array types zero is returned.
139 if "[" not in type:
140 return 0
142 # Is there a better way to do this?
143 return int(type.split("[")[1].split("]")[0])
145 def basic_machine_units(type):
146 """Return the size in 'basic machine units' of a scalar type."""
147 if type in ["float", "bool", "int", "uint"]:
148 return 4
150 if type == "double":
151 return 8
153 raise Exception("Non-scalar type {}".format(type))
156 def array_base_type(type):
157 """Return the type of an element from an array type."""
158 if not isarray(type):
159 raise Exception("Non-array type {}".format(type))
161 return type[:type.index("[")] + type[type.index("]")+1:]
163 def without_array(type):
164 """Return the type of an element with all arrays removed."""
165 if not isarray(type):
166 raise Exception("Non-array type {}".format(type))
168 return type.split("[")[0]
170 def arrays_of_arrays_size(type):
171 """Return the total number of elements in an array of arrays."""
172 if not isarray(type):
173 raise Exception("Non-array type {}".format(type))
175 size = 1
176 base_type = type
177 while (isarray(base_type)):
178 size = size * array_elements(base_type)
179 base_type = array_base_type(base_type)
181 return size
183 def vector_base_type(type):
184 """Return the type of an element from a vector."""
185 if not isvector(type):
186 raise Exception("Non-vector type {}".format(type))
188 if type[0] == 'v':
189 return "float"
190 elif type[0] == 'i':
191 return "int"
192 elif type[0] == 'u':
193 return "uint"
194 elif type[0] == 'b':
195 return "bool"
196 elif type[0] == 'd':
197 return "double"
198 else:
199 raise Exception("Unknown vector type {}".format(type))
202 def iterate_structures(fields, types_seen=[], types_yielded=[]):
203 """Given a list of fields, yields the structures in the fields in proper
204 declaration order. Detects recurrsion in the types and raises an
205 exception.
207 for (type, name) in fields:
208 if isarray(type):
209 type = without_array(type)
211 if not isstructure(type):
212 continue
214 if type in types_seen:
215 raise Exception("Type recurrsion involving {}".format(type))
217 for t in iterate_structures(struct_types[type],
218 types_seen + [type],
219 types_yielded):
220 yield t
222 if type not in types_yielded:
223 types_yielded.append(type)
224 yield type
227 def select_basic_type(types, names):
228 """Return a random type with a matching field name.
230 From the list of supplied types, picks a random type. Using supplied
231 unique_name_dict, a name is also chosen. The two are returned as a tuple.
233 t = random.choice(types)
234 return t, names.get_name(t)
237 def generate_struct_of_basic_types(types, names):
238 """Return a sequence of random types with unique field names."""
239 return [select_basic_type(types, names)
240 for i in xrange(0, random.randint(1,12))]
243 def generate_member_from_description(description, builtin_types, names):
244 """Generate a single block member for a list of required attributes.
246 The list of required attributes is a sequence of 'struct' and 'array'
247 perhaps terminated with the name of a GLSL basic type. In addition to any
248 required subfields, structures generated in the sequence will be populated
249 with a random selection of available GLSL types named in builtin_types.
251 A matrix orientation can also be listed as the first requirement.
252 However, that is not handled by this function, and it will be ignored.
254 The tuple returned is (member_type, member_name).
256 if len(description) == 0:
257 return select_basic_type(builtin_types, names)
259 item = description[0]
260 if item == "array":
261 base_type, name = generate_member_from_description(
262 description[1:],
263 builtin_types,
264 names)
266 # If we're making an array of something that can be "big," try to make
267 # the array a little smaller.
269 if ismatrix(base_type) or isarray(base_type) or isstructure(base_type):
270 size = random.choice([2, 3, 5, 7])
271 else:
272 size = random.choice([3, 5, 7, 11, 13])
274 t = "{}[{}]".format(base_type, size)
275 return t, name
276 elif item == "struct":
277 fields = generate_struct_of_basic_types(builtin_types, names)
278 random.shuffle(fields)
280 # Peek ahead. If the next item in the description is a built-in type,
281 # then all of the remaining items must be built-in types. Generate a
282 # list of these.
284 if len(description) > 1 and description[1] in ALL_TYPES:
285 required_fields = [generate_member_from_description([i],
286 builtin_types,
287 names)
288 for i in description[1:]]
290 else:
291 required_fields = [generate_member_from_description(
292 description[1:],
293 builtin_types,
294 names)]
296 # Pick a random spot in the list of "common" fields and insert all of
297 # the required fields there.
299 j = random.randint(0, len(fields))
300 f = fields[:j] + required_fields + fields[j:]
302 struct_name = "S{}".format(len(struct_types) + 1)
303 struct_types[struct_name] = f
305 field_name = names.get_name(struct_name)
306 return struct_name, field_name
307 elif item in ALL_TYPES:
308 return item, names.get_name(item)
309 elif item in ["row_major", "column_major", "#column_major"]:
310 # While "row_major" and "column_major" are valid requirements, they
311 # are not processed here. Just skip over them for now.
312 return generate_member_from_description(description[1:],
313 builtin_types,
314 names)
316 raise Exception("Invalid UBO member description {}".format(item))
319 def generate_ubo(description_list, builtin_types):
320 """Generate a uniform block for a list of requirements.
322 Each member of description_list is taken to be a sequence of requirements
323 for a single field in the uniform block. These are processed by
324 generate_member_from_description.
326 In addition to the list of required fields, the uniform block is also
327 populated with a random selection of available GLSL types named in
328 builtin_types.
330 layouts = dict()
331 names = unique_name_dict()
333 fields = []
335 for desc in description_list:
336 m = generate_member_from_description(desc, builtin_types, names)
337 fields.append(m)
339 if desc[0] in ["row_major", "column_major", "#column_major"]:
340 layouts[m[1]] = desc[0]
342 fields.extend(generate_struct_of_basic_types(builtin_types, names))
343 random.shuffle(fields)
345 required_layouts = []
346 for (field_type, field_name) in fields:
347 if field_name in layouts:
348 required_layouts.append(layouts[field_name])
349 else:
350 required_layouts.append(None)
352 return fields, required_layouts
355 def generate_layouts(fields, required_layouts, allow_row_major_structure):
356 """Generate a directed random sequence of layout qualifiers.
358 Elements in requred_layouts that are non-None will have the same value in
359 the final sequence. Remaining elements matching entries in fields that
360 are either structure or matrix types will have random layouts assigned.
362 If allow_row_major_structure is not set, only matrix types will have
363 random layout assignments. Explicit layouts in required_layouts are
364 unaffected.
366 if required_layouts is None:
367 required_layouts = [None] * len(fields)
369 layouts = []
370 for ((type, name), lay) in zip(fields, required_layouts):
371 if isarray(type):
372 type = without_array(type)
374 if lay:
375 layouts.append(lay)
376 elif isstructure(type) and not allow_row_major_structure:
377 # This would work-around a bug in NVIDIA closed source drivers.
378 # They do not propagate row-major down into structures.
380 layouts.append("#column_major")
381 elif ismatrix(type) or isstructure(type):
382 # Choose a random matrix orientation. The #column_major are
383 # ignored when the UBO is emitted, but when a the UBO is
384 # re-emitted with a default row-major layout, these become
385 # "column_major".
387 layouts.append(random.choice(["#column_major",
388 "#column_major",
389 "#column_major",
390 "row_major",
391 "row_major",
392 "column_major"]))
393 else:
394 layouts.append("")
395 return layouts
398 def relayout_for_default_row_major(l):
399 """Return a new layout for an assumed default layout of row-major."""
400 if l == "row_major":
401 return "#row_major"
402 elif l == "column_major" or l == "#column_major":
403 return "column_major"
404 elif l == "":
405 return ""
406 else:
407 raise Exception("Invalid layout {}".format(l))
410 def fields_to_glsl_struct(type):
411 """From a name structure type, generate a GLSL definition of that
412 structure.
414 # The longest type name will have the form 'dmatCxR[##]' for 11
415 # characters. Use this to set the spacing between the field type and the
416 # field name.
418 structure_template = Template(dedent("""\
419 struct ${struct_name} {
420 % for (field_type, field_name) in fields:
421 ${"{:<11}".format(field_type)} ${field_name};
422 % endfor
424 """))
426 return structure_template.render(struct_name=type, fields=struct_types[type])
428 def iterate_struct_array_recursive(field_type,
429 name_from_API,
430 name_from_shader,
431 packing,
432 offset,
433 row_major,
434 field_row_major,
435 explicit_layout):
437 astride = packing.array_stride(field_type, field_row_major)
438 array_member_align = packing.base_alignment(field_type, field_row_major)
440 element_t = array_base_type(field_type)
442 for i in xrange(array_elements(field_type)):
443 name_from_API_with_index = "{}[{}]".format(name_from_API, i)
444 name_from_shader_with_index = "{}[{}]".format(name_from_shader, i)
446 if isarray(element_t):
447 inner_aoa_size = arrays_of_arrays_size(element_t)
448 o = align(offset, array_member_align) + (astride * i * inner_aoa_size)
450 for x in iterate_struct_array_recursive(element_t,
451 name_from_API_with_index,
452 name_from_shader_with_index,
453 packing,
455 row_major,
456 field_row_major,
457 explicit_layout):
458 yield x
460 a = packing.base_alignment(x.GLSL_type, row_major)
461 o = align(o, a) + packing.size(x.GLSL_type, row_major)
462 else:
463 o = align(offset, array_member_align) + (astride * i)
464 yield block_member(
465 name_from_shader_with_index,
466 name_from_API_with_index,
467 element_t,
468 explicit_layout,
470 field_row_major)
471 for x in iterate_all_recursive(struct_types[element_t],
472 None,
473 name_from_API_with_index,
474 name_from_shader_with_index,
475 packing,
477 field_row_major):
478 yield x
480 a = packing.base_alignment(x.GLSL_type, row_major)
481 o = align(o, a) + packing.size(x.GLSL_type, row_major)
483 def iterate_all_recursive(fields,
484 field_layouts,
485 name_from_API_base,
486 name_from_shader_base,
487 packing,
488 offset,
489 row_major):
490 """In-order recursive iteration of all subfields of a structure type
492 fields -- List of fields in the uniform block or structure
493 field_layouts -- Layout for each field in the uniform block (None for
494 structures).
495 name_from_API_base -- Base name of the member as it would be accessed via
496 the GL API.
497 name_from_shader_base -- Base name of the member as it would be accessed via
498 the GLSL shader.
499 packing -- Packing rules used to layout the type
500 offset -- Aligned base offset of the member
501 row_major -- True if the current matrix orientation is row-major
503 At each step of the iteration will yield a block_member object
504 representing the member.
506 Basic GLSL types will be visited once. Arrays of basic GLSL types will
507 also be visited once.
509 A structure will be visited once, then each field in the structure will be
510 visited.
512 An array of structures will be visited once, then each element of the
513 array will be visited. Since each element is a structure, each field will
514 be visited.
516 Consider the following structure:
518 struct S2 {
519 int i;
520 float f[2];
523 struct S1 {
524 S2 s[2];
527 If name_from_API_base is "x", the members would be visited in the
528 following order: "x.s", "x.s[0]", "x.s[0].i", "x.s[0].f[0]", "x.s[1]",
529 "x.s[1].i", "x.s[1].f[0]".
531 See also iterate_all_block_members.
533 if field_layouts is None:
534 field_layouts = [""] * len(fields)
536 if len(name_from_shader_base) > 0:
537 fmt = "{base}.{field}"
538 else:
539 fmt = "{field}"
541 for ((field_type, field_name), explicit_layout) in zip(fields,
542 field_layouts):
543 name_from_shader = fmt.format(
544 base=name_from_shader_base,
545 field=field_name)
546 name_from_API = fmt.format(
547 base=name_from_API_base,
548 field=field_name)
550 if explicit_layout == "row_major":
551 field_row_major = True
552 elif explicit_layout == "column_major":
553 field_row_major = False
554 else:
555 field_row_major = row_major
557 if isarray(field_type):
558 base_type = without_array(field_type)
560 if isstructure(base_type):
561 yield block_member(
562 name_from_shader,
563 name_from_API,
564 field_type,
565 explicit_layout,
566 offset,
567 field_row_major)
569 for x in iterate_struct_array_recursive(field_type,
570 name_from_API,
571 name_from_shader,
572 packing,
573 offset,
574 row_major,
575 field_row_major,
576 explicit_layout):
577 yield x
579 elif ismatrix(base_type):
580 yield block_member(
581 name_from_shader,
582 name_from_API,
583 field_type,
584 explicit_layout,
585 offset,
586 field_row_major)
587 else:
588 yield block_member(
589 name_from_shader,
590 name_from_API,
591 field_type,
593 offset,
594 False)
595 elif isstructure(field_type):
596 yield block_member(
597 name_from_shader,
598 name_from_API,
599 field_type,
600 explicit_layout,
601 offset,
602 field_row_major)
604 a = packing.base_alignment(field_type, field_row_major)
606 for x in iterate_all_recursive(struct_types[field_type],
607 None,
608 name_from_API,
609 name_from_shader,
610 packing,
611 align(offset, a),
612 field_row_major):
613 yield x
615 elif ismatrix(field_type):
616 yield block_member(
617 name_from_shader,
618 name_from_API,
619 field_type,
620 explicit_layout,
621 offset,
622 field_row_major)
623 elif isvector(field_type) or isscalar(field_type):
624 yield block_member(
625 name_from_shader,
626 name_from_API,
627 field_type,
629 offset,
630 False)
631 else:
632 raise Exception("Malformed type name {}".format(field_type))
634 a = packing.base_alignment(field_type, field_row_major)
635 offset = align(offset, a) + packing.size(field_type, field_row_major)
638 def iterate_all_block_members(fields,
639 field_layouts,
640 block_name,
641 instance_name,
642 packing,
643 row_major):
644 """In-order recursive iteration of all subfields of a block
646 fields -- List of fields in the uniform block
647 field_layouts -- Layout for each field in the uniform block
648 block_name - Name of the uniform block
649 instance_name - Instance name associated with the block. May be None.
650 packing -- Packing rules used to layout the type
651 row_major -- True if the default block matrix orientation is row-major
653 At each step of the iteration will yield a block_member object
654 representing the member.
656 Basic GLSL types will be visited once. Arrays of basic GLSL types will
657 also be visited once.
659 A structure will be visited once, then each field in the structure will be
660 visited.
662 An array of structures will be visited once, then each element of the
663 array will be visited. Since each element is a structure, each field will
664 be visited.
666 Consider the following block:
668 struct S {
669 int i;
670 float f[2];
673 uniform U {
674 S s[2];
677 The members would be visited in the following order: s, s[0], s[0].i,
678 s[0].f[0], s[1], s[1].i, s[1].f[0].
680 for x in iterate_all_recursive(fields,
681 field_layouts,
682 block_name,
683 instance_name,
684 packing,
686 row_major):
687 yield x
690 def hash_string(string):
691 """The djb2 string hash algorithm from the old comp.lang.c days. Not a
692 terrific hash, but we just need a pseudorandom number based on the string.
693 This will do.
695 This is used instead of the built-in hash function so that the results
696 will be consistent on other systems. See
697 http://stackoverflow.com/questions/793761/built-in-python-hash-function.
699 h = 5381
701 for c in string:
702 h = h * 33 + ord(c)
704 return h & 0x0ffffffff
707 def random_data(type, name, offset):
708 """Generate pseudorandom data.
710 The data generated is based on the type, name of the field, and offset of
711 the member in the UBO.
713 if isscalar(type):
714 h = hash_string("{}@{}".format(offset, name))
716 if type == "int":
717 return str(h - 0x7fffffff)
718 elif type == "uint":
719 return str(h)
720 elif type == "bool":
721 return str(int((h & 8) == 0))
722 elif type == "float" or type == "double":
723 return str(float(h - 0x7fffffff) / 65535.0)
724 else:
725 raise Exception("Unknown scalar type {}".format(type))
727 if isvector(type):
728 scalar = vector_base_type(type)
730 x = [random_data(scalar, name, offset + (i * 3))
731 for i in xrange(vector_size(type))]
732 return " ".join(x)
734 if ismatrix(type):
735 r, c = matrix_dimensions(type)
737 x = [random_data("float", name, offset + (i * 7))
738 for i in xrange(r * c)]
739 return " ".join(x)
742 def generate_test_vectors(fields,
743 field_layouts,
744 block_name,
745 instance_name,
746 packing,
747 row_major):
748 test_vectors = []
750 for m in iterate_all_block_members(fields,
751 field_layouts,
752 block_name,
753 instance_name,
754 packing,
755 row_major):
756 a = packing.base_alignment(m.GLSL_type, m.row_major)
758 if isarray(m.GLSL_type):
759 size = array_elements(m.GLSL_type)
760 base_type = array_base_type(m.GLSL_type)
761 astride = packing.array_stride(m.GLSL_type, m.row_major)
762 name = m.API_name + "[0]"
763 while(isarray(base_type)):
764 size = array_elements(base_type)
765 base_type = array_base_type(base_type)
766 name = name + "[0]"
767 else:
768 base_type = m.GLSL_type
769 astride = 0
770 name = m.API_name
771 size = m.size
773 if ismatrix(base_type):
774 test_vectors.append((
775 name,
776 m.API_type,
777 size,
778 align(m.offset, a),
779 astride,
780 packing.matrix_stride(base_type, m.row_major),
781 int(m.row_major)))
782 elif isvector(base_type) or isscalar(base_type):
783 test_vectors.append((
784 name,
785 m.API_type,
786 size,
787 align(m.offset, a),
788 astride,
792 return test_vectors
795 def scalar_derp(type, name, data):
796 """Return a GLSL code string to compare a scalar with its expected value."""
797 if type == "bool":
798 if int(data) == 0:
799 return name
800 else:
801 return "!" + name
802 elif type == "uint":
803 return "{} != {}u".format(name, data)
804 elif type == "int":
805 return "{} != {}".format(name, data)
806 elif type == "float":
807 # Not all implementations support the bit-cast operators that are used
808 # to do bit-exact comparisons. For this reason float_match needs the
809 # float data and the bit-exact data.
811 bits = bit_exact_data(data, "float")
812 return "!float_match({}, {}, {}u)".format(name, data, bits)
813 elif type == "double":
814 bits = bit_exact_data(data, "double")
816 # 0xHHHHHHHHLLLLLLLL
817 # 012345678901234567
819 hi = "0x" + bits[2:10]
820 lo = "0x" + bits[10:18]
822 return "!double_match({}, uvec2({}, {}))".format(name, lo, hi)
823 else:
824 raise Exception("Unknown scalar type {}".format(type))
827 def vector_derp(type, name, data):
828 """Return a list of GLSL code strings that compare each field of a vector
829 its expected value.
831 scalar = vector_base_type(type)
832 components = ["x", "y", "z", "w"]
834 return [scalar_derp(scalar,
835 "{}.{}".format(name, "xyzw"[i]),
836 data[i])
837 for i in xrange(vector_size(type))]
840 def matrix_derp(type, name, data):
841 """Return a list of GLSL code strings that compare each field of a matrix
842 its expected value.
844 c, r = matrix_dimensions(type)
846 if type[0] == 'd':
847 column_type = "dvec{}".format(r)
848 else:
849 column_type = "vec{}".format(r)
851 data_pairs = []
853 for i in xrange(c):
854 data_pairs.extend(vector_derp(
855 column_type,
856 "{}[{}]".format(name, i),
857 data[(i * r):(i * r) + r]))
859 return data_pairs
862 def fudge_type_for_setter(type):
863 """Return the correct type for the GL API to set the uniform.
865 Most GLSL data types are set using a the enum name for the actual type.
866 The sole exception is bool and related vector types. For bool types, the
867 same-sized (scalar or vector) integer type is used.
869 if type[0] == 'b':
870 if type == "bool":
871 return "int"
872 else:
873 return "i" + type[1:]
874 else:
875 return type
878 def bit_exact_data(raw_data, type):
879 """Several places in the test want bit-exact data for all types.
880 For integer types, this is just the raw data. For floating point (both
881 single and double precission) types, the bit-exact data is the hex
882 representation of the IEEE 754 encoding.
884 if type in ["float", "vec2", "vec3", "vec4",
885 "mat2", "mat2x2", "mat2x3", "mat2x4",
886 "mat3", "mat3x2", "mat3x3", "mat3x4",
887 "mat4", "mat4x2", "mat4x3", "mat4x4"]:
888 exact_data = []
890 for d in raw_data.split(" "):
891 p = struct.pack('!f', float(d))
892 u = struct.unpack('!I', p)[0]
893 exact_data.append(hex(u))
895 return " ".join(exact_data)
896 elif type in ["double", "dvec2", "dvec3", "dvec4",
897 "dmat2", "dmat2x2", "dmat2x3", "dmat2x4",
898 "dmat3", "dmat3x2", "dmat3x3", "dmat3x4",
899 "dmat4", "dmat4x2", "dmat4x3", "dmat4x4"]:
900 exact_data = []
902 for d in raw_data.split(" "):
903 p = struct.pack('!d', float(d))
904 u = struct.unpack('!Q', p)[0]
906 # Sometimes the hex() generates a spurious "L" at the end of the
907 # string. Only take the first 18 characters to omit the unwanted
908 # "L". I believe this occurs when bit 63 is set.
910 exact_data.append(hex(u)[0:18])
912 return " ".join(exact_data)
913 else:
914 return raw_data
916 def generate_array_data_pairs(name, api_name, element_type, row_major, offset, packing, setters, checkers):
917 base_type = array_base_type(element_type)
919 astride = packing.array_stride(element_type, row_major)
921 for i in xrange(array_elements(element_type)):
923 name_with_index = "{}[{}]".format(name, i)
924 api_name_with_index = "{}[{}]".format(api_name, i)
926 if isarray(base_type):
927 offset = offset + (i * arrays_of_arrays_size(base_type) * astride)
928 generate_array_data_pairs(name_with_index, api_name_with_index, base_type, row_major, offset, packing, setters, checkers)
929 else:
930 offset = offset + (i * astride)
931 raw_data = random_data(base_type, name_with_index, offset)
932 setters.append(
933 (fudge_type_for_setter(base_type),
934 api_name_with_index,
935 bit_exact_data(raw_data, base_type)))
937 data = raw_data.split(" ")
939 if isscalar(base_type):
940 checkers.append(scalar_derp(base_type,
941 name_with_index,
942 data[0]))
943 elif isvector(base_type):
944 checkers.extend(vector_derp(base_type,
945 name_with_index,
946 data))
947 elif ismatrix(base_type):
948 checkers.extend(matrix_derp(base_type,
949 name_with_index,
950 data))
952 def generate_data_pairs(uniform_blocks, packing):
953 """Return GLSL code to test values and shader_runner code to set them.
955 For each element in each uniform block, two lists are generated, and these
956 lists are returned in a tuple of (checkers, setters). The "checkers" list
957 is a list of GLSL comparisons that return true if the contents of the
958 uniform block element DOES NOT match the expected value.
960 The "setters" list is a list of shader_runner "uniform" statements to set
961 each uniform block member to an expected value.
963 checkers = []
964 setters = []
966 for (block_name,
967 instance_name,
968 global_layout,
969 block_layout,
970 fields,
971 field_layouts) in uniform_blocks:
972 for m in iterate_all_block_members(
973 fields,
974 field_layouts,
975 block_name,
976 instance_name,
977 packing,
978 block_row_major_default(global_layout, block_layout)):
980 if m.API_type:
981 if isarray(m.GLSL_type):
982 generate_array_data_pairs(m.GLSL_name, m.API_name, m.GLSL_type, m.row_major, m.offset, packing, setters, checkers)
983 else:
984 raw_data = random_data(m.GLSL_type, m.GLSL_name, m.offset)
985 setters.append((fudge_type_for_setter(m.GLSL_type),
986 m.API_name,
987 bit_exact_data(raw_data, m.GLSL_type)))
989 data = raw_data.split(" ")
991 if isscalar(m.GLSL_type):
992 checkers.append(scalar_derp(m.GLSL_type,
993 m.GLSL_name,
994 data[0]))
995 elif isvector(m.GLSL_type):
996 checkers.extend(vector_derp(m.GLSL_type,
997 m.GLSL_name,
998 data))
999 elif ismatrix(m.GLSL_type):
1000 checkers.extend(matrix_derp(m.GLSL_type,
1001 m.GLSL_name,
1002 data))
1004 return checkers, setters
1007 def pretty_format_type_data(packing, type, offset, row_major):
1008 """Return a string describing the layout of the type
1010 This string is intended to be a comment embedded in the GLSL shader code
1011 that is generated.
1013 a = packing.base_alignment(type, row_major)
1014 aligned_offset = align(offset, a)
1015 size = packing.size(type, row_major)
1017 row_major_str = "-"
1018 mstride = "-"
1019 astride = "-"
1021 if isarray(type):
1022 astride = packing.array_stride(type, row_major)
1024 base_type = without_array(type)
1025 if ismatrix(base_type) and row_major:
1026 if row_major:
1027 row_major_str = "yes"
1028 else:
1029 row_major_str = "no"
1031 mstride = packing.matrix_stride(base_type, row_major)
1032 else:
1033 if ismatrix(type):
1034 if row_major:
1035 row_major_str = "yes"
1036 else:
1037 row_major_str = "no"
1039 mstride = packing.matrix_stride(type, row_major)
1041 return "{base_align:>3} {base_offset:>4} {aligned_offset:>5} {padded_size:>6} {row_major:^5} {array_stride:>6} {matrix_stride:>6}".format(
1042 base_align=a,
1043 base_offset=offset,
1044 aligned_offset=aligned_offset,
1045 padded_size=size,
1046 row_major=row_major_str,
1047 array_stride=astride,
1048 matrix_stride=mstride
1052 def pretty_format_member(m, packing):
1053 """Return a string of GLSL code to declare the member.
1055 m -- a block_member object
1056 packing -- packing rules
1058 If the member is "nested" inside a structure, the string returned will be
1059 a comment simply describing the layout of the submember.
1061 # If the name ends in an array subscript, emit a special line to note that
1062 # the following fields are the contents of an element of an array of
1063 # structures.
1064 if m.GLSL_name[-1] == "]":
1065 n = m.struct_nesting() + 1
1066 indent = "// " + (" " * n)
1068 return "{indent}{index}".format(indent=indent,
1069 index=m.GLSL_name[m.GLSL_name.index("["):])
1071 # Strip off everything before the last period.
1072 name = m.GLSL_name.split(".")[-1]
1074 n = m.struct_nesting()
1075 if n > 0:
1076 indent = "// " + (" " * n)
1077 field_str = "{indent}{type:<11} {name:<20}".format(
1078 indent=indent,
1079 type=m.GLSL_type,
1080 name=name)[0:31]
1081 else:
1082 field_str = " {type:<11}{name};{padding}// ".format(
1083 type=m.GLSL_type,
1084 name=name,
1085 padding=" "[len(name):])
1087 data_str = pretty_format_type_data(
1088 packing,
1089 m.GLSL_type,
1090 m.offset,
1091 m.row_major)
1093 # If there is an explicit layout for the member, prepend it to the member
1094 # declaration. This also means that the member must be contained directly
1095 # in the UBO (i.e., not nested in a struct), so no additional indentation
1096 # is necessary.
1098 if m.explicit_layout and "#" not in m.explicit_layout:
1099 return " layout({layout})\n{field}{data}".format(
1100 layout=m.explicit_layout,
1101 field=field_str,
1102 data=data_str)
1103 else:
1104 return "{field}{data}".format(field=field_str, data=data_str)
1107 def block_row_major_default(global_layout, block_layout):
1108 """Return true if the default matrix layout for the block is row-major."""
1109 row_major = global_layout is not None and "row_major" in global_layout
1111 if block_layout:
1112 if "row_major" in block_layout:
1113 row_major = True
1114 elif "column_major" in block_layout:
1115 # The block layout can override a previous global layout.
1116 row_major = False
1118 return row_major
1121 def generate_block_list(glsl_version, packing, ubo_fields, layouts):
1122 """Return list of uniform blocks to be passed to emit_shader_test.
1124 The supplied ubo_fields and layouts are reformatted as an element in a
1125 list of blocks that can be consumed by emit_shader_test. Depending on the
1126 value of glsl_version, additional blocks may be added to the list. The
1127 new blocks will have the same layout as the original, but the layout will
1128 be specified in different ways (e.g., by using a global layout qualifier).
1131 blocks = [("UB1", "", None, packing.layout_string(), ubo_fields, layouts)]
1133 # If the GLSL version is at least 1.50, UBO functionality is significantly
1134 # extended.
1136 # 1. Uniform blocks can have instance names. The existence of the name
1137 # changes the way the block is queried through the API (with the block
1138 # name) and the way it is accessed by the shader (with the instance
1139 # name).
1141 # 2. Uniform blocks can be grouped in arrays. UBO arrays must have an
1142 # instance name.
1144 # This is used to make the tests dramatically more complex. Each UBO is
1145 # emitted three times.
1147 # 1. Without an instance name.
1149 # 2. With an instance name and the per-block matrix layout switched to
1150 # row_major. The declared layout of the individual fields is modified
1151 # so that this block has the same layout as the previous block.
1153 # 3. With an instance name and an array size. The per-block matrix layout
1154 # is empty, but the global matrix layout is changed to row_major. This
1155 # block should have the same layout as the previous two.
1157 if glsl_version >= 150:
1158 inverted_layouts = [relayout_for_default_row_major(l) for l in layouts]
1160 blocks.append(("UB2",
1161 "ub2",
1162 None,
1163 packing.layout_string() + ", row_major",
1164 ubo_fields,
1165 inverted_layouts))
1167 blocks.append(("UB3",
1168 "ub3",
1169 # Disabled to work around Mesa bug #83508.
1170 # "ub3[2]",
1171 packing.layout_string() + ", row_major",
1172 None,
1173 ubo_fields,
1174 inverted_layouts))
1176 return blocks
1179 def emit_shader_test(blocks, packing, glsl_version, extensions):
1180 structures = []
1181 test_vectors = []
1183 for (block_name,
1184 instance_name,
1185 global_layout,
1186 block_layout,
1187 fields,
1188 field_layouts) in blocks:
1190 structures.extend([s for s in iterate_structures(fields)])
1192 test_vectors.extend(generate_test_vectors(
1193 fields,
1194 field_layouts,
1195 block_name,
1196 instance_name,
1197 packing,
1198 block_row_major_default(global_layout, block_layout)))
1201 checkers, setters = generate_data_pairs(blocks, packing)
1203 # If the GLSL version is at least 1.40, UBOs are already supported, and we
1204 # don't need to enable the extension.
1206 if glsl_version >= 140 and "GL_ARB_uniform_buffer_object" in extensions:
1207 extensions.remove("GL_ARB_uniform_buffer_object")
1209 t = Template(dedent("""\
1210 [require]
1211 GLSL >= ${glsl_version / 100}.${glsl_version % 100}
1212 % for ext in extensions:
1213 ${ext}
1214 % endfor
1216 # Do NOT edit the following lines.
1217 # GLSL ${glsl_version}
1218 # EXTENSIONS ${extensions}
1219 # PACKING ${packing.layout_string()}
1220 % for s in structures:
1221 # STRUCT ("${s}", ${struct_types[s]})
1222 % endfor
1223 % for b in uniform_blocks:
1224 # UBO ${b}
1225 % endfor
1226 # DATA END
1228 [vertex shader]
1229 % for ext in extensions:
1230 #extension ${ext}: require
1231 % endfor
1232 #extension GL_ARB_shader_bit_encoding: enable
1233 #extension GL_ARB_gpu_shader5: enable
1235 precision highp float;
1236 % for s in structures:
1238 struct ${s} {
1239 % for (field_type, field_name) in struct_types[s]:
1240 ${"{:<11}".format(field_type)} ${field_name};
1241 % endfor
1243 % endfor
1245 % for (block_name, instance_name, global_layout, block_layout, fields, field_layouts) in uniform_blocks:
1246 % if global_layout:
1247 layout(${global_layout}) uniform;
1249 % endif
1250 % if block_layout:
1251 layout(${block_layout})
1252 % endif
1253 uniform ${block_name} {
1254 // base base align padded row- array matrix
1255 // align off. off. size major stride stride
1256 % for m in iterate_all_block_members(fields, field_layouts, block_name, instance_name, packing, block_row_major_default(global_layout, block_layout)):
1257 ${pretty_format_member(m, packing)}
1258 % endfor
1259 } ${instance_name};
1260 % endfor
1262 flat out int vertex_pass;
1263 in vec4 piglit_vertex;
1265 #if defined(GL_ARB_shader_bit_encoding) || defined(GL_ARB_gpu_shader5) || __VERSION__ >= 430
1266 bool float_match(float u, float f, uint bits) { return floatBitsToUint(u) == bits; }
1267 #else
1268 bool float_match(float u, float f, uint bits) { return u == f; }
1269 #endif
1270 % if glsl_version >= 400 or "GL_ARB_gpu_shader_fp64" in extensions:
1272 bool double_match(double u, uvec2 bits) { return unpackDouble2x32(u) == bits; }
1273 %endif
1275 void main()
1277 /* std140 (or shared) layout prevents any fields or blocks from being
1278 * eliminated. Section 2.11.6 of the OpenGL ES 3.0 spec makes this
1279 * explicit, but desktop GL specs only imply it.
1281 bool pass = true;
1283 % for i in xrange(len(checkers)):
1284 % if i % 5 == 0:
1285 if (${checkers[i]})
1286 pass = false;
1287 % endif
1288 % endfor
1290 vertex_pass = int(pass);
1291 gl_Position = piglit_vertex;
1294 [fragment shader]
1295 precision highp float;
1297 out vec4 piglit_fragcolor;
1298 flat in int vertex_pass;
1300 void main()
1302 piglit_fragcolor = bool(vertex_pass) ? vec4(0, 1, 0, 1) : vec4(1, 0, 0, 1);
1305 [test]
1306 link success
1307 % for (name, type, size, offset, astride, mstride, row_major) in test_vectors:
1309 active uniform ${name} GL_UNIFORM_TYPE ${type}
1310 active uniform ${name} GL_UNIFORM_SIZE ${size}
1311 % if packing.fixed_offsets():
1312 active uniform ${name} GL_UNIFORM_OFFSET ${offset}
1313 active uniform ${name} GL_UNIFORM_ARRAY_STRIDE ${astride}
1314 active uniform ${name} GL_UNIFORM_MATRIX_STRIDE ${mstride}
1315 % endif
1316 active uniform ${name} GL_UNIFORM_IS_ROW_MAJOR ${row_major}
1317 % endfor
1319 % for (type, name, data) in setters:
1320 uniform ${type} ${name} ${data}
1321 % endfor
1323 draw rect -1 -1 2 2
1324 probe all rgba 0.0 1.0 0.0 1.0"""))
1326 return t.render(glsl_version=glsl_version,
1327 extensions=extensions,
1328 structures=structures,
1329 test_vectors=test_vectors,
1330 uniform_blocks=blocks,
1331 packing=packing,
1332 iterate_all_block_members=iterate_all_block_members,
1333 pretty_format_member=pretty_format_member,
1334 block_row_major_default=block_row_major_default,
1335 struct_types=struct_types,
1336 checkers=checkers,
1337 setters=setters)
1340 def generate_file_name(requirements, packing):
1341 """Based on the required UBO elements and the packing, generate a
1342 plausible file name for the test case.
1344 prefix = packing.layout_string() + "-"
1345 suffix = ".shader_test"
1347 body = "-and-".join(["-".join(req) for req in requirements])
1349 return prefix + body + suffix
1352 class packing_rules(object):
1353 __metaclass__ = abc.ABCMeta
1355 @abc.abstractproperty
1356 def layout_string(self):
1357 """Get the string used in a layout qualifier to select this set of
1358 layout rules.
1361 @abc.abstractproperty
1362 def fixed_offsets(self):
1363 """Return true if fields in this layout have fixed locations (e.g.,
1364 std140) or false if they can vary among implementations (e.g., shared
1365 or packed)?
1368 @abc.abstractmethod
1369 def base_alignment(self, type, row_major):
1370 """Determine the base alignment, in bytes, of the named type"""
1372 @abc.abstractmethod
1373 def matrix_stride(self, type, row_major):
1374 """Determine the stride, in bytes, from one indexable vector of the
1375 matrix (column or row depending on the orientation) to the next.
1378 @abc.abstractmethod
1379 def array_stride(self, type, row_major):
1380 """Determine the stride, in bytes, from one array element to the next.
1381 If the type is not an array type, zero is returned.
1384 def size(self, type, row_major):
1385 """Determine the size, in bytes, of the specified type.
1387 Applying the packing rules and the row-major setting, determine the
1388 size, in bytes, of the entire data type. This will include padded
1389 after the data element as required by the GLSL specification.
1391 if isarray(type):
1392 return self.array_stride(type, row_major) * arrays_of_arrays_size(type)
1394 if type in ["float", "bool", "int", "uint"]:
1395 return 4
1397 if type == "double":
1398 return 8
1400 if type in ["vec2", "bvec2", "ivec2", "uvec2"]:
1401 return 2 * 4
1403 if type == "dvec2":
1404 return 2 * 8
1406 if type in ["vec3", "bvec3", "ivec3", "uvec3"]:
1407 return 3 * 4
1409 if type == "dvec3":
1410 return 3 * 8
1412 if type in ["vec4", "bvec4", "ivec4", "uvec4"]:
1413 return 4 * 4
1415 if type == "dvec4":
1416 return 4 * 8
1418 if "mat" in type:
1419 c, r = matrix_dimensions(type)
1420 if not row_major:
1421 return c * self.matrix_stride(type, row_major)
1422 else:
1423 return r * self.matrix_stride(type, row_major)
1425 if type not in struct_types:
1426 raise Exception("Unknown type {}".format(type))
1428 s = 0
1429 fields = struct_types[type]
1430 for (t, n) in fields:
1431 a = self.base_alignment(t, row_major)
1433 s = align(s, a) + self.size(t, row_major)
1435 s = align(s, self.base_alignment(type, row_major))
1436 return s
1439 class std140_packing_rules(packing_rules):
1440 def layout_string(self):
1441 return "std140"
1443 def fixed_offsets(self):
1444 return True
1446 def base_alignment(self, type, row_major):
1447 # (4) If the member is an array of scalars or vectors, the base
1448 # alignment and array stride are set to match the base alignment
1449 # of a single array element, according to rules (1), (2), and (3),
1450 # and rounded up to the base alignment of a vec4. The array may
1451 # have padding at the end; the base offset of the member following
1452 # the array is rounded up to the next multiple of the base
1453 # alignment.
1455 if isarray(type):
1456 return max(16,
1457 self.base_alignment(array_base_type(type), row_major))
1459 # (1) If the member is a scalar consuming <N> basic machine units, the
1460 # base alignment is <N>.
1462 if isscalar(type):
1463 return basic_machine_units(type)
1465 if isvector(type):
1466 # (2) If the member is a two- or four-component vector with
1467 # components consuming <N> basic machine units, the base
1468 # alignment is 2<N> or 4<N>, respectively.
1470 # (3) If the member is a three-component vector with components
1471 # consuming <N> basic machine units, the base alignment is
1472 # 4<N>.
1474 components = vector_size(type)
1475 if components == 2 or components == 4:
1476 return components * basic_machine_units(vector_base_type(type))
1477 elif components == 3:
1478 return 4 * basic_machine_units(vector_base_type(type))
1480 raise Exception("Invalid vector size {} for type {}".format(
1481 components,
1482 type))
1483 elif ismatrix(type):
1484 return self.matrix_stride(type, row_major)
1486 if type not in struct_types:
1487 raise Exception("Unknown type {}".format(type))
1489 # (9) If the member is a structure, the base alignment of the
1490 # structure is <N>, where <N> is the largest base alignment value
1491 # of any of its members, and rounded up to the base alignment of a
1492 # vec4. The individual members of this sub-structure are then
1493 # assigned offsets by applying this set of rules recursively,
1494 # where the base offset of the first member of the sub-structure
1495 # is equal to the aligned offset of the structure. The structure
1496 # may have padding at the end; the base offset of the member
1497 # following the sub-structure is rounded up to the next multiple
1498 # of the base alignment of the structure.
1500 a = 16
1501 fields = struct_types[type]
1502 for (field_type, field_name) in fields:
1503 a = max(a, self.base_alignment(field_type, row_major))
1505 return a
1507 def matrix_stride(self, type, row_major):
1508 c, r = matrix_dimensions(type)
1509 if not row_major:
1510 # (4) If the member is an array of scalars or vectors, the base
1511 # alignment and array stride are set to match the base
1512 # alignment of a single array element, according to rules (1),
1513 # (2), and (3), and rounded up to the base alignment of a
1514 # vec4. The array may have padding at the end; the base offset
1515 # of the member following the array is rounded up to the next
1516 # multiple of the base alignment.
1518 # (5) If the member is a column-major matrix with <C> columns and
1519 # <R> rows, the matrix is stored identically to an array of
1520 # <C> column vectors with <R> components each, according to
1521 # rule (4).
1523 if type[0] == 'd':
1524 return max(16, self.base_alignment("dvec{}".format(r), False))
1525 else:
1526 return max(16, self.base_alignment("vec{}".format(r), False))
1527 else:
1528 # (7) If the member is a row-major matrix with <C> columns and <R>
1529 # rows, the matrix is stored identically to an array of <R>
1530 # row vectors with <C> components each, according to rule (4).
1532 if type[0] == 'd':
1533 return max(16, self.base_alignment("dvec{}".format(c), False))
1534 else:
1535 return max(16, self.base_alignment("vec{}".format(c), False))
1537 def array_stride(self, type, row_major):
1538 base_type = without_array(type)
1540 if not isstructure(base_type):
1541 # (4) If the member is an array of scalars or vectors, the base
1542 # alignment and array stride are set to match the base
1543 # alignment of a single array element, according to rules (1),
1544 # (2), and (3), and rounded up to the base alignment of a
1545 # vec4. The array may have padding at the end; the base offset
1546 # of the member following the array is rounded up to the next
1547 # multiple of the base alignment.
1548 return max(16,
1549 max(self.base_alignment(base_type, row_major),
1550 self.size(base_type, row_major)))
1551 else:
1552 # (9) If the member is a structure, the base alignment of the
1553 # structure is <N>, where <N> is the largest base alignment
1554 # value of any of its members, and rounded up to the base
1555 # alignment of a vec4. The individual members of this
1556 # sub-structure are then assigned offsets by applying this set
1557 # of rules recursively, where the base offset of the first
1558 # member of the sub-structure is equal to the aligned offset
1559 # of the structure. The structure may have padding at the end;
1560 # the base offset of the member following the sub-structure is
1561 # rounded up to the next multiple of the base alignment of the
1562 # structure.
1564 # (10) If the member is an array of <S> structures, the <S> elements
1565 # of the array are laid out in order, according to rule (9).
1567 return align(self.size(base_type, row_major),
1568 self.base_alignment(base_type, row_major))
1571 class shared_packing_rules(std140_packing_rules):
1572 def layout_string(self):
1573 return "shared"
1575 def fixed_offsets(self):
1576 return False
1579 class unique_name_dict:
1580 """Helper class to generate a unique name for each field.
1582 Fields for each particular type have names based on the type. Each name
1583 is suffixed by a number, and the number is incremented each time a field
1584 of that type is created. For example, the first int field will be named
1585 "i1", and the second will be named "i2".
1588 def __init__(self):
1589 self.names = {}
1591 def trim_name(self, type):
1592 """Internal method to reduce a type name to a canonical form
1594 These names are used to track the type in the self.names dict.
1596 Array types have the arrayness stripped. Vector types have vector
1597 count stripped. Matrix types are converted to canonical "mat#x#"
1598 form. All other type names are unmodified.
1600 if isarray(type):
1601 t = without_array(type)
1602 else:
1603 t = type
1605 if ismatrix(t):
1606 # Canonicalize matrix type names.
1607 c, r = matrix_dimensions(t)
1609 name = "mat{}x{}".format(c, r)
1610 if t[0] == "d":
1611 name = "d" + name
1613 return name
1614 elif isscalar(t):
1615 return t
1616 elif isvector:
1617 return t.strip("1234")
1618 else:
1619 # Assume it must be a structure.
1620 return t
1622 def add_type(self, type):
1623 """Internal method to add a previously unknown type to the dictionary
1625 type -- Actual GLSL type name
1627 Generates the base name for fields of this type. Adds a tuple to dict
1628 (indexed by "type") of (base_name, 1).
1630 if isarray(type):
1631 t = without_array(type)
1632 else:
1633 t = type
1635 if isvector(t):
1636 base = "{}v".format(vector_base_type(t)[0])
1637 elif ismatrix(t):
1638 c, r = matrix_dimensions(t)
1640 if t[0] == 'd':
1641 base = "dm{}{}_".format(c, r)
1642 else:
1643 base = "m{}{}_".format(c, r)
1644 elif isscalar(t):
1645 base = t[0]
1646 elif t[0] == "S":
1647 base = "s{}_".format(t[1:])
1648 else:
1649 raise Exception("Malformed type name {}".format(t))
1651 self.names[self.trim_name(t)] = (base, 1)
1652 return
1654 def get_name(self, type):
1655 """Return a unique name for a field of the specified type."""
1656 t = self.trim_name(type)
1657 if t not in self.names:
1658 self.add_type(type)
1660 base, count = self.names[t]
1661 self.names[t] = (base, count + 1)
1663 return "{}{}".format(base, count)
1666 class block_member(object):
1667 """Helper class to track all of the layout information for a single
1668 (sub-)member of a uniform block."""
1670 TYPE_ENUM = {
1671 'float': "GL_FLOAT",
1672 'vec2': "GL_FLOAT_VEC2",
1673 'vec3': "GL_FLOAT_VEC3",
1674 'vec4': "GL_FLOAT_VEC4",
1676 'double': "GL_DOUBLE",
1677 'dvec2': "GL_DOUBLE_VEC2",
1678 'dvec3': "GL_DOUBLE_VEC3",
1679 'dvec4': "GL_DOUBLE_VEC4",
1681 'int': "GL_INT",
1682 'ivec2': "GL_INT_VEC2",
1683 'ivec3': "GL_INT_VEC3",
1684 'ivec4': "GL_INT_VEC4",
1686 'uint': "GL_UNSIGNED_INT",
1687 'uvec2': "GL_UNSIGNED_INT_VEC2",
1688 'uvec3': "GL_UNSIGNED_INT_VEC3",
1689 'uvec4': "GL_UNSIGNED_INT_VEC4",
1691 'bool': "GL_BOOL",
1692 'bvec2': "GL_BOOL_VEC2",
1693 'bvec3': "GL_BOOL_VEC3",
1694 'bvec4': "GL_BOOL_VEC4",
1696 'mat2': "GL_FLOAT_MAT2",
1697 'mat2x2': "GL_FLOAT_MAT2",
1698 'mat2x3': "GL_FLOAT_MAT2x3",
1699 'mat2x4': "GL_FLOAT_MAT2x4",
1701 'mat3': "GL_FLOAT_MAT3",
1702 'mat3x2': "GL_FLOAT_MAT3x2",
1703 'mat3x3': "GL_FLOAT_MAT3",
1704 'mat3x4': "GL_FLOAT_MAT3x4",
1706 'mat4': "GL_FLOAT_MAT4",
1707 'mat4x2': "GL_FLOAT_MAT4x2",
1708 'mat4x3': "GL_FLOAT_MAT4x3",
1709 'mat4x4': "GL_FLOAT_MAT4",
1711 'dmat2': "GL_DOUBLE_MAT2",
1712 'dmat2x2': "GL_DOUBLE_MAT2",
1713 'dmat2x3': "GL_DOUBLE_MAT2x3",
1714 'dmat2x4': "GL_DOUBLE_MAT2x4",
1716 'dmat3': "GL_DOUBLE_MAT3",
1717 'dmat3x2': "GL_DOUBLE_MAT3x2",
1718 'dmat3x3': "GL_DOUBLE_MAT3",
1719 'dmat3x4': "GL_DOUBLE_MAT3x4",
1721 'dmat4': "GL_DOUBLE_MAT4",
1722 'dmat4x2': "GL_DOUBLE_MAT4x2",
1723 'dmat4x3': "GL_DOUBLE_MAT4x3",
1724 'dmat4x4': "GL_DOUBLE_MAT4"
1727 def __init__(self,
1728 GLSL_name,
1729 API_name,
1730 GLSL_type,
1731 explicit_layout,
1732 offset,
1733 row_major):
1734 self.GLSL_name = GLSL_name
1735 self.GLSL_type = GLSL_type
1737 self.API_name = API_name
1739 self.explicit_layout = explicit_layout
1740 self.offset = offset
1741 self.row_major = row_major
1743 if isarray(GLSL_type):
1744 base_type = without_array(GLSL_type)
1745 if isstructure(base_type):
1746 self.API_type = None
1747 else:
1748 self.API_type = self.TYPE_ENUM[base_type];
1750 self.size = array_elements(GLSL_type)
1751 elif isstructure(GLSL_type):
1752 self.API_type = None
1753 self.size = 1
1754 else:
1755 self.API_type = self.TYPE_ENUM[GLSL_type];
1756 self.size = 1
1758 def struct_nesting(self):
1759 if "." in self.GLSL_name:
1760 # If the block has an instance name, the API name will use the
1761 # block name instead of the instance name. As a result,
1762 # GLSL_name and API_name will be different.
1764 # The first "." is for the block instance name, so it does not count
1765 # as structure nesting.
1767 if self.GLSL_name != self.API_name:
1768 return collections.Counter(self.GLSL_name)["."] - 1
1769 else:
1770 return collections.Counter(self.GLSL_name)["."]
1771 else:
1772 return 0
1775 if __name__ == "__main__":
1776 if len(sys.argv) > 1:
1777 max_glsl_version = int(sys.argv[1])
1778 else:
1779 max_glsl_version = 130
1781 if len(sys.argv) > 2:
1782 extensions = sys.argv[2:]
1783 else:
1784 extensions = []
1786 # Pick a random GLSL version from the available set of possible versions.
1787 glsl_version = random.choice([v for v in [130, 140, 150, 400, 430]
1788 if v <= max_glsl_version])
1790 # Use the GLSL version filter out some extensions that are redundant.
1791 if glsl_version >= 140 and "GL_ARB_uniform_buffer_object" in extensions:
1792 extensions.remove("GL_ARB_uniform_buffer_object")
1794 if glsl_version >= 400 and "GL_ARB_gpu_shader_fp64" in extensions:
1795 extensions.remove("GL_ARB_gpu_shader_fp64")
1797 if glsl_version >= 430 and "GL_ARB_arrays_of_arrays" in extensions:
1798 extensions.remove("GL_ARB_arrays_of_arrays")
1800 # Pick a random subset of the remaining extensions.
1801 num_ext = len(extensions)
1802 if num_ext > 0:
1803 random.shuffle(extensions)
1804 r = random.randint(0, num_ext)
1805 extensions = extensions[:r]
1807 # Based on the GLSL version and the set of extensions, pick the set of
1808 # possible data types.
1809 if glsl_version < 400:
1810 types = ALL130_TYPES
1811 else:
1812 types = ALL400_TYPES
1814 if "GL_ARB_gpu_shader_fp64" in extensions:
1815 types.extend(DOUBLE_TYPES)
1817 # Based on the GLSL version, pick a set of packing rules
1818 # FINISHME: Add support for std430_packing_rules() soon.
1819 packing = random.choice([std140_packing_rules(), shared_packing_rules()])
1821 # Based on the GLSL version and the set of available extensions, pick
1822 # some required combinations of data structures to include in the UBO.
1823 arrays_of_arrays = (glsl_version >= 430 or
1824 "GL_ARB_arrays_of_arrays" in extensions)
1826 allow_row_major_structure = glsl_version >= 150
1828 requirements = []
1829 for i in [1, 2]:
1830 x = [random.choice(["array", "struct"])]
1832 for j in [1, 2, 3]:
1833 # If arrays-of-arrays are not supported, don't allow "array" to be
1834 # picked twice in a row.
1836 if x[-1] == "array" and not arrays_of_arrays:
1837 x.append("struct")
1838 else:
1839 x.append(random.choice(["array", "struct"]))
1841 if "struct" in x and allow_row_major_structure:
1842 ordering = random.choice([None,
1843 None,
1844 None,
1845 None,
1846 "column_major",
1847 "#column_major",
1848 "row_major",
1849 "row_major"])
1850 if ordering:
1851 x = [ordering] + x
1853 requirements.append(x)
1855 if glsl_version < 140:
1856 extensions.append("GL_ARB_uniform_buffer_object")
1858 # Generate the test!
1859 fields, required_layouts = generate_ubo(requirements, types)
1861 layouts = generate_layouts(
1862 fields,
1863 required_layouts,
1864 allow_row_major_structure)
1866 blocks = generate_block_list(
1867 glsl_version,
1868 packing,
1869 fields,
1870 layouts)
1872 print(emit_shader_test(
1873 blocks,
1874 packing,
1875 glsl_version,
1876 extensions))