From 0975442a9a2703a2d4d20e33eeb0e5a6f0ca6469 Mon Sep 17 00:00:00 2001 From: Florian Will Date: Sun, 21 Jan 2018 11:25:27 +0100 Subject: [PATCH 2/2] [HACK] generators/random_ubo: generate SSBO tests Hack the random_ubo.py script to generate SSBO tests based on the rules it uses to generate UBO tests. The tests create std140 and std430 SSBO blocks with both column_major and row_major formats, and populate the buffers using random data. The generated shaders check if the SSBO blocks contain expected values when reading them in GLSL. This needs more clean-up (including new names for the script files). --- .../random_ubo-arb_uniform_buffer_object.py | 28 ++- generated_tests/random_ubo.py | 224 ++++++++++++++++----- tests/shaders/shader_runner.c | 21 ++ 3 files changed, 218 insertions(+), 55 deletions(-) diff --git a/generated_tests/random_ubo-arb_uniform_buffer_object.py b/generated_tests/random_ubo-arb_uniform_buffer_object.py index d9cdb5d5a..59de35e3f 100644 --- a/generated_tests/random_ubo-arb_uniform_buffer_object.py +++ b/generated_tests/random_ubo-arb_uniform_buffer_object.py @@ -24,8 +24,12 @@ import os import errno import random_ubo -def do_test(requirements, packing): - path = os.path.join("spec", "arb_uniform_buffer_object", "execution") +def do_test(requirements, packing, block_type): + if block_type == "ubo": + path = os.path.join("spec", "arb_uniform_buffer_object", "execution") + elif block_type == "ssbo": + path = os.path.join("spec", "arb_shader_storage_buffer_object", + "execution") try: os.makedirs(path) @@ -54,23 +58,27 @@ def do_test(requirements, packing): False) blocks = random_ubo.generate_block_list( - 130, + 450, packing, fields, - layouts) + layouts, + block_type) print basename file.write(random_ubo.emit_shader_test( blocks, packing, - 130, + 450, ["GL_ARB_uniform_buffer_object","GL_ARB_arrays_of_arrays"])) file.close() -all_packing = [random_ubo.std140_packing_rules(), +ubo_packing = [random_ubo.std140_packing_rules(), random_ubo.shared_packing_rules()] +ssbo_packing = [random_ubo.std140_packing_rules(), + random_ubo.std430_packing_rules()] + all_requirements = [] # Generate a test for each matrix type that: @@ -120,6 +128,8 @@ all_requirements.append([["struct", "array", "array", "array", "struct"]]) all_requirements.append([["array", "array", "struct", "array"]]) all_requirements.append([["struct", "array", "array", "array"]]) -for p in all_packing: - for r in all_requirements: - do_test(r, p) +for r in all_requirements: + for p in ubo_packing: + do_test(r, p, "ubo") + for p in ssbo_packing: + do_test(r, p, "ssbo") diff --git a/generated_tests/random_ubo.py b/generated_tests/random_ubo.py index 31d0f8523..075608412 100644 --- a/generated_tests/random_ubo.py +++ b/generated_tests/random_ubo.py @@ -21,6 +21,7 @@ # SOFTWARE. from __future__ import print_function +import binascii import random import abc import collections @@ -828,12 +829,17 @@ def vector_derp(type, name, data): its expected value. """ scalar = vector_base_type(type) - components = ["x", "y", "z", "w"] - return [scalar_derp(scalar, - "{}.{}".format(name, "xyzw"[i]), - data[i]) - for i in xrange(vector_size(type))] + swizzle_tests = [scalar_derp(scalar, + "{}.{}".format(name, "xyzw"[i]), + data[i]) + for i in xrange(vector_size(type))] + index_tests = [scalar_derp(scalar, + "{}[{}]".format(name, i), + data[i]) + for i in xrange(vector_size(type))] + + return swizzle_tests + index_tests def matrix_derp(type, name, data): @@ -912,7 +918,77 @@ def bit_exact_data(raw_data, type): else: return raw_data -def generate_array_data_pairs(name, api_name, element_type, row_major, offset, packing, setters, checkers): +def ssbo_data(raw_data, type, packing, row_major): + """Turn the raw_datagenerated by random_data() for a SSBO buffer block + member into a hex string ready to be passed to the ssbo subdata hex + shader_runner command. type is the GLSL type of the member. + """ + + if ismatrix(type): + dim = matrix_dimensions(type) + stride = packing.matrix_stride(type, row_major) + + result = [] + if type in ["float", "vec2", "vec3", "vec4", + "mat2", "mat2x2", "mat2x3", "mat2x4", + "mat3", "mat3x2", "mat3x3", "mat3x4", + "mat4", "mat4x2", "mat4x3", "mat4x4"]: + + written = 0 + for d in iterate_data(raw_data, type, row_major): + p = struct.pack('f', float(d)) + result.append(binascii.hexlify(p)) + written += 1 + + # Add padding for matrix stride + relevant_dim = 0 if row_major else 1 + if ismatrix(type) and written % dim[relevant_dim] == 0: + result.append("00" * (stride - dim[relevant_dim] * 4)) + + elif type in ["double", "dvec2", "dvec3", "dvec4", + "dmat2", "dmat2x2", "dmat2x3", "dmat2x4", + "dmat3", "dmat3x2", "dmat3x3", "dmat3x4", + "dmat4", "dmat4x2", "dmat4x3", "dmat4x4"]: + + written = 0 + for d in iterate_data(raw_data, type, row_major): + p = struct.pack('d', float(d)) + result.append(binascii.hexlify(p)) + written += 1 + + # Add padding for matrix stride + relevant_dim = 0 if row_major else 1 + if ismatrix(type) and written % dim[relevant_dim] == 0: + result.append("00" * (stride - dim[relevant_dim] * 8)) + + elif type in ["int", "ivec2", "ivec3", "ivec4"]: + for d in raw_data.split(" "): + p = struct.pack('i', int(d)) + result.append(binascii.hexlify(p)) + + elif type in ["uint", "bool", "uvec2", "uvec3", "uvec4", "bvec2", "bvec3", "bvec4"]: + for d in raw_data.split(" "): + p = struct.pack('I', int(d)) + result.append(binascii.hexlify(p)) + + else: + print("Invalid type {0}!".format(type)) + + return "".join(result) + +def iterate_data(raw_data, type, row_major): + data = raw_data.split(" ") + + if ismatrix(type) and row_major: + dim = matrix_dimensions(type) + for row in range(0, dim[1]): + for col in range(0, dim[0]): + yield data[col * dim[1] + row] + + else: + for d in data: yield d + +def generate_array_data_pairs(name, api_name, element_type, row_major, offset, block_type, block_binding, packing, setters, checkers): base_type = array_base_type(element_type) astride = packing.array_stride(element_type, row_major) @@ -923,15 +999,25 @@ def generate_array_data_pairs(name, api_name, element_type, row_major, offset, p api_name_with_index = "{}[{}]".format(api_name, i) if isarray(base_type): - offset = offset + (i * arrays_of_arrays_size(base_type) * astride) - generate_array_data_pairs(name_with_index, api_name_with_index, base_type, row_major, offset, packing, setters, checkers) + elem_offset = offset + (i * arrays_of_arrays_size(base_type) * astride) + generate_array_data_pairs(name_with_index, api_name_with_index, base_type, row_major, elem_offset, block_type, block_binding, packing, setters, checkers) else: - offset = offset + (i * astride) - raw_data = random_data(base_type, name_with_index, offset) - setters.append( - (fudge_type_for_setter(base_type), - api_name_with_index, - bit_exact_data(raw_data, base_type))) + elem_offset = offset + (i * astride) + raw_data = random_data(base_type, name_with_index, elem_offset) + + if block_type == "ubo": + setters.append( + (block_type, + fudge_type_for_setter(base_type), + api_name_with_index, + bit_exact_data(raw_data, base_type))) + else: + size = packing.size(base_type, row_major) + setters.append((block_type, + block_binding, + elem_offset, + size, + ssbo_data(raw_data, base_type, packing, row_major))) data = raw_data.split(" ") @@ -962,7 +1048,9 @@ def generate_data_pairs(uniform_blocks, packing): checkers = [] setters = [] - for (block_name, + for (block_type, + block_binding, + block_name, instance_name, global_layout, block_layout, @@ -977,13 +1065,24 @@ def generate_data_pairs(uniform_blocks, packing): block_row_major_default(global_layout, block_layout)): if m.API_type: + a = packing.base_alignment(m.GLSL_type, m.row_major) + aligned_offset = align(m.offset, a) if isarray(m.GLSL_type): - generate_array_data_pairs(m.GLSL_name, m.API_name, m.GLSL_type, m.row_major, m.offset, packing, setters, checkers) + generate_array_data_pairs(m.GLSL_name, m.API_name, m.GLSL_type, m.row_major, aligned_offset, block_type, block_binding, packing, setters, checkers) else: raw_data = random_data(m.GLSL_type, m.GLSL_name, m.offset) - setters.append((fudge_type_for_setter(m.GLSL_type), - m.API_name, - bit_exact_data(raw_data, m.GLSL_type))) + if block_type == "ubo": + setters.append((block_type, + fudge_type_for_setter(m.GLSL_type), + m.API_name, + bit_exact_data(raw_data, m.GLSL_type))) + else: + size = packing.size(m.GLSL_type, m.row_major) + setters.append((block_type, + block_binding, + aligned_offset, + size, + ssbo_data(raw_data, m.GLSL_type, packing, m.row_major))) data = raw_data.split(" ") @@ -1117,7 +1216,7 @@ def block_row_major_default(global_layout, block_layout): return row_major -def generate_block_list(glsl_version, packing, ubo_fields, layouts): +def generate_block_list(glsl_version, packing, ubo_fields, layouts, block_type): """Return list of uniform blocks to be passed to emit_shader_test. The supplied ubo_fields and layouts are reformatted as an element in a @@ -1127,7 +1226,8 @@ def generate_block_list(glsl_version, packing, ubo_fields, layouts): be specified in different ways (e.g., by using a global layout qualifier). """ - blocks = [("UB1", "", None, packing.layout_string(), ubo_fields, layouts)] + blocks = [(block_type, 0, "UB1", "", None, packing.layout_string(), + ubo_fields, layouts)] # If the GLSL version is at least 1.50, UBO functionality is significantly # extended. @@ -1156,14 +1256,18 @@ def generate_block_list(glsl_version, packing, ubo_fields, layouts): if glsl_version >= 150: inverted_layouts = [relayout_for_default_row_major(l) for l in layouts] - blocks.append(("UB2", + blocks.append((block_type, + 1, + "UB2", "ub2", None, packing.layout_string() + ", row_major", ubo_fields, inverted_layouts)) - blocks.append(("UB3", + blocks.append((block_type, + 2, + "UB3", "ub3", # Disabled to work around Mesa bug #83508. # "ub3[2]", @@ -1179,7 +1283,9 @@ def emit_shader_test(blocks, packing, glsl_version, extensions): structures = [] test_vectors = [] - for (block_name, + for (block_type, + block_binding, + block_name, instance_name, global_layout, block_layout, @@ -1188,13 +1294,14 @@ def emit_shader_test(blocks, packing, glsl_version, extensions): structures.extend([s for s in iterate_structures(fields)]) - test_vectors.extend(generate_test_vectors( - fields, - field_layouts, - block_name, - instance_name, - packing, - block_row_major_default(global_layout, block_layout))) + if block_type != "ssbo": + test_vectors.extend(generate_test_vectors( + fields, + field_layouts, + block_name, + instance_name, + packing, + block_row_major_default(global_layout, block_layout))) checkers, setters = generate_data_pairs(blocks, packing) @@ -1219,7 +1326,7 @@ def emit_shader_test(blocks, packing, glsl_version, extensions): % for s in structures: # STRUCT ("${s}", ${struct_types[s]}) % endfor - % for b in uniform_blocks: + % for b in blocks: # UBO ${b} % endfor # DATA END @@ -1241,15 +1348,17 @@ def emit_shader_test(blocks, packing, glsl_version, extensions): }; % endfor - % for (block_name, instance_name, global_layout, block_layout, fields, field_layouts) in uniform_blocks: + % for (block_type, block_binding, block_name, instance_name, global_layout, block_layout, fields, field_layouts) in blocks: % if global_layout: - layout(${global_layout}) uniform; + layout(${global_layout}) ${"uniform" if block_type == "ubo" else "buffer"}; % endif % if block_layout: - layout(${block_layout}) + layout(${block_layout} ${", binding = " + str(block_binding) if block_type == "ssbo" else ""}) + % elif block_type == "ssbo": + layout(binding = ${block_binding}) % endif - uniform ${block_name} { + ${"uniform" if block_type == "ubo" else "buffer"} ${block_name} { // base base align padded row- array matrix // align off. off. size major stride stride % for m in iterate_all_block_members(fields, field_layouts, block_name, instance_name, packing, block_row_major_default(global_layout, block_layout)): @@ -1315,8 +1424,18 @@ def emit_shader_test(blocks, packing, glsl_version, extensions): active uniform ${name} GL_UNIFORM_IS_ROW_MAJOR ${row_major} % endfor - % for (type, name, data) in setters: - uniform ${type} ${name} ${data} + % for (block_type, block_binding, block_name, instance_name, global_layout, block_layout, fields, field_layouts) in blocks: + % if block_type == "ssbo": + ssbo ${block_binding} 1000000 + % endif + % endfor + + % for setter in setters: + % if setter[0] == "ubo": + uniform ${setter[1]} ${setter[2]} ${setter[3]} + % else: + ssbo ${setter[1]} subdata hex ${setter[2]} ${setter[3]} ${setter[4]} + % endif % endfor draw rect -1 -1 2 2 @@ -1326,7 +1445,7 @@ def emit_shader_test(blocks, packing, glsl_version, extensions): extensions=extensions, structures=structures, test_vectors=test_vectors, - uniform_blocks=blocks, + blocks=blocks, packing=packing, iterate_all_block_members=iterate_all_block_members, pretty_format_member=pretty_format_member, @@ -1442,6 +1561,10 @@ class std140_packing_rules(packing_rules): def fixed_offsets(self): return True + def base_alignment_roundup(self): + # See (4) + return basic_machine_units("float") * 4 + def base_alignment(self, type, row_major): # (4) If the member is an array of scalars or vectors, the base # alignment and array stride are set to match the base alignment @@ -1452,7 +1575,7 @@ class std140_packing_rules(packing_rules): # alignment. if isarray(type): - return max(16, + return max(self.base_alignment_roundup(), self.base_alignment(array_base_type(type), row_major)) # (1) If the member is a scalar consuming basic machine units, the @@ -1496,7 +1619,7 @@ class std140_packing_rules(packing_rules): # following the sub-structure is rounded up to the next multiple # of the base alignment of the structure. - a = 16 + a = self.base_alignment_roundup() fields = struct_types[type] for (field_type, field_name) in fields: a = max(a, self.base_alignment(field_type, row_major)) @@ -1505,6 +1628,7 @@ class std140_packing_rules(packing_rules): def matrix_stride(self, type, row_major): c, r = matrix_dimensions(type) + a = self.base_alignment_roundup() if not row_major: # (4) If the member is an array of scalars or vectors, the base # alignment and array stride are set to match the base @@ -1520,18 +1644,18 @@ class std140_packing_rules(packing_rules): # rule (4). if type[0] == 'd': - return max(16, self.base_alignment("dvec{}".format(r), False)) + return max(a, self.base_alignment("dvec{}".format(r), False)) else: - return max(16, self.base_alignment("vec{}".format(r), False)) + return max(a, self.base_alignment("vec{}".format(r), False)) else: # (7) If the member is a row-major matrix with columns and # rows, the matrix is stored identically to an array of # row vectors with components each, according to rule (4). if type[0] == 'd': - return max(16, self.base_alignment("dvec{}".format(c), False)) + return max(a, self.base_alignment("dvec{}".format(c), False)) else: - return max(16, self.base_alignment("vec{}".format(c), False)) + return max(a, self.base_alignment("vec{}".format(c), False)) def array_stride(self, type, row_major): base_type = without_array(type) @@ -1544,7 +1668,7 @@ class std140_packing_rules(packing_rules): # vec4. The array may have padding at the end; the base offset # of the member following the array is rounded up to the next # multiple of the base alignment. - return max(16, + return max(self.base_alignment_roundup(), max(self.base_alignment(base_type, row_major), self.size(base_type, row_major))) else: @@ -1566,6 +1690,14 @@ class std140_packing_rules(packing_rules): return align(self.size(base_type, row_major), self.base_alignment(base_type, row_major)) +class std430_packing_rules(std140_packing_rules): + def layout_string(self): + return "std430" + + def base_alignment_roundup(self): + # No rounding up of array/struct base alignments + return 0 + class shared_packing_rules(std140_packing_rules): def layout_string(self): diff --git a/tests/shaders/shader_runner.c b/tests/shaders/shader_runner.c index 700b11327..8157af58d 100644 --- a/tests/shaders/shader_runner.c +++ b/tests/shaders/shader_runner.c @@ -3506,6 +3506,27 @@ piglit_display(void) glBufferData(GL_SHADER_STORAGE_BUFFER, y, ssbo_init, GL_DYNAMIC_DRAW); free(ssbo_init); + } else if (sscanf(line, "ssbo %d subdata hex %d %d", &x, &y, &z) == 3) { + if (z > 128 || strlen(line) > 295) { + fprintf(stderr, "ssbo hex subdata: max. 128 bytes allowed!\n"); + piglit_report_result(PIGLIT_FAIL); + continue; + } + + sscanf(line, "ssbo %d subdata hex %d %d %s", &x, &y, &z, &s); + if (strlen(s) != 2 * z) { + fprintf(stderr, "ssbo hex: incorrect buffer size!\n"); + piglit_report_result(PIGLIT_FAIL); + continue; + } + + GLubyte *ssbo_init = calloc(z, 1); + for (unsigned int i = 0; i < z; i++) + sscanf(s + (2 * i), "%2hhx", &ssbo_init[i]); + + glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo[x]); + glBufferSubData(GL_SHADER_STORAGE_BUFFER, y, z, ssbo_init); + free(ssbo_init); } else if (sscanf(line, "ssbo %d subdata float %d %f", &x, &y, &c[0]) == 3) { glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo[x]); glBufferSubData(GL_SHADER_STORAGE_BUFFER, y, 4, &c[0]); -- 2.14.1