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
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.
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"
49 "double", "dvec2", "dvec3", "dvec4",
51 "dmat2", "dmat2x3", "dmat2x4",
52 "dmat3x2", "dmat3", "dmat3x4",
53 "dmat4x2", "dmat4x3", "dmat4"
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
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",
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"]
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"]
102 """Return true if the type name appears to be an array 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
115 return not (isscalar(type) or isvector(type) or ismatrix(type) or
119 def vector_size(type):
120 """Return the number of elements in a vector 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))
136 s
= type[-3:].split("x")
137 return int(s
[0]), int(s
[1])
143 def array_elements(type):
144 """Return the number of elements in an array type.
146 For non-array types zero is returned.
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"]:
159 if type in ["double", "int64_t", "uint64_t"]:
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))
186 while (isarray(base_type
)):
187 size
= size
* array_elements(base_type
)
188 base_type
= array_base_type(base_type
)
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":
199 elif type[0:1] == "u6":
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
220 for (type, name
) in fields
:
222 type = without_array(type)
224 if not isstructure(type):
227 if type in types_seen
:
228 raise Exception("Type recurrsion involving {}".format(type))
230 for t
in iterate_structures(struct_types
[type],
235 if type not in types_yielded
:
236 types_yielded
.append(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]
274 base_type
, name
= generate_member_from_description(
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])
285 size
= random
.choice([3, 5, 7, 11, 13])
287 t
= "{}[{}]".format(base_type
, size
)
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
297 if len(description
) > 1 and description
[1] in ALL_TYPES
:
298 required_fields
= [generate_member_from_description([i
],
301 for i
in description
[1:]]
304 required_fields
= [generate_member_from_description(
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:],
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
344 names
= unique_name_dict()
348 for desc
in description_list
:
349 m
= generate_member_from_description(desc
, builtin_types
, names
)
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
])
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
379 if required_layouts
is None:
380 required_layouts
= [None] * len(fields
)
383 for ((type, name
), lay
) in zip(fields
, required_layouts
):
385 type = without_array(type)
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
400 layouts
.append(random
.choice(["#column_major",
411 def relayout_for_default_row_major(l
):
412 """Return a new layout for an assumed default layout of row-major."""
415 elif l
== "column_major" or l
== "#column_major":
416 return "column_major"
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
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
431 structure_template
= Template(dedent("""\
432 struct ${struct_name} {
433 % for (field_type, field_name) in fields:
434 ${"{:<11}".format(field_type)} ${field_name};
439 return structure_template
.render(struct_name
=type, fields
=struct_types
[type])
441 def iterate_struct_array_recursive(field_type
,
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
,
473 a
= packing
.base_alignment(x
.GLSL_type
, row_major
)
474 o
= align(o
, a
) + packing
.size(x
.GLSL_type
, row_major
)
476 o
= align(offset
, array_member_align
) + (astride
* i
)
478 name_from_shader_with_index
,
479 name_from_API_with_index
,
484 for x
in iterate_all_recursive(struct_types
[element_t
],
486 name_from_API_with_index
,
487 name_from_shader_with_index
,
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
,
499 name_from_shader_base
,
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
508 name_from_API_base -- Base name of the member as it would be accessed via
510 name_from_shader_base -- Base name of the member as it would be accessed via
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
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
529 Consider the following structure:
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}"
554 for ((field_type
, field_name
), explicit_layout
) in zip(fields
,
556 name_from_shader
= fmt
.format(
557 base
=name_from_shader_base
,
559 name_from_API
= fmt
.format(
560 base
=name_from_API_base
,
563 if explicit_layout
== "row_major":
564 field_row_major
= True
565 elif explicit_layout
== "column_major":
566 field_row_major
= False
568 field_row_major
= row_major
570 if isarray(field_type
):
571 base_type
= without_array(field_type
)
573 if isstructure(base_type
):
582 for x
in iterate_struct_array_recursive(field_type
,
592 elif ismatrix(base_type
):
608 elif isstructure(field_type
):
617 a
= packing
.base_alignment(field_type
, field_row_major
)
619 for x
in iterate_all_recursive(struct_types
[field_type
],
628 elif ismatrix(field_type
):
636 elif isvector(field_type
) or isscalar(field_type
):
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
,
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
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
679 Consider the following block:
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
,
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.
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.
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.
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":
734 return str(int((h
& 8) == 0))
735 elif type == "float" or type == "double":
736 return str(float(h
- 0x7fffffff) / 65535.0)
738 raise Exception("Unknown scalar type {}".format(type))
741 scalar
= vector_base_type(type)
743 x
= [random_data(scalar
, name
, offset
+ (i
* 3))
744 for i
in range(vector_size(type))]
748 r
, c
= matrix_dimensions(type)
750 x
= [random_data("float", name
, offset
+ (i
* 7))
751 for i
in range(r
* c
)]
755 def generate_test_vectors(fields
,
763 for m
in iterate_all_block_members(fields
,
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
)
781 base_type
= m
.GLSL_type
786 if ismatrix(base_type
):
787 test_vectors
.append((
793 packing
.matrix_stride(base_type
, m
.row_major
),
795 elif isvector(base_type
) or isscalar(base_type
):
796 test_vectors
.append((
808 def scalar_derp(type, name
, data
):
809 """Return a GLSL code string to compare a scalar with its expected value."""
816 return "{} != {}u".format(name
, data
)
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")
836 hi
= "0x" + bits
[2:10]
837 lo
= "0x" + bits
[10:18]
839 return "!double_match({}, uvec2({}, {}))".format(name
, lo
, hi
)
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
848 scalar
= vector_base_type(type)
849 components
= ["x", "y", "z", "w"]
851 return [scalar_derp(scalar
,
852 "{}.{}".format(name
, "xyzw"[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
861 c
, r
= matrix_dimensions(type)
864 column_type
= "dvec{}".format(r
)
866 column_type
= "vec{}".format(r
)
871 data_pairs
.extend(vector_derp(
873 "{}[{}]".format(name
, i
),
874 data
[(i
* r
):(i
* r
) + r
]))
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.
890 return "i" + type[1:]
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"]:
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"]:
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
)
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
)
947 offset
= offset
+ (i
* astride
)
948 raw_data
= random_data(base_type
, name_with_index
, offset
)
950 (fudge_type_for_setter(base_type
),
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
,
960 elif isvector(base_type
):
961 checkers
.extend(vector_derp(base_type
,
964 elif ismatrix(base_type
):
965 checkers
.extend(matrix_derp(base_type
,
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.
988 field_layouts
) in uniform_blocks
:
989 for m
in iterate_all_block_members(
995 block_row_major_default(global_layout
, block_layout
)):
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
)
1001 raw_data
= random_data(m
.GLSL_type
, m
.GLSL_name
, m
.offset
)
1002 setters
.append((fudge_type_for_setter(m
.GLSL_type
),
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
,
1012 elif isvector(m
.GLSL_type
):
1013 checkers
.extend(vector_derp(m
.GLSL_type
,
1016 elif ismatrix(m
.GLSL_type
):
1017 checkers
.extend(matrix_derp(m
.GLSL_type
,
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
1030 a
= packing
.base_alignment(type, row_major
)
1031 aligned_offset
= align(offset
, a
)
1032 size
= packing
.size(type, row_major
)
1039 astride
= packing
.array_stride(type, row_major
)
1041 base_type
= without_array(type)
1042 if ismatrix(base_type
) and row_major
:
1044 row_major_str
= "yes"
1046 row_major_str
= "no"
1048 mstride
= packing
.matrix_stride(base_type
, row_major
)
1052 row_major_str
= "yes"
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(
1061 aligned_offset
=aligned_offset
,
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
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()
1093 indent
= "// " + (" " * n
)
1094 field_str
= "{indent}{type:<11} {name:<20}".format(
1099 field_str
= " {type:<11}{name};{padding}// ".format(
1102 padding
=" "[len(name
):])
1104 data_str
= pretty_format_type_data(
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
1115 if m
.explicit_layout
and "#" not in m
.explicit_layout
:
1116 return " layout({layout})\n{field}{data}".format(
1117 layout
=m
.explicit_layout
,
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
1129 if "row_major" in block_layout
:
1131 elif "column_major" in block_layout
:
1132 # The block layout can override a previous global layout.
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
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
1158 # 2. Uniform blocks can be grouped in arrays. UBO arrays must have an
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",
1180 packing
.layout_string() + ", row_major",
1184 blocks
.append(("UB3",
1186 # Disabled to work around Mesa bug #83508.
1188 packing
.layout_string() + ", row_major",
1196 def emit_shader_test(blocks
, packing
, glsl_version
, extensions
):
1205 field_layouts
) in blocks
:
1207 structures
.extend([s
for s
in iterate_structures(fields
)])
1209 test_vectors
.extend(generate_test_vectors(
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("""\
1228 GLSL >= ${glsl_version // 100}.${glsl_version % 100}
1229 % for ext in extensions:
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]})
1240 % for b in uniform_blocks:
1246 % for ext in extensions:
1247 #extension ${ext}: require
1249 #extension GL_ARB_shader_bit_encoding: enable
1250 #extension GL_ARB_gpu_shader5: enable
1252 precision highp float;
1253 % for s in structures:
1256 % for (field_type, field_name) in struct_types[s]:
1257 ${"{:<11}".format(field_type)} ${field_name};
1262 % for (block_name, instance_name, global_layout, block_layout, fields, field_layouts) in uniform_blocks:
1264 layout(${global_layout}) uniform;
1268 layout(${block_layout})
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)}
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; }
1285 bool float_match(float u, float f, uint bits) { return u == f; }
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; }
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.
1300 % for i in range(len(checkers)):
1307 vertex_pass = int(pass);
1308 gl_Position = piglit_vertex;
1312 precision highp float;
1314 out vec4 piglit_fragcolor;
1315 flat in int vertex_pass;
1319 piglit_fragcolor = bool(vertex_pass) ? vec4(0, 1, 0, 1) : vec4(1, 0, 0, 1);
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}
1333 active uniform ${name} GL_UNIFORM_IS_ROW_MAJOR ${row_major}
1336 % for (type, name, data) in setters:
1337 uniform ${type} ${name} ${data}
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
,
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
,
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
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
1386 def base_alignment(self
, type, row_major
):
1387 """Determine the base alignment, in bytes, of the named type"""
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.
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.
1409 return self
.array_stride(type, row_major
) * arrays_of_arrays_size(type)
1411 if type in ["float", "bool", "int", "uint"]:
1414 if type in ["double", "int64_t", "uint64_t"]:
1417 if type in ["vec2", "bvec2", "ivec2", "uvec2"]:
1420 if type in ["dvec2", "i64vec2", "u64vec2"]:
1423 if type in ["vec3", "bvec3", "ivec3", "uvec3"]:
1426 if type in ["dvec3", "i64vec3", "u64vec3"]:
1429 if type in ["vec4", "bvec4", "ivec4", "uvec4"]:
1432 if type in ["dvec4", "i64vec4", "u64vec4"]:
1436 c
, r
= matrix_dimensions(type)
1438 return c
* self
.matrix_stride(type, row_major
)
1440 return r
* self
.matrix_stride(type, row_major
)
1442 if type not in struct_types
:
1443 raise Exception("Unknown type {}".format(type))
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
))
1456 class std140_packing_rules(packing_rules
):
1457 def layout_string(self
):
1460 def fixed_offsets(self
):
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
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>.
1480 return basic_machine_units(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
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(
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.
1518 fields
= struct_types
[type]
1519 for (field_type
, field_name
) in fields
:
1520 a
= max(a
, self
.base_alignment(field_type
, row_major
))
1524 def matrix_stride(self
, type, row_major
):
1525 c
, r
= matrix_dimensions(type)
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
1541 return max(16, self
.base_alignment("dvec{}".format(r
), False))
1543 return max(16, self
.base_alignment("vec{}".format(r
), False))
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).
1550 return max(16, self
.base_alignment("dvec{}".format(c
), False))
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.
1566 max(self
.base_alignment(base_type
, row_major
),
1567 self
.size(base_type
, row_major
)))
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
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
):
1592 def fixed_offsets(self
):
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".
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.
1618 t
= without_array(type)
1623 # Canonicalize matrix type names.
1624 c
, r
= matrix_dimensions(t
)
1626 name
= "mat{}x{}".format(c
, r
)
1634 return t
.strip("1234")
1636 # Assume it must be a structure.
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).
1648 t
= without_array(type)
1653 base
= "{}v".format(vector_base_type(t
)[0])
1655 c
, r
= matrix_dimensions(t
)
1658 base
= "dm{}{}_".format(c
, r
)
1660 base
= "m{}{}_".format(c
, r
)
1664 base
= "s{}_".format(t
[1:])
1666 raise Exception("Malformed type name {}".format(t
))
1668 self
.names
[self
.trim_name(t
)] = (base
, 1)
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
:
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."""
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",
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",
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"
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
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
1782 self
.API_type
= self
.TYPE_ENUM
[GLSL_type
];
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
1797 return collections
.Counter(self
.GLSL_name
)["."]
1802 if __name__
== "__main__":
1803 if len(sys
.argv
) > 1:
1804 max_glsl_version
= int(sys
.argv
[1])
1806 max_glsl_version
= 130
1808 if len(sys
.argv
) > 2:
1809 extensions
= sys
.argv
[2:]
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
)
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
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
1857 x
= [random
.choice(["array", "struct"])]
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
:
1866 x
.append(random
.choice(["array", "struct"]))
1868 if "struct" in x
and allow_row_major_structure
:
1869 ordering
= random
.choice([None,
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(
1891 allow_row_major_structure
)
1893 blocks
= generate_block_list(
1899 print(emit_shader_test(