import tempfile import unittest from tools.gen_vulkan_spv import DEFAULT_ENV, SPVGenerator #################### # Data for testing # #################### test_shader = """ #version 450 core #define FORMAT ${FORMAT} #define PRECISION ${PRECISION} #define OP(X) ${OPERATOR} $def is_int(dtype): $ return dtype in {"int", "int32", "int8"} $def is_uint(dtype): $ return dtype in {"uint", "uint32", "uint8"} $if is_int(DTYPE): #define VEC4_T ivec4 $elif is_uint(DTYPE): #define VEC4_T uvec4 $else: #define VEC4_T vec4 $if not INPLACE: $if is_int(DTYPE): layout(set = 0, binding = 0, FORMAT) uniform PRECISION restrict writeonly iimage3D uOutput; layout(set = 0, binding = 1) uniform PRECISION isampler3D uInput; $elif is_uint(DTYPE): layout(set = 0, binding = 0, FORMAT) uniform PRECISION restrict writeonly uimage3D uOutput; layout(set = 0, binding = 1) uniform PRECISION usampler3D uInput; $else: layout(set = 0, binding = 0, FORMAT) uniform PRECISION restrict writeonly image3D uOutput; layout(set = 0, binding = 1) uniform PRECISION sampler3D uInput; $else: $if is_int(DTYPE): layout(set = 0, binding = 0, FORMAT) uniform PRECISION restrict iimage3D uOutput; $elif is_uint(DTYPE): layout(set = 0, binding = 0, FORMAT) uniform PRECISION restrict uimage3D uOutput; $else: layout(set = 0, binding = 0, FORMAT) uniform PRECISION restrict image3D uOutput; layout(local_size_x_id = 0, local_size_y_id = 1, local_size_z_id = 2) in; void main() { const ivec3 pos = ivec3(gl_GlobalInvocationID); $if not INPLACE: VEC4_T v = texelFetch(uInput, pos, 0); $else: VEC4_T v = imageLoad(uOutput, pos); $for i in range(ITER[0]): for (int i = 0; i < ${ITER[1]}; ++i) { v = OP(v + i); } imageStore(uOutput, pos, OP(v)); } """ test_params_yaml = """ test_shader: parameter_names_with_default_values: DTYPE: float INPLACE: false OPERATOR: X + 3 ITER: !!python/tuple [3, 5] generate_variant_forall: INPLACE: - VALUE: false SUFFIX: "" - VALUE: true SUFFIX: inplace DTYPE: - VALUE: int8 - VALUE: float shader_variants: - NAME: test_shader_1 - NAME: test_shader_3 OPERATOR: X - 1 ITER: !!python/tuple [3, 2] generate_variant_forall: DTYPE: - VALUE: float - VALUE: int """ ############## # Unit Tests # ############## class TestVulkanSPVCodegen(unittest.TestCase): def setUp(self) -> None: self.tmpdir = tempfile.TemporaryDirectory() with open(f"{self.tmpdir.name}/test_shader.glsl,", "w") as f: f.write(test_shader) with open(f"{self.tmpdir.name}/test_params.yaml", "w") as f: f.write(test_params_yaml) self.tmpoutdir = tempfile.TemporaryDirectory() self.generator = SPVGenerator( src_dir_paths=self.tmpdir.name, env=DEFAULT_ENV, glslc_path=None ) def cleanUp(self) -> None: self.tmpdir.cleanup() self.tmpoutdir.cleanup() def testOutputMap(self) -> None: # Each shader variant will produce variants generated based on all possible combinations # of the DTYPE and INPLACE parameters. test_shader_3 has fewer generated variants due to # a custom specified generate_variant_forall field. expected_output_shaders = { "test_shader_1_float", "test_shader_1_inplace_float", "test_shader_1_inplace_int8", "test_shader_1_int8", "test_shader_3_float", "test_shader_3_int", } actual_output_shaders = set(self.generator.output_shader_map.keys()) self.assertEqual(expected_output_shaders, actual_output_shaders)