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_pass_through_array_of_vectors(self): glsl_template = """ #version 450 #extension GL_ARB_separate_shader_objects : enable layout(local_size_x=1, local_size_y=1, local_size_z=1) in; layout({layout_in}, binding = 0) buffer BufferA {{ {dtype}[720][1280] imageIn; }}; layout({layout_out}, binding = 1) buffer BufferB {{ {dtype}[720][1280] imageOut; }}; void main() {{ vec3 pixel = gl_GlobalInvocationID; int h = int(pixel.x); int w = int(pixel.y); imageOut[h][w] = imageIn[h][w]; }} """ rng = np.random.RandomState(123) w = 1280 h = 720 for layout_in, layout_out, n, dtype in itertools.product( self.LAYOUTS, self.LAYOUTS, range(2, 5), DataType.ALL): vector = Vector(n, dtype) im = rng.randint(0, 255, size=(h, w, n)).astype(vector.scalar.numpy_dtype()) glsl = glsl_template.format( **{ "layout_in": self.LAYOUT_MAP[layout_in], "layout_out": self.LAYOUT_MAP[layout_out], "dtype": vector.glsl_dtype() }) shader = self.shader_from_txt(glsl, verbose=False) shader.inspect() cache_in = ByteCache(shader.code.get_block_definition(0)) cache_in["imageIn"] = im bytez_in = cache_in.definition.to_bytes(cache_in.get_as_dict()) cache_out = ByteCache(shader.code.get_block_definition(1)) bytez_out_count = cache_out.definition.size() bytez_out = self.run_compiled_program(shader, bytez_in, bytez_out_count, groups=(h, w, 1)) cache_out.set_from_dict(cache_out.definition.from_bytes(bytez_out)) self.assertTrue((cache_out["imageOut"] == im).all())
def test_scalars_and_vectors(self): rng = np.random.RandomState(123) variables = [ Scalar.uint(), Scalar.int(), Scalar.float(), Scalar.double() ] variables += [ Vector(n, dtype) for n, dtype in itertools.product(range(2, 5), DataType.ALL) ] containers_std140 = [Struct(variables, Layout.STD140)] containers_std430 = [Struct(variables, Layout.STD430)] for _ in range(5): containers_std140.append( Struct(rng.permutation(variables), Layout.STD140)) containers_std430.append( Struct(rng.permutation(variables), Layout.STD430)) for container in containers_std140: self.run_test(container, [], BufferUsage.STORAGE_BUFFER) self.run_test(container, [], BufferUsage.UNIFORM_BUFFER) for container in containers_std430: self.run_test(container, [], BufferUsage.STORAGE_BUFFER)
def test_detection_layout_stdxxx_ssbo(self): variables = [ Scalar.uint(), Scalar.int(), Scalar.float(), Scalar.double() ] variables += [ Vector(n, dtype) for n, dtype in itertools.product(range(2, 5), DataType.ALL) ] binding = 0 usage = BufferUsage.STORAGE_BUFFER glsl_std140 = self.build_glsl_program( ((Struct(variables, Layout.STD140), binding, usage), )) glsl_std430 = self.build_glsl_program( ((Struct(variables, Layout.STD430), binding, usage), )) glsls = [glsl_std140, glsl_std430] for glsl in glsls: shader = self.shader_from_txt(glsl, verbose=False) shader.inspect() definition, detected_usage = shader.get_block(binding) self.assertEqual(detected_usage, usage) self.assertEqual(definition.layout, Layout.STDXXX)
def test_detection_type_nested_with_structs(self): rng = np.random.RandomState(321) 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)): 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=3, replace=False), layout, type_name="SomeStruct") structs = [struct] for _ in range(4): members = [structs[-1]] + rng.choice(simple_and_matrices, size=2, replace=False).tolist() structs.append(Struct(rng.permutation(members), layout, type_name="SomeStruct{}".format(len(structs)))) container = structs[-1] structs = structs[:-1] glsl = self.build_glsl_program(((container, 0, BufferUsage.STORAGE_BUFFER),), structs) shader = self.shader_from_txt(glsl, verbose=False) shader.inspect() definition, _ = shader.code.get_block(0) self.assertTrue(container.compare(definition, quiet=True))
def test_detection_layout_stdxxx_ubo(self): variables = [ Scalar.uint(), Scalar.int(), Scalar.float(), Scalar.double() ] variables += [ Vector(n, dtype) for n, dtype in itertools.product(range(2, 5), DataType.ALL) ] binding = 0 usage = BufferUsage.UNIFORM_BUFFER glsl = self.build_glsl_program( ((Struct(variables, Layout.STD140), binding, usage), )) shader = self.shader_from_txt(glsl, verbose=False) shader.inspect() definition, detected_usage = shader.get_block(binding) self.assertEqual(detected_usage, usage) self.assertEqual( definition.layout, Layout.STD140) # uniform buffer objects can not use std430
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_bytecode_parsing_without_gpu(self): with self.env_backup(): del os.environ["VULKAN_SDK"] import lava as lv from lava.api.bytecode.logical import ByteCode from lava.api.bytecode.physical import ByteCodeData from lava.api.bytes import Vector, Scalar, Struct from lava.api.constants.spirv import Layout self.assertTrue(not lv.initialized()) glsl = """ #version 450 #extension GL_ARB_separate_shader_objects : enable layout(local_size_x=1, local_size_y=1, local_size_z=1) in; layout(std430, binding = 0) readonly buffer bufIn { vec3 var1; }; layout(std430, binding = 1) writeonly buffer bufOut { float var2; }; void main() { var2 = var1.x + var1.y + var1.z; } """ path_shader = write_to_temp_file(glsl, suffix=".comp") path_shader_spirv = lv.compile_glsl(path_shader, verbose=True) with self.env_backup(): del os.environ["VULKAN_SDK"] self.assertTrue(not lv.initialized()) byte_code_data = ByteCodeData.from_file(path_shader_spirv) byte_code = ByteCode(byte_code_data, None) quiet = True container0 = Struct([Vector.vec3()], Layout.STD430) container1 = Struct([Scalar.float()], Layout.STD430) self.assertTrue( container0.compare(byte_code.get_block_definition(0), quiet=quiet)) self.assertTrue( container1.compare(byte_code.get_block_definition(1), quiet=quiet)) os.remove(path_shader) os.remove(path_shader_spirv)
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_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_detection_binding(self): container = Struct([Scalar.int(), Vector.vec3()], Layout.STD140) for binding, usage in itertools.product([0, 1, 2, 3, 4, 99, 512], [BufferUsage.UNIFORM_BUFFER, BufferUsage.STORAGE_BUFFER]): glsl = self.build_glsl_program(((container, binding, usage),)) shader = self.shader_from_txt(glsl, verbose=False) shader.inspect() detected_definition, detected_usage = shader.code.get_block(binding) self.assertEqual(detected_usage, usage) equal = container.compare(detected_definition, quiet=True) self.assertTrue(equal)
def test_struct_shared_between_different_layouts(self): glsl = """ #version 450 #extension GL_ARB_separate_shader_objects : enable struct Shared { int var1; double var2; }; layout(std140, binding = 0) buffer BufferA { uvec2 varA1; Shared varA2; // expected offset 16 }; layout(std430, binding = 1) buffer BufferB { uvec2 varB1; Shared varB2; // expected offset 8 }; void main() {} """ shared_std140 = Struct([Scalar.int(), Scalar.double()], Layout.STD140) shared_std430 = Struct([Scalar.int(), Scalar.double()], Layout.STD430) container_std140 = Struct([Vector.uvec2(), shared_std140], Layout.STD140) container_std430 = Struct([Vector.uvec2(), shared_std430], Layout.STD430) shader = self.shader_from_txt(glsl, verbose=False) shader.inspect() definition0, _ = shader.get_block(0) definition1, _ = shader.get_block(1) self.assertTrue(container_std140.compare(definition0, quiet=True)) self.assertFalse(container_std140.compare(definition1, quiet=True)) self.assertFalse(container_std430.compare(definition0, quiet=True)) self.assertTrue(container_std430.compare(definition1, 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_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_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_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 inspect(self): self.block_data = self.byte_code.find_blocks() self.definitions_block = {} defs_scalar = { index: Scalar.of(dtype) for index, dtype in self.byte_code.types_scalar.items() } defs_vector = { index: Vector(n, dtype) for index, (dtype, n) in self.byte_code.types_vector.items() } defs_array = {} defs_struct = {} for binding in self.get_bindings(): index, _ = self.get_block_index(binding) self.deduce_definition(index, defs_scalar, defs_vector, defs_array, defs_struct, index) self.definitions_block[index] = defs_struct[index] self.deduce_layout(binding)
def test_scalars_and_vectors_and_matrices(self): rng = np.random.RandomState(123) variables = [ Scalar.uint(), Scalar.int(), Scalar.float(), Scalar.double() ] variables += [ Vector(n, dtype) for n, dtype in itertools.product(range(2, 5), DataType.ALL) ] matrix_combinations = itertools.product(range(2, 5), range( 2, 5), [DataType.FLOAT, DataType.DOUBLE]) variables_std140 = variables + [ Matrix(n, m, dtype, Layout.STD140) for n, m, dtype in matrix_combinations ] variables_std430 = variables + [ Matrix(n, m, dtype, Layout.STD430) for n, m, dtype in matrix_combinations ] containers_std140 = [Struct(variables_std140, Layout.STD140)] containers_std430 = [Struct(variables_std430, Layout.STD430)] for _ in range(5): containers_std140.append( Struct(rng.permutation(variables_std140), Layout.STD140)) containers_std430.append( Struct(rng.permutation(variables_std430), Layout.STD430)) for container in containers_std140 + containers_std430: self.run_test(container, [], BufferUsage.STORAGE_BUFFER)
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)
def test_pass_through_struct(self): glsl_template = """ #version 450 #extension GL_ARB_separate_shader_objects : enable layout(local_size_x=1, local_size_y=1, local_size_z=1) in; {struct_glsl} layout({layout_in}, binding = 0) buffer BufferA {{ {dtype} structIn; }}; layout({layout_out}, binding = 1) buffer BufferB {{ {dtype} structOut; }}; void main() {{ structOut = structIn; }} """ rng = np.random.RandomState(123) scalars = [Scalar.of(dtype) for dtype in DataType.ALL] vectors = [ Vector(n, dtype) for n, dtype in itertools.product(range(2, 5), DataType.ALL) ] type_name = "SomeStruct" for layout_in, layout_out in itertools.product(self.LAYOUTS, self.LAYOUTS): members = rng.permutation(scalars + scalars + vectors + vectors) glsl_struct = ["struct {} {{".format(type_name)] for i, member in enumerate(members): glsl_struct.append("{} member{};".format( member.glsl_dtype(), i)) glsl_struct.append("};") glsl = glsl_template.format( **{ "layout_in": self.LAYOUT_MAP[layout_in], "layout_out": self.LAYOUT_MAP[layout_out], "struct_glsl": "\n".join(glsl_struct), "dtype": type_name }) shader = self.shader_from_txt(glsl, verbose=False) shader.inspect() cache_in = ByteCache(shader.code.get_block_definition(0)) for i, member in enumerate(members): if isinstance(member, Scalar): value = member.numpy_dtype()(1.) elif isinstance(member, Vector): value = np.ones(member.length(), member.scalar.numpy_dtype()) else: value = None cache_in["structIn"][i] = value bytez_in = cache_in.definition.to_bytes(cache_in.get_as_dict()) cache_out = ByteCache(shader.code.get_block_definition(1)) bytez_out_count = cache_out.definition.size() bytez_out = self.run_compiled_program(shader, bytez_in, bytez_out_count) cache_out.set_from_dict(cache_out.definition.from_bytes(bytez_out)) for i, member in enumerate(members): a = cache_in["structIn"][i] b = cache_out["structOut"][i] if isinstance(member, Vector): a = a.tolist() b = b.tolist() self.assertEqual(a, b)