def test_detection_type_bools(self): glsl = """ #version 450 #extension GL_ARB_separate_shader_objects : enable layout({layout}, binding = 0) buffer Buffer {{ bool var1; bool[720][1280] var2; bvec2 var3; bvec3 var4; bvec4 var5; bvec3[5] var6; }}; void main() {{}} """ for layout in (Layout.STD140, Layout.STD430): # the vulkan spir-v compiler turns bools into uints expected_definition = Struct([ Scalar.uint(), Array(Scalar.uint(), (720, 1280), layout), Vector.uvec2(), Vector.uvec3(), Vector.uvec4(), Array(Vector.uvec3(), 5, layout) ], layout) shader = self.shader_from_txt(glsl.format(layout=layout), verbose=False) shader.inspect() detected_definition, _ = shader.code.get_block(0) equal = expected_definition.compare(detected_definition, quiet=True) self.assertTrue(equal)
def test_arb_example_std140(self): layout = Layout.STD430 struct_a = Struct( [ Scalar.int(), Vector.uvec2() # actually bvec2 ], layout, type_name="structA") struct_b = Struct([ Vector.uvec3(), Vector.vec2(), Array(Scalar.float(), 2, layout), Vector.vec2(), Array(Matrix(3, 3, DataType.FLOAT, layout), 2, layout) ], layout, type_name="structB") container = Struct([ Scalar.float(), Vector.vec2(), Vector.vec3(), struct_a, Scalar.float(), Array(Scalar.float(), 2, layout), Matrix(2, 3, DataType.FLOAT, layout), Array(struct_b, 2, layout) ], layout) self.run_test(container, [struct_a, struct_b], BufferUsage.STORAGE_BUFFER)
def test_manual(self): buffer_usage = BufferUsage.STORAGE_BUFFER buffer_layout = Layout.STD140 buffer_order = Order.ROW_MAJOR structA = Struct([Vector.ivec2(), Scalar.double()], buffer_layout, member_names=["a", "b"], type_name="structA") structB = Struct([Scalar.uint(), Scalar.double()], buffer_layout, type_name="structB") structC = Struct([structB, Vector.ivec2()], buffer_layout, type_name="structC") structs = [structA, structB, structC] variables = [ Vector.vec3(), Vector.ivec4(), Array(structC, 2, buffer_layout), Vector.ivec4(), Scalar.uint(), Array(Scalar.double(), (5, 2), buffer_layout), Scalar.int(), Array(Vector.vec4(), (2, 3, 4), buffer_layout), Vector.dvec2(), structA ] container = Struct(variables, buffer_layout, type_name="block") print(container) glsl = self.build_glsl_program(container, structs, buffer_usage) # print(glsl) values, array_expected = self.build_values(container.definitions) array_expected = np.array(array_expected, dtype=np.float32) bytez_input = container.to_bytes(values) bytez_output = self.run_program(glsl, bytez_input, array_expected.nbytes, usage_input=buffer_usage) array = np.frombuffer(bytez_output, dtype=array_expected.dtype) print(array_expected) print(array) print("equal", ((array_expected - array) == 0).all())
def test_detection_type_arrays(self): rng = np.random.RandomState(321) variables = [ Scalar.uint(), Scalar.int(), Scalar.float(), Scalar.double() ] variables += [ Vector(n, dtype) for n, dtype in itertools.product(range(2, 5), DataType.ALL) ] for definition, layout, _ in itertools.product( variables, [Layout.STD140, Layout.STD430], range(3)): container = Struct( [Array(definition, Random.shape(rng, 3, 5), layout)], layout) glsl = self.build_glsl_program( ((container, 0, BufferUsage.STORAGE_BUFFER), )) shader = self.shader_from_txt(glsl, verbose=False) shader.inspect() detected_definition, _ = shader.get_block(0) self.assertTrue(container.compare(detected_definition, quiet=True)) if isinstance(definition, Vector): if definition.length( ) < 3 and definition.dtype != DataType.DOUBLE: self.assertEqual(detected_definition.layout, layout)
def test_nested_with_arrays_of_structs(self): rng = np.random.RandomState(123) simple = [Scalar.uint(), Scalar.int(), Scalar.float(), Scalar.double()] simple += [ Vector(n, dtype) for n, dtype in itertools.product(range(2, 5), DataType.ALL) ] for layout, _ in itertools.product([Layout.STD140, Layout.STD430], range(10)): matrices = [ Matrix(n, m, dtype, layout) for n, m, dtype in itertools.product(range(2, 5), range( 2, 5), [DataType.FLOAT, DataType.DOUBLE]) ] simple_and_matrices = simple + matrices struct = Struct(rng.choice(simple_and_matrices, size=4, replace=False), layout, type_name="SomeStruct") structs = [struct] arrays = [Array(struct, Random.shape(rng, 2, 3), layout)] for _ in range(2): members = [arrays[-1]] + rng.choice( simple_and_matrices, size=3, replace=False).tolist() structs.append( Struct(rng.permutation(members), layout, type_name="SomeStruct{}".format(len(structs)))) arrays.append( Array(structs[-1], Random.shape(rng, 2, 3), layout)) container = structs[-1] structs = structs[:-1] self.run_test(container, structs, BufferUsage.STORAGE_BUFFER) if layout == Layout.STD140: self.run_test(container, structs, BufferUsage.UNIFORM_BUFFER)
def test_manually(self): # byte cache test buffer_usage = BufferUsage.STORAGE_BUFFER buffer_layout = Layout.STD430 buffer_order = Order.ROW_MAJOR struct1 = Struct([Vector.vec3(), Vector.ivec2()], buffer_layout, member_names=["a", "b"], type_name="structB") struct2 = Struct( [Scalar.double(), Scalar.double(), struct1], buffer_layout, type_name="structC") structs = [struct1, struct2] variables = [ Scalar.uint(), Array(Vector.vec2(), (5, 2, 3), buffer_layout), Array(Scalar.float(), 5, buffer_layout), struct2, # this struct needs padding at the end Scalar.uint(), Array(struct1, (2, 3), buffer_layout) ] container = Struct(variables, buffer_layout, type_name="block") cache = ByteCache(container) print("") print("") pprint.pprint(cache.values) print(cache[-1][0][0]["a"]) print("") print("") pprint.pprint(cache) print(cache[-1][0][0]) print("") print("") pprint.pprint(cache.get_as_dict())
def test_array_of_matrices(self): # skipping ROW_MAJOR order for now since the glsl generation does not support it rng = np.random.RandomState(123) matrix_combinations = itertools.product(range(2, 5), range( 2, 5), [DataType.FLOAT, DataType.DOUBLE]) for (n, m, dtype), layout, _ in itertools.product( matrix_combinations, [Layout.STD140, Layout.STD430], range(3)): matrix = Matrix(n, m, dtype, layout) container = Struct( [Array(matrix, Random.shape(rng, 3, 5), layout)], layout) self.run_test(container, [], BufferUsage.STORAGE_BUFFER)
def test_copy(self): data = np.arange(128, dtype=np.float32) definition = Struct([Array(ScalarFloat(), len(data), Layout.STD140)], Layout.STD140) buffer_a = lv.BufferCPU(self.session, definition, lv.BufferCPU.USAGE_STORAGE) buffer_b = lv.BufferCPU(self.session, definition, lv.BufferCPU.USAGE_STORAGE) buffer_a[0] = data buffer_a.flush() buffer_a.copy_to(buffer_b) buffer_b.fetch() self.assertTrue((buffer_a[0] == buffer_b[0]).all())
def test_detection_type_arrays_of_matrices(self): rng = np.random.RandomState(321) matrix_attributes = itertools.product(range(2, 5), range(2, 5), [DataType.FLOAT, DataType.DOUBLE]) for (n, m, dtype), layout, _ in itertools.product(matrix_attributes, [Layout.STD140, Layout.STD430], range(3)): matrix = Matrix(n, m, dtype, layout) container = Struct([Array(matrix, Random.shape(rng, 3, 5), layout)], layout) glsl = self.build_glsl_program(((container, 0, BufferUsage.STORAGE_BUFFER),)) shader = self.shader_from_txt(glsl, verbose=False) shader.inspect() detected_definition, _ = shader.code.get_block(0) self.assertTrue(container.compare(detected_definition, quiet=True))
def test_array_of_vectors(self): rng = np.random.RandomState(123) vector_types = [ Vector(n, dtype) for n, dtype in itertools.product(range(2, 5), DataType.ALL) ] for definition, layout, _ in itertools.product( vector_types, [Layout.STD140, Layout.STD430], range(5)): container = Struct( [Array(definition, Random.shape(rng, 3, 5), layout)], layout) self.run_test(container, [], BufferUsage.STORAGE_BUFFER) if layout == Layout.STD140: self.run_test(container, [], BufferUsage.UNIFORM_BUFFER)
def test_array_of_scalars(self): rng = np.random.RandomState(123) scalar_types = [ Scalar.uint(), Scalar.int(), Scalar.float(), Scalar.double() ] for definition, layout, _ in itertools.product( scalar_types, [Layout.STD140, Layout.STD430], range(5)): container = Struct( [Array(definition, Random.shape(rng, 5, 7), layout)], layout) self.run_test(container, [], BufferUsage.STORAGE_BUFFER) if layout == Layout.STD140: self.run_test(container, [], BufferUsage.UNIFORM_BUFFER)
def test_array_of_structs(self): rng = np.random.RandomState(123) simple = [Scalar.uint(), Scalar.int(), Scalar.float(), Scalar.double()] simple += [ Vector(n, dtype) for n, dtype in itertools.product(range(2, 5), DataType.ALL) ] for layout, _ in itertools.product([Layout.STD140, Layout.STD430], range(5)): struct = Struct(rng.choice(simple, size=3, replace=False), layout, type_name="SomeStruct") array = Array(struct, Random.shape(rng, 3, 5), layout) container = Struct([array], layout) self.run_test(container, [struct], BufferUsage.STORAGE_BUFFER) if layout == Layout.STD140: self.run_test(container, [struct], BufferUsage.UNIFORM_BUFFER)
def test_definition_check(self): glsl = """ #version 450 #extension GL_ARB_separate_shader_objects : enable layout(std140, binding = 0) buffer BufferA { float[720][1280][3] image; }; void main() {} """ shader = self.shader_from_txt(glsl, verbose=False) incompatible_definition = Struct( [Array(ScalarFloat(), (721, 1281, 4), Layout.STD140)], Layout.STD140) incompatible_buffer = lv.BufferCPU(self.session, incompatible_definition, lv.BufferCPU.USAGE_STORAGE) self.assertRaises(LavaError, lv.Stage, shader=shader, bindings={0: incompatible_buffer})
def deduce_definition(self, index, definitions_scalar, definitions_vector, definitions_array, definitions_struct, last_struct=None): default_layout = Layout.STD140 if index in self.byte_code.types_array: type_index, dims = self.byte_code.types_array[index] # build missing definition if type_index in self.byte_code.types_struct and type_index not in definitions_struct: self.deduce_definition(type_index, definitions_scalar, definitions_vector, definitions_array, definitions_struct, last_struct) definition = None # matrix types are shared, but still affected by the layout, create a instance for every occurrence if type_index in self.byte_code.types_matrix: definition = self.build_matrix_definition( type_index, default_layout, last_struct) definition = definition or definitions_scalar.get(type_index) definition = definition or definitions_vector.get(type_index) definition = definition or definitions_struct.get(type_index) definitions_array[index] = Array(definition.copy(), dims, default_layout) elif index in self.byte_code.types_struct: member_indices = self.byte_code.types_struct[index] # build missing definitions for member_index in member_indices: is_struct = member_index in self.byte_code.types_struct is_array = member_index in self.byte_code.types_array defs = { "definitions_scalar": definitions_scalar, "definitions_vector": definitions_vector, "definitions_array": definitions_array, "definitions_struct": definitions_struct } if is_struct and member_index not in definitions_struct: self.deduce_definition(member_index, last_struct=member_index, **defs) if is_array and member_index not in definitions_array: self.deduce_definition(member_index, last_struct=index, **defs) definitions = [] for member_index in member_indices: definition = None # matrix types are shared, but still affected by the layout, create a instance for every occurrence if member_index in self.byte_code.types_matrix: definition = self.build_matrix_definition( member_index, default_layout, last_struct) definition = definition or definitions_scalar.get(member_index) definition = definition or definitions_vector.get(member_index) definition = definition or definitions_array.get(member_index) definition = definition or definitions_struct.get(member_index) definitions.append(definition.copy()) struct_name, member_names = self.byte_code.find_names(index) definitions_struct[index] = Struct(definitions, default_layout, member_names=member_names, type_name=struct_name) else: raise ByteCodeError.unexpected()
def test_manually(self): buffer_usage = BufferUsage.STORAGE_BUFFER buffer_layout = Layout.STD140 buffer_order = Order.ROW_MAJOR structA = Struct([Vector.ivec2(), Scalar.double()], buffer_layout, member_names=["a", "b"], type_name="structA") structB = Struct([Scalar.uint(), Scalar.double()], buffer_layout, type_name="structB") structC = Struct([structB, Vector.ivec2()], buffer_layout, type_name="structC") structs = [structA, structB, structC] variables = [ Vector.vec3(), Vector.ivec4(), Array(structC, 2, buffer_layout), Vector.ivec4(), Scalar.uint(), Array(Scalar.double(), (5, 2), buffer_layout), Scalar.int(), Array(Vector.vec4(), (2, 3, 4), buffer_layout), Vector.dvec2(), structA ] container = Struct(variables, buffer_layout, type_name="block") print(container) glsl = self.build_glsl_program(container, structs, buffer_usage) # print(glsl) values_expected, array = self.build_values(container.definitions) array = np.array(array, dtype=np.float32) bytez_in = array.tobytes() # std430 bytez_out = self.run_program(glsl, bytez_in, container.size()) values = container.from_bytes(bytez_out) register = {} steps = {Scalar: 0, Vector: 0, Array: 0, Struct: 0} for struct in structs + [container]: self.build_register(register, struct, steps) values_ftd = self.format_values(container, values, register) values_expected_ftd = self.format_values(container, values_expected, register) print("") self.print_formatted_values(values_ftd) print("") self.print_formatted_values(values_expected_ftd) print("") print("") print(values_ftd == values_expected_ftd)