From d488d0fd7baff77204dbd3fd0d625b5974728534 Mon Sep 17 00:00:00 2001 From: Rhys Perry Date: Fri, 14 Feb 2020 11:32:18 +0000 Subject: [PATCH] aco: add framework for testing isel and integration tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit And add some simple tests to demonstrate/test the pipeline builder and glsl_scraper.py. Signed-off-by: Rhys Perry Acked-by: Samuel Pitoiset Acked-by: Daniel Schürmann Acked-by: Timur Kristóf Part-of: --- meson.build | 4 + meson_options.txt | 2 +- src/amd/compiler/tests/glsl_scraper.py | 339 ++++++++++++++ src/amd/compiler/tests/helpers.cpp | 605 +++++++++++++++++++++++++ src/amd/compiler/tests/helpers.h | 103 +++++ src/amd/compiler/tests/meson.build | 15 +- src/amd/compiler/tests/test_isel.cpp | 82 ++++ src/vulkan/overlay-layer/meson.build | 4 +- 8 files changed, 1148 insertions(+), 6 deletions(-) create mode 100644 src/amd/compiler/tests/glsl_scraper.py create mode 100644 src/amd/compiler/tests/test_isel.cpp diff --git a/meson.build b/meson.build index fc6eecaeaa9..011b1eca832 100644 --- a/meson.build +++ b/meson.build @@ -543,6 +543,10 @@ if with_gallium_zink dep_vulkan = dependency('vulkan') endif +if with_vulkan_overlay_layer or with_aco_tests + prog_glslang = find_program('glslangValidator') +endif + _xvmc = get_option('gallium-xvmc') if _xvmc == 'true' _xvmc = 'enabled' diff --git a/meson_options.txt b/meson_options.txt index 63290eba415..ae0e7cc1d71 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -292,7 +292,7 @@ option( 'build-aco-tests', type : 'boolean', value : false, - description : 'Build ACO tests. These do not require an AMD GPU.' + description : 'Build ACO tests. These require RADV and glslang but not an AMD GPU.' ) option( 'install-intel-gpu-tests', diff --git a/src/amd/compiler/tests/glsl_scraper.py b/src/amd/compiler/tests/glsl_scraper.py new file mode 100644 index 00000000000..c2ca6ebb93e --- /dev/null +++ b/src/amd/compiler/tests/glsl_scraper.py @@ -0,0 +1,339 @@ +#! /usr/bin/env python3 +# Taken from Crucible and modified to parse declarations + +import argparse +import io +import os +import re +import shutil +import struct +import subprocess +import sys +import tempfile +from textwrap import dedent + +class ShaderCompileError(RuntimeError): + def __init__(self, *args): + super(ShaderCompileError, self).__init__(*args) + +target_env_re = re.compile(r'QO_TARGET_ENV\s+(\S+)') + +stage_to_glslang_stage = { + 'VERTEX': 'vert', + 'TESS_CONTROL': 'tesc', + 'TESS_EVALUATION': 'tese', + 'GEOMETRY': 'geom', + 'FRAGMENT': 'frag', + 'COMPUTE': 'comp', +} + +base_layout_qualifier_id_re = r'({0}\s*=\s*(?P<{0}>\d+))' +id_re = '(?P[^(gl_)]\S+)' +type_re = '(?P\S+)' +location_re = base_layout_qualifier_id_re.format('location') +component_re = base_layout_qualifier_id_re.format('component') +binding_re = base_layout_qualifier_id_re.format('binding') +set_re = base_layout_qualifier_id_re.format('set') +unk_re = r'\S+(=\d+)?' +layout_qualifier_re = r'layout\W*\((%s)+\)' % '|'.join([location_re, binding_re, set_re, unk_re, '[, ]+']) +ubo_decl_re = 'uniform\W+%s(\W*{)?(?P)' % (id_re%0) +ssbo_decl_re = 'buffer\W+%s(\W*{)?(?P)' % (id_re%1) +image_buffer_decl_re = r'uniform\W+imageBuffer\w+%s;(?P)' % (id_re%2) +image_decl_re = r'uniform\W+image\S+\W+%s;(?P)' % (id_re%3) +texture_buffer_decl_re = r'uniform\W+textureBuffer\w+%s;(?P)' % (id_re%4) +combined_texture_sampler_decl_re = r'uniform\W+sampler\S+\W+%s;(?P)' % (id_re%5) +texture_decl_re = r'uniform\W+texture\S+\W+%s;(?P)' % (id_re%6) +sampler_decl_re = r'uniform\W+sampler\w+%s;(?P)' % (id_re%7) +input_re = r'in\W+%s\W+%s;(?P)' % (type_re%0, id_re%8) +output_re = r'out\W+%s\W+%s;(?P)' % (type_re%1, id_re%9) +match_decl_re = re.compile(layout_qualifier_re + r'\W*((' + r')|('.join([ubo_decl_re, ssbo_decl_re, image_buffer_decl_re, image_decl_re, texture_buffer_decl_re, combined_texture_sampler_decl_re, texture_decl_re, sampler_decl_re, input_re, output_re]) + r'))$') + +class Shader: + def __init__(self, stage): + self.glsl = None + self.stream = io.StringIO() + self.stage = stage + self.dwords = None + self.target_env = "" + self.declarations = [] + + def add_text(self, s): + self.stream.write(s) + + def finish_text(self, start_line, end_line): + self.glsl = self.stream.getvalue() + self.stream = None + + # Handle the QO_EXTENSION macro + self.glsl = self.glsl.replace('QO_EXTENSION', '#extension') + + # Handle the QO_DEFINE macro + self.glsl = self.glsl.replace('QO_DEFINE', '#define') + + m = target_env_re.search(self.glsl) + if m: + self.target_env = m.group(1) + self.glsl = self.glsl.replace('QO_TARGET_ENV', '// --target-env') + + self.start_line = start_line + self.end_line = end_line + + def __run_glslang(self, extra_args=[]): + stage = stage_to_glslang_stage[self.stage] + stage_flags = ['-S', stage] + + in_file = tempfile.NamedTemporaryFile(suffix='.'+stage) + src = ('#version 450\n' + self.glsl).encode('utf-8') + in_file.write(src) + in_file.flush() + out_file = tempfile.NamedTemporaryFile(suffix='.spirv') + args = [glslang, '-H'] + extra_args + stage_flags + if self.target_env: + args += ['--target-env', self.target_env] + args += ['-o', out_file.name, in_file.name] + with subprocess.Popen(args, + stdout = subprocess.PIPE, + stderr = subprocess.PIPE, + stdin = subprocess.PIPE) as proc: + + out, err = proc.communicate(timeout=30) + in_file.close() + + if proc.returncode != 0: + # Unfortunately, glslang dumps errors to standard out. + # However, since we don't really want to count on that, + # we'll grab the output of both + message = out.decode('utf-8') + '\n' + err.decode('utf-8') + raise ShaderCompileError(message.strip()) + + out_file.seek(0) + spirv = out_file.read() + out_file.close() + return (spirv, out) + + def _parse_declarations(self): + for line in self.glsl.splitlines(): + res = re.match(match_decl_re, line.lstrip().rstrip()) + if res == None: + continue + res = {k:v for k, v in res.groupdict().items() if v != None} + name = [v for k, v in res.items() if k.startswith('name_')][0] + data_type = ([v for k, v in res.items() if k.startswith('dtype_')] + [''])[0] + decl_type = [k for k, v in res.items() if k.startswith('type_')][0][5:] + location = int(res.get('location', 0)) + component = int(res.get('component', 0)) + binding = int(res.get('binding', 0)) + desc_set = int(res.get('set', 0)) + self.declarations.append('{"%s", "%s", QoShaderDeclType_%s, %d, %d, %d, %d}' % + (name, data_type, decl_type, location, component, binding, desc_set)) + + def compile(self): + def dwords(f): + while True: + dword_str = f.read(4) + if not dword_str: + return + assert len(dword_str) == 4 + yield struct.unpack('I', dword_str)[0] + + (spirv, assembly) = self.__run_glslang() + self.dwords = list(dwords(io.BytesIO(spirv))) + self.assembly = str(assembly, 'utf-8') + + self._parse_declarations() + + def _dump_glsl_code(self, f): + # Dump GLSL code for reference. Use // instead of /* */ + # comments so we don't need to escape the GLSL code. + f.write('// GLSL code:\n') + f.write('//') + for line in self.glsl.splitlines(): + f.write('\n// {0}'.format(line)) + f.write('\n\n') + + def _dump_spirv_code(self, f, var_name): + f.write('/* SPIR-V Assembly:\n') + f.write(' *\n') + for line in self.assembly.splitlines(): + f.write(' * ' + line + '\n') + f.write(' */\n') + + f.write('static const uint32_t {0}[] = {{'.format(var_name)) + line_start = 0 + while line_start < len(self.dwords): + f.write('\n ') + for i in range(line_start, min(line_start + 6, len(self.dwords))): + f.write(' 0x{:08x},'.format(self.dwords[i])) + line_start += 6 + f.write('\n};\n') + + def dump_c_code(self, f): + f.write('\n\n') + var_prefix = '__qonos_shader{0}'.format(self.end_line) + + self._dump_glsl_code(f) + self._dump_spirv_code(f, var_prefix + '_spir_v_src') + f.write('static const QoShaderDecl {0}_decls[] = {{{1}}};\n'.format(var_prefix, ', '.join(self.declarations))) + + f.write(dedent("""\ + static const QoShaderModuleCreateInfo {0}_info = {{ + .spirvSize = sizeof({0}_spir_v_src), + .pSpirv = {0}_spir_v_src, + .declarationCount = sizeof({0}_decls) / sizeof({0}_decls[0]), + .pDeclarations = {0}_decls, + """.format(var_prefix))) + + f.write(" .stage = VK_SHADER_STAGE_{0}_BIT,\n".format(self.stage)) + + f.write('};\n') + + f.write('#define __qonos_shader{0}_info __qonos_shader{1}_info\n'\ + .format(self.start_line, self.end_line)) + +token_exp = re.compile(r'(qoShaderModuleCreateInfoGLSL|qoCreateShaderModuleGLSL|\(|\)|,)') + +class Parser: + def __init__(self, f): + self.infile = f + self.paren_depth = 0 + self.shader = None + self.line_number = 1 + self.shaders = [] + + def tokenize(f): + leftover = '' + for line in f: + pos = 0 + while True: + m = token_exp.search(line, pos) + if m: + if m.start() > pos: + leftover += line[pos:m.start()] + pos = m.end() + + if leftover: + yield leftover + leftover = '' + + yield m.group(0) + + else: + leftover += line[pos:] + break + + self.line_number += 1 + + if leftover: + yield leftover + + self.token_iter = tokenize(self.infile) + + def handle_shader_src(self): + paren_depth = 1 + for t in self.token_iter: + if t == '(': + paren_depth += 1 + elif t == ')': + paren_depth -= 1 + if paren_depth == 0: + return + + self.current_shader.add_text(t) + + def handle_macro(self, macro): + t = next(self.token_iter) + assert t == '(' + + start_line = self.line_number + + if macro == 'qoCreateShaderModuleGLSL': + # Throw away the device parameter + t = next(self.token_iter) + t = next(self.token_iter) + assert t == ',' + + stage = next(self.token_iter).strip() + + t = next(self.token_iter) + assert t == ',' + + self.current_shader = Shader(stage) + self.handle_shader_src() + self.current_shader.finish_text(start_line, self.line_number) + + self.shaders.append(self.current_shader) + self.current_shader = None + + def run(self): + for t in self.token_iter: + if t in ('qoShaderModuleCreateInfoGLSL', 'qoCreateShaderModuleGLSL'): + self.handle_macro(t) + +def open_file(name, mode): + if name == '-': + if mode == 'w': + return sys.stdout + elif mode == 'r': + return sys.stdin + else: + assert False + else: + return open(name, mode) + +def parse_args(): + description = dedent("""\ + This program scrapes a C file for any instance of the + qoShaderModuleCreateInfoGLSL and qoCreateShaderModuleGLSL macaros, + grabs the GLSL source code, compiles it to SPIR-V. The resulting + SPIR-V code is written to another C file as an array of 32-bit + words. + + If '-' is passed as the input file or output file, stdin or stdout + will be used instead of a file on disc.""") + + p = argparse.ArgumentParser( + description=description, + formatter_class=argparse.RawDescriptionHelpFormatter) + p.add_argument('-o', '--outfile', default='-', + help='Output to the given file (default: stdout).') + p.add_argument('--with-glslang', metavar='PATH', + default='glslangValidator', + dest='glslang', + help='Full path to the glslangValidator shader compiler.') + p.add_argument('infile', metavar='INFILE') + + return p.parse_args() + + +args = parse_args() +infname = args.infile +outfname = args.outfile +glslang = args.glslang + +with open_file(infname, 'r') as infile: + parser = Parser(infile) + parser.run() + +for shader in parser.shaders: + shader.compile() + +with open_file(outfname, 'w') as outfile: + outfile.write(dedent("""\ + /* ========================== DO NOT EDIT! ========================== + * This file is autogenerated by glsl_scraper.py. + */ + + #include + + #define __QO_SHADER_INFO_VAR2(_line) __qonos_shader ## _line ## _info + #define __QO_SHADER_INFO_VAR(_line) __QO_SHADER_INFO_VAR2(_line) + + #define qoShaderModuleCreateInfoGLSL(stage, ...) \\ + __QO_SHADER_INFO_VAR(__LINE__) + + #define qoCreateShaderModuleGLSL(dev, stage, ...) \\ + __qoCreateShaderModule((dev), &__QO_SHADER_INFO_VAR(__LINE__)) + """)) + + for shader in parser.shaders: + shader.dump_c_code(outfile) diff --git a/src/amd/compiler/tests/helpers.cpp b/src/amd/compiler/tests/helpers.cpp index f2b7ec786ab..58539db074b 100644 --- a/src/amd/compiler/tests/helpers.cpp +++ b/src/amd/compiler/tests/helpers.cpp @@ -22,12 +22,21 @@ * */ #include "helpers.h" +#include "vulkan/vk_format.h" +#include "llvm/ac_llvm_util.h" #include #include #include +#include using namespace aco; +extern "C" { +PFN_vkVoidFunction VKAPI_CALL vk_icdGetInstanceProcAddr( + VkInstance instance, + const char* pName); +} + ac_shader_config config; radv_shader_info info; std::unique_ptr program; @@ -36,6 +45,35 @@ Temp inputs[16]; Temp exec_input; const char *subvariant = ""; +static VkInstance instance_cache[CHIP_LAST] = {VK_NULL_HANDLE}; +static VkDevice device_cache[CHIP_LAST] = {VK_NULL_HANDLE}; +static std::mutex create_device_mutex; + +#define FUNCTION_LIST\ + ITEM(CreateInstance)\ + ITEM(DestroyInstance)\ + ITEM(EnumeratePhysicalDevices)\ + ITEM(GetPhysicalDeviceProperties2)\ + ITEM(CreateDevice)\ + ITEM(DestroyDevice)\ + ITEM(CreateShaderModule)\ + ITEM(DestroyShaderModule)\ + ITEM(CreateGraphicsPipelines)\ + ITEM(CreateComputePipelines)\ + ITEM(DestroyPipeline)\ + ITEM(CreateDescriptorSetLayout)\ + ITEM(DestroyDescriptorSetLayout)\ + ITEM(CreatePipelineLayout)\ + ITEM(DestroyPipelineLayout)\ + ITEM(CreateRenderPass)\ + ITEM(DestroyRenderPass)\ + ITEM(GetPipelineExecutablePropertiesKHR)\ + ITEM(GetPipelineExecutableInternalRepresentationsKHR) + +#define ITEM(n) PFN_vk##n n; +FUNCTION_LIST +#undef ITEM + void create_program(enum chip_class chip_class, Stage stage, unsigned wave_size, enum radeon_family family) { memset(&config, 0, sizeof(config)); @@ -168,3 +206,570 @@ void writeout(unsigned i, Temp tmp) bld.pseudo(aco_opcode::p_unit_test, Operand(i)); } +VkDevice get_vk_device(enum chip_class chip_class) +{ + enum radeon_family family; + switch (chip_class) { + case GFX6: + family = CHIP_TAHITI; + break; + case GFX7: + family = CHIP_BONAIRE; + break; + case GFX8: + family = CHIP_POLARIS10; + break; + case GFX9: + family = CHIP_VEGA10; + break; + case GFX10: + family = CHIP_NAVI10; + break; + default: + family = CHIP_UNKNOWN; + break; + } + return get_vk_device(family); +} + +VkDevice get_vk_device(enum radeon_family family) +{ + assert(family != CHIP_UNKNOWN); + + std::lock_guard guard(create_device_mutex); + + if (device_cache[family]) + return device_cache[family]; + + setenv("RADV_FORCE_FAMILY", ac_get_llvm_processor_name(family), 1); + + VkApplicationInfo app_info = {}; + app_info.pApplicationName = "aco_tests"; + app_info.apiVersion = VK_API_VERSION_1_2; + VkInstanceCreateInfo instance_create_info = {}; + instance_create_info.pApplicationInfo = &app_info; + instance_create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; + VkResult result = ((PFN_vkCreateInstance)vk_icdGetInstanceProcAddr(NULL, "vkCreateInstance"))(&instance_create_info, NULL, &instance_cache[family]); + assert(result == VK_SUCCESS); + + #define ITEM(n) n = (PFN_vk##n)vk_icdGetInstanceProcAddr(instance_cache[family], "vk" #n); + FUNCTION_LIST + #undef ITEM + + uint32_t device_count = 1; + VkPhysicalDevice device = VK_NULL_HANDLE; + result = EnumeratePhysicalDevices(instance_cache[family], &device_count, &device); + assert(result == VK_SUCCESS); + assert(device != VK_NULL_HANDLE); + + VkDeviceCreateInfo device_create_info = {}; + device_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; + static const char *extensions[] = {"VK_KHR_pipeline_executable_properties"}; + device_create_info.enabledExtensionCount = sizeof(extensions) / sizeof(extensions[0]); + device_create_info.ppEnabledExtensionNames = extensions; + result = CreateDevice(device, &device_create_info, NULL, &device_cache[family]); + + return device_cache[family]; +} + +static struct DestroyDevices { + ~DestroyDevices() { + for (unsigned i = 0; i < CHIP_LAST; i++) { + if (!device_cache[i]) + continue; + DestroyDevice(device_cache[i], NULL); + DestroyInstance(instance_cache[i], NULL); + } + } +} destroy_devices; + +void print_pipeline_ir(VkDevice device, VkPipeline pipeline, VkShaderStageFlagBits stages, + const char *name, bool remove_encoding) +{ + uint32_t executable_count = 16; + VkPipelineExecutablePropertiesKHR executables[16]; + VkPipelineInfoKHR pipeline_info; + pipeline_info.sType = VK_STRUCTURE_TYPE_PIPELINE_INFO_KHR; + pipeline_info.pNext = NULL; + pipeline_info.pipeline = pipeline; + VkResult result = GetPipelineExecutablePropertiesKHR(device, &pipeline_info, &executable_count, executables); + assert(result == VK_SUCCESS); + + uint32_t executable = 0; + for (; executable < executable_count; executable++) { + if (executables[executable].stages == stages) + break; + } + assert(executable != executable_count); + + VkPipelineExecutableInfoKHR exec_info; + exec_info.sType = VK_STRUCTURE_TYPE_PIPELINE_EXECUTABLE_INFO_KHR; + exec_info.pNext = NULL; + exec_info.pipeline = pipeline; + exec_info.executableIndex = executable; + + uint32_t ir_count = 16; + VkPipelineExecutableInternalRepresentationKHR ir[16]; + memset(ir, 0, sizeof(ir)); + result = GetPipelineExecutableInternalRepresentationsKHR(device, &exec_info, &ir_count, ir); + assert(result == VK_SUCCESS); + + for (unsigned i = 0; i < ir_count; i++) { + if (strcmp(ir[i].name, name)) + continue; + + char *data = (char*)malloc(ir[i].dataSize); + ir[i].pData = data; + result = GetPipelineExecutableInternalRepresentationsKHR(device, &exec_info, &ir_count, ir); + assert(result == VK_SUCCESS); + + if (remove_encoding) { + for (char *c = data; *c; c++) { + if (*c == ';') { + for (; *c && *c != '\n'; c++) + *c = ' '; + } + } + } + + fprintf(output, "%s", data); + free(data); + return; + } +} + +VkShaderModule __qoCreateShaderModule(VkDevice dev, const QoShaderModuleCreateInfo *info) +{ + VkShaderModuleCreateInfo module_info; + module_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; + module_info.pNext = NULL; + module_info.flags = 0; + module_info.codeSize = info->spirvSize; + module_info.pCode = (const uint32_t*)info->pSpirv; + + VkShaderModule module; + VkResult result = CreateShaderModule(dev, &module_info, NULL, &module); + assert(result == VK_SUCCESS); + + return module; +} + +PipelineBuilder::PipelineBuilder(VkDevice dev) { + memset(this, 0, sizeof(*this)); + topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; + device = dev; +} + +PipelineBuilder::~PipelineBuilder() +{ + DestroyPipeline(device, pipeline, NULL); + + for (unsigned i = 0; i < (is_compute() ? 1 : gfx_pipeline_info.stageCount); i++) { + VkPipelineShaderStageCreateInfo *stage_info = &stages[i]; + if (owned_stages & stage_info->stage) + DestroyShaderModule(device, stage_info->module, NULL); + } + + DestroyPipelineLayout(device, pipeline_layout, NULL); + + for (unsigned i = 0; i < util_bitcount64(desc_layouts_used); i++) + DestroyDescriptorSetLayout(device, desc_layouts[i], NULL); + + DestroyRenderPass(device, render_pass, NULL); +} + +void PipelineBuilder::add_desc_binding(VkShaderStageFlags stage_flags, uint32_t layout, + uint32_t binding, VkDescriptorType type, uint32_t count) +{ + desc_layouts_used |= 1ull << layout; + desc_bindings[layout][num_desc_bindings[layout]++] = {binding, type, count, stage_flags, NULL}; +} + +void PipelineBuilder::add_vertex_binding(uint32_t binding, uint32_t stride, VkVertexInputRate rate) +{ + vs_bindings[vs_input.vertexBindingDescriptionCount++] = {binding, stride, rate}; +} + +void PipelineBuilder::add_vertex_attribute(uint32_t location, uint32_t binding, VkFormat format, uint32_t offset) +{ + vs_attributes[vs_input.vertexAttributeDescriptionCount++] = {location, binding, format, offset}; +} + +void PipelineBuilder::add_resource_decls(QoShaderModuleCreateInfo *module) +{ + for (unsigned i = 0; i < module->declarationCount; i++) { + const QoShaderDecl *decl = &module->pDeclarations[i]; + switch (decl->decl_type) { + case QoShaderDeclType_ubo: + add_desc_binding(module->stage, decl->set, decl->binding, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER); + break; + case QoShaderDeclType_ssbo: + add_desc_binding(module->stage, decl->set, decl->binding, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); + break; + case QoShaderDeclType_img_buf: + add_desc_binding(module->stage, decl->set, decl->binding, VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER); + break; + case QoShaderDeclType_img: + add_desc_binding(module->stage, decl->set, decl->binding, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE); + break; + case QoShaderDeclType_tex_buf: + add_desc_binding(module->stage, decl->set, decl->binding, VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER); + break; + case QoShaderDeclType_combined: + add_desc_binding(module->stage, decl->set, decl->binding, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER); + break; + case QoShaderDeclType_tex: + add_desc_binding(module->stage, decl->set, decl->binding, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE); + break; + case QoShaderDeclType_samp: + add_desc_binding(module->stage, decl->set, decl->binding, VK_DESCRIPTOR_TYPE_SAMPLER); + break; + default: + break; + } + } +} + +void PipelineBuilder::add_io_decls(QoShaderModuleCreateInfo *module) +{ + unsigned next_vtx_offset = 0; + for (unsigned i = 0; i < module->declarationCount; i++) { + const QoShaderDecl *decl = &module->pDeclarations[i]; + switch (decl->decl_type) { + case QoShaderDeclType_in: + if (module->stage == VK_SHADER_STAGE_VERTEX_BIT) { + if (!strcmp(decl->type, "float") || decl->type[0] == 'v') + add_vertex_attribute(decl->location, 0, VK_FORMAT_R32G32B32A32_SFLOAT, next_vtx_offset); + else if (decl->type[0] == 'u') + add_vertex_attribute(decl->location, 0, VK_FORMAT_R32G32B32A32_UINT, next_vtx_offset); + else if (decl->type[0] == 'i') + add_vertex_attribute(decl->location, 0, VK_FORMAT_R32G32B32A32_SINT, next_vtx_offset); + next_vtx_offset += 16; + } + break; + case QoShaderDeclType_out: + if (module->stage == VK_SHADER_STAGE_FRAGMENT_BIT) { + if (!strcmp(decl->type, "float") || decl->type[0] == 'v') + color_outputs[decl->location] = VK_FORMAT_R32G32B32A32_SFLOAT; + else if (decl->type[0] == 'u') + color_outputs[decl->location] = VK_FORMAT_R32G32B32A32_UINT; + else if (decl->type[0] == 'i') + color_outputs[decl->location] = VK_FORMAT_R32G32B32A32_SINT; + } + break; + default: + break; + } + } + if (next_vtx_offset) + add_vertex_binding(0, next_vtx_offset); +} + +void PipelineBuilder::add_stage(VkShaderStageFlagBits stage, VkShaderModule module, const char *name) +{ + VkPipelineShaderStageCreateInfo *stage_info; + if (stage == VK_SHADER_STAGE_COMPUTE_BIT) + stage_info = &stages[0]; + else + stage_info = &stages[gfx_pipeline_info.stageCount++]; + stage_info->sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + stage_info->pNext = NULL; + stage_info->flags = 0; + stage_info->stage = stage; + stage_info->module = module; + stage_info->pName = name; + stage_info->pSpecializationInfo = NULL; + owned_stages |= stage; +} + +void PipelineBuilder::add_vsfs(VkShaderModule vs, VkShaderModule fs) +{ + add_stage(VK_SHADER_STAGE_VERTEX_BIT, vs); + add_stage(VK_SHADER_STAGE_FRAGMENT_BIT, fs); +} + +void PipelineBuilder::add_vsfs(QoShaderModuleCreateInfo vs, QoShaderModuleCreateInfo fs) +{ + add_vsfs(__qoCreateShaderModule(device, &vs), __qoCreateShaderModule(device, &fs)); + add_resource_decls(&vs); + add_io_decls(&vs); + add_resource_decls(&fs); + add_io_decls(&fs); +} + +void PipelineBuilder::add_cs(VkShaderModule cs) +{ + add_stage(VK_SHADER_STAGE_COMPUTE_BIT, cs); +} + +void PipelineBuilder::add_cs(QoShaderModuleCreateInfo cs) +{ + add_cs(__qoCreateShaderModule(device, &cs)); + add_resource_decls(&cs); +} + +bool PipelineBuilder::is_compute() { + return gfx_pipeline_info.stageCount == 0; +} + +void PipelineBuilder::create_compute_pipeline() { + VkComputePipelineCreateInfo create_info; + create_info.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO; + create_info.pNext = NULL; + create_info.flags = VK_PIPELINE_CREATE_CAPTURE_INTERNAL_REPRESENTATIONS_BIT_KHR; + create_info.stage = stages[0]; + create_info.layout = pipeline_layout; + create_info.basePipelineHandle = VK_NULL_HANDLE; + create_info.basePipelineIndex = 0; + + VkResult result = CreateComputePipelines(device, VK_NULL_HANDLE, 1, &create_info, NULL, &pipeline); + assert(result == VK_SUCCESS); +} + +void PipelineBuilder::create_graphics_pipeline() { + /* create the create infos */ + if (!samples) + samples = VK_SAMPLE_COUNT_1_BIT; + + unsigned num_color_attachments = 0; + VkPipelineColorBlendAttachmentState blend_attachment_states[16]; + VkAttachmentReference color_attachments[16]; + VkAttachmentDescription attachment_descs[17]; + for (unsigned i = 0; i < 16; i++) { + if (color_outputs[i] == VK_FORMAT_UNDEFINED) + continue; + + VkAttachmentDescription *desc = &attachment_descs[num_color_attachments]; + desc->flags = 0; + desc->format = color_outputs[i]; + desc->samples = samples; + desc->loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; + desc->storeOp = VK_ATTACHMENT_STORE_OP_STORE; + desc->stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD; + desc->stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE; + desc->initialLayout = VK_IMAGE_LAYOUT_GENERAL; + desc->finalLayout = VK_IMAGE_LAYOUT_GENERAL; + + VkAttachmentReference *ref = &color_attachments[num_color_attachments]; + ref->attachment = num_color_attachments; + ref->layout = VK_IMAGE_LAYOUT_GENERAL; + + VkPipelineColorBlendAttachmentState *blend = &blend_attachment_states[num_color_attachments]; + blend->blendEnable = false; + blend->colorWriteMask = VK_COLOR_COMPONENT_R_BIT | + VK_COLOR_COMPONENT_G_BIT | + VK_COLOR_COMPONENT_B_BIT | + VK_COLOR_COMPONENT_A_BIT; + + num_color_attachments++; + } + + unsigned num_attachments = num_color_attachments; + VkAttachmentReference ds_attachment; + if (ds_output != VK_FORMAT_UNDEFINED) { + VkAttachmentDescription *desc = &attachment_descs[num_attachments]; + desc->flags = 0; + desc->format = ds_output; + desc->samples = samples; + desc->loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; + desc->storeOp = VK_ATTACHMENT_STORE_OP_STORE; + desc->stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD; + desc->stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE; + desc->initialLayout = VK_IMAGE_LAYOUT_GENERAL; + desc->finalLayout = VK_IMAGE_LAYOUT_GENERAL; + + ds_attachment.attachment = num_color_attachments; + ds_attachment.layout = VK_IMAGE_LAYOUT_GENERAL; + + num_attachments++; + } + + vs_input.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; + vs_input.pNext = NULL; + vs_input.flags = 0; + vs_input.pVertexBindingDescriptions = vs_bindings; + vs_input.pVertexAttributeDescriptions = vs_attributes; + + VkPipelineInputAssemblyStateCreateInfo assembly_state; + assembly_state.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; + assembly_state.pNext = NULL; + assembly_state.flags = 0; + assembly_state.topology = topology; + assembly_state.primitiveRestartEnable = false; + + VkPipelineTessellationStateCreateInfo tess_state; + tess_state.sType = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO; + tess_state.pNext = NULL; + tess_state.flags = 0; + tess_state.patchControlPoints = patch_size; + + VkPipelineViewportStateCreateInfo viewport_state; + viewport_state.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; + viewport_state.pNext = NULL; + viewport_state.flags = 0; + viewport_state.viewportCount = 1; + viewport_state.pViewports = NULL; + viewport_state.scissorCount = 1; + viewport_state.pScissors = NULL; + + VkPipelineRasterizationStateCreateInfo rasterization_state; + rasterization_state.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; + rasterization_state.pNext = NULL; + rasterization_state.flags = 0; + rasterization_state.depthClampEnable = false; + rasterization_state.rasterizerDiscardEnable = false; + rasterization_state.polygonMode = VK_POLYGON_MODE_FILL; + rasterization_state.cullMode = VK_CULL_MODE_NONE; + rasterization_state.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; + rasterization_state.depthBiasEnable = false; + rasterization_state.lineWidth = 1.0; + + VkPipelineMultisampleStateCreateInfo ms_state; + ms_state.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; + ms_state.pNext = NULL; + ms_state.flags = 0; + ms_state.rasterizationSamples = samples; + ms_state.sampleShadingEnable = sample_shading_enable; + ms_state.minSampleShading = min_sample_shading; + VkSampleMask sample_mask = 0xffffffff; + ms_state.pSampleMask = &sample_mask; + ms_state.alphaToCoverageEnable = false; + ms_state.alphaToOneEnable = false; + + VkPipelineDepthStencilStateCreateInfo ds_state; + ds_state.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; + ds_state.pNext = NULL; + ds_state.flags = 0; + ds_state.depthTestEnable = ds_output != VK_FORMAT_UNDEFINED; + ds_state.depthWriteEnable = true; + ds_state.depthCompareOp = VK_COMPARE_OP_ALWAYS; + ds_state.depthBoundsTestEnable = false; + ds_state.stencilTestEnable = true; + ds_state.front.failOp = VK_STENCIL_OP_KEEP; + ds_state.front.passOp = VK_STENCIL_OP_REPLACE; + ds_state.front.depthFailOp = VK_STENCIL_OP_REPLACE; + ds_state.front.compareOp = VK_COMPARE_OP_ALWAYS; + ds_state.front.compareMask = 0xffffffff, + ds_state.front.reference = 0; + ds_state.back = ds_state.front; + + VkPipelineColorBlendStateCreateInfo color_blend_state; + color_blend_state.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; + color_blend_state.pNext = NULL; + color_blend_state.flags = 0; + color_blend_state.logicOpEnable = false; + color_blend_state.attachmentCount = num_color_attachments; + color_blend_state.pAttachments = blend_attachment_states; + + VkDynamicState dynamic_states[9] = { + VK_DYNAMIC_STATE_VIEWPORT, + VK_DYNAMIC_STATE_SCISSOR, + VK_DYNAMIC_STATE_LINE_WIDTH, + VK_DYNAMIC_STATE_DEPTH_BIAS, + VK_DYNAMIC_STATE_BLEND_CONSTANTS, + VK_DYNAMIC_STATE_DEPTH_BOUNDS, + VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK, + VK_DYNAMIC_STATE_STENCIL_WRITE_MASK, + VK_DYNAMIC_STATE_STENCIL_REFERENCE + }; + + VkPipelineDynamicStateCreateInfo dynamic_state; + dynamic_state.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; + dynamic_state.pNext = NULL; + dynamic_state.flags = 0; + dynamic_state.dynamicStateCount = sizeof(dynamic_states) / sizeof(VkDynamicState); + dynamic_state.pDynamicStates = dynamic_states; + + gfx_pipeline_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; + gfx_pipeline_info.pNext = NULL; + gfx_pipeline_info.flags = VK_PIPELINE_CREATE_CAPTURE_INTERNAL_REPRESENTATIONS_BIT_KHR; + gfx_pipeline_info.pVertexInputState = &vs_input; + gfx_pipeline_info.pInputAssemblyState = &assembly_state; + gfx_pipeline_info.pTessellationState = &tess_state; + gfx_pipeline_info.pViewportState = &viewport_state; + gfx_pipeline_info.pRasterizationState = &rasterization_state; + gfx_pipeline_info.pMultisampleState = &ms_state; + gfx_pipeline_info.pDepthStencilState = &ds_state; + gfx_pipeline_info.pColorBlendState = &color_blend_state; + gfx_pipeline_info.pDynamicState = &dynamic_state; + gfx_pipeline_info.subpass = 0; + + /* create the objects used to create the pipeline */ + VkSubpassDescription subpass; + subpass.flags = 0; + subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; + subpass.inputAttachmentCount = 0; + subpass.pInputAttachments = NULL; + subpass.colorAttachmentCount = num_color_attachments; + subpass.pColorAttachments = color_attachments; + subpass.pResolveAttachments = NULL; + subpass.pDepthStencilAttachment = ds_output == VK_FORMAT_UNDEFINED ? NULL : &ds_attachment; + subpass.preserveAttachmentCount = 0; + subpass.pPreserveAttachments = NULL; + + VkRenderPassCreateInfo renderpass_info; + renderpass_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; + renderpass_info.pNext = NULL; + renderpass_info.flags = 0; + renderpass_info.attachmentCount = num_attachments; + renderpass_info.pAttachments = attachment_descs; + renderpass_info.subpassCount = 1; + renderpass_info.pSubpasses = &subpass; + renderpass_info.dependencyCount = 0; + renderpass_info.pDependencies = NULL; + + VkResult result = CreateRenderPass(device, &renderpass_info, NULL, &render_pass); + assert(result == VK_SUCCESS); + + gfx_pipeline_info.layout = pipeline_layout; + gfx_pipeline_info.renderPass = render_pass; + + /* create the pipeline */ + gfx_pipeline_info.pStages = stages; + + result = CreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, &gfx_pipeline_info, NULL, &pipeline); + assert(result == VK_SUCCESS); +} + +void PipelineBuilder::create_pipeline() { + unsigned num_desc_layouts = 0; + for (unsigned i = 0; i < 64; i++) { + if (!(desc_layouts_used & (1ull << i))) + continue; + + VkDescriptorSetLayoutCreateInfo desc_layout_info; + desc_layout_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; + desc_layout_info.pNext = NULL; + desc_layout_info.flags = 0; + desc_layout_info.bindingCount = num_desc_bindings[i]; + desc_layout_info.pBindings = desc_bindings[i]; + + VkResult result = CreateDescriptorSetLayout(device, &desc_layout_info, NULL, &desc_layouts[num_desc_layouts]); + assert(result == VK_SUCCESS); + num_desc_layouts++; + } + + VkPipelineLayoutCreateInfo pipeline_layout_info; + pipeline_layout_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; + pipeline_layout_info.pNext = NULL; + pipeline_layout_info.flags = 0; + pipeline_layout_info.pushConstantRangeCount = 1; + pipeline_layout_info.pPushConstantRanges = &push_constant_range; + pipeline_layout_info.setLayoutCount = num_desc_layouts; + pipeline_layout_info.pSetLayouts = desc_layouts; + + VkResult result = CreatePipelineLayout(device, &pipeline_layout_info, NULL, &pipeline_layout); + assert(result == VK_SUCCESS); + + if (is_compute()) + create_compute_pipeline(); + else + create_graphics_pipeline(); +} + +void PipelineBuilder::print_ir(VkShaderStageFlagBits stages, const char *name, bool remove_encoding) +{ + if (!pipeline) + create_pipeline(); + print_pipeline_ir(device, pipeline, stages, name, remove_encoding); +} diff --git a/src/amd/compiler/tests/helpers.h b/src/amd/compiler/tests/helpers.h index 50f50497951..6fa8f41a5ee 100644 --- a/src/amd/compiler/tests/helpers.h +++ b/src/amd/compiler/tests/helpers.h @@ -25,6 +25,40 @@ #define ACO_TEST_HELPERS_H #include "framework.h" +#include "vulkan/vulkan.h" + +enum QoShaderDeclType { + QoShaderDeclType_ubo, + QoShaderDeclType_ssbo, + QoShaderDeclType_img_buf, + QoShaderDeclType_img, + QoShaderDeclType_tex_buf, + QoShaderDeclType_combined, + QoShaderDeclType_tex, + QoShaderDeclType_samp, + QoShaderDeclType_in, + QoShaderDeclType_out, +}; + +struct QoShaderDecl { + const char *name; + const char *type; + QoShaderDeclType decl_type; + //TODO: array size? + unsigned location; + unsigned component; + unsigned binding; + unsigned set; +}; + +struct QoShaderModuleCreateInfo { + void *pNext; + size_t spirvSize; + const void *pSpirv; + uint32_t declarationCount; + const QoShaderDecl *pDeclarations; + VkShaderStageFlagBits stage; +}; extern ac_shader_config config; extern radv_shader_info info; @@ -47,4 +81,73 @@ void finish_assembler_test(); void writeout(unsigned i, aco::Temp tmp=aco::Temp(0, aco::s1)); +/* vulkan helpers */ +VkDevice get_vk_device(enum chip_class chip_class); +VkDevice get_vk_device(enum radeon_family family); + +void print_pipeline_ir(VkDevice device, VkPipeline pipeline, VkShaderStageFlagBits stages, + const char *name, bool remove_encoding=false); + +VkShaderModule __qoCreateShaderModule(VkDevice dev, const QoShaderModuleCreateInfo *info); + +class PipelineBuilder { +public: + /* inputs */ + VkDevice device; + VkFormat color_outputs[16]; + VkFormat ds_output; + VkPrimitiveTopology topology; + VkSampleCountFlagBits samples; + bool sample_shading_enable; + float min_sample_shading; + uint32_t patch_size; + VkPipelineVertexInputStateCreateInfo vs_input; + VkVertexInputBindingDescription vs_bindings[16]; + VkVertexInputAttributeDescription vs_attributes[16]; + VkPushConstantRange push_constant_range; + uint64_t desc_layouts_used; + unsigned num_desc_bindings[64]; + VkDescriptorSetLayoutBinding desc_bindings[64][64]; + VkPipelineShaderStageCreateInfo stages[5]; + VkShaderStageFlags owned_stages; + + /* outputs */ + VkGraphicsPipelineCreateInfo gfx_pipeline_info; + VkComputePipelineCreateInfo cs_pipeline_info; + VkDescriptorSetLayout desc_layouts[64]; + VkPipelineLayout pipeline_layout; + VkRenderPass render_pass; + VkPipeline pipeline; + + PipelineBuilder(VkDevice dev); + ~PipelineBuilder(); + + PipelineBuilder(const PipelineBuilder&) = delete; + PipelineBuilder& operator = (const PipelineBuilder&) = delete; + + void add_desc_binding(VkShaderStageFlags stage_flags, uint32_t layout, + uint32_t binding, VkDescriptorType type, uint32_t count=1); + + void add_vertex_binding(uint32_t binding, uint32_t stride, VkVertexInputRate rate=VK_VERTEX_INPUT_RATE_VERTEX); + void add_vertex_attribute(uint32_t location, uint32_t binding, VkFormat format, uint32_t offset); + + void add_resource_decls(QoShaderModuleCreateInfo *module); + void add_io_decls(QoShaderModuleCreateInfo *module); + + void add_stage(VkShaderStageFlagBits stage, VkShaderModule module, const char *name="main"); + void add_vsfs(VkShaderModule vs, VkShaderModule fs); + void add_vsfs(QoShaderModuleCreateInfo vs, QoShaderModuleCreateInfo fs); + void add_cs(VkShaderModule cs); + void add_cs(QoShaderModuleCreateInfo cs); + + bool is_compute(); + + void create_pipeline(); + + void print_ir(VkShaderStageFlagBits stages, const char *name, bool remove_encoding=false); +private: + void create_compute_pipeline(); + void create_graphics_pipeline(); +}; + #endif /* ACO_TEST_HELPERS_H */ diff --git a/src/amd/compiler/tests/meson.build b/src/amd/compiler/tests/meson.build index c63b860630a..bb8e7ca9288 100644 --- a/src/amd/compiler/tests/meson.build +++ b/src/amd/compiler/tests/meson.build @@ -23,15 +23,26 @@ aco_tests_files = files( 'helpers.h', 'main.cpp', 'test_assembler.cpp', + 'test_isel.cpp', 'test_optimizer.cpp', 'test_tests.cpp', ) +spirv_files = files( + 'test_isel.cpp', +) + +gen_spirv = generator(prog_python, + output : '@BASENAME@-spirv.h', + arguments : [join_paths(meson.current_source_dir(), 'glsl_scraper.py'), + '@INPUT@', '--with-glslang', prog_glslang.path(), '-o', '@OUTPUT@']) +gen_spirv_files = gen_spirv.process(spirv_files) + test( 'aco_tests', executable( 'aco_tests', - aco_tests_files, + [aco_tests_files, gen_spirv_files], cpp_args : ['-DACO_TEST_SOURCE_DIR="@0@"'.format(meson.current_source_dir()), '-DACO_TEST_BUILD_ROOT="@0@"'.format(meson.build_root()), '-DACO_TEST_PYTHON_BIN="@0@"'.format(prog_python.path())], @@ -39,7 +50,7 @@ test( inc_include, inc_src, inc_gallium, inc_compiler, inc_mesa, inc_mapi, inc_amd, inc_amd_common, inc_amd_common_llvm, ], link_with : [ - libamd_common, libamd_common_llvm + libamd_common, libamd_common_llvm, libvulkan_radeon, ], dependencies : [ dep_llvm, dep_thread, idep_aco, idep_nir, idep_mesautil diff --git a/src/amd/compiler/tests/test_isel.cpp b/src/amd/compiler/tests/test_isel.cpp new file mode 100644 index 00000000000..f45fe4311c0 --- /dev/null +++ b/src/amd/compiler/tests/test_isel.cpp @@ -0,0 +1,82 @@ +/* + * Copyright © 2020 Valve Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + */ +#include "helpers.h" +#include "test_isel-spirv.h" + +using namespace aco; + +BEGIN_TEST(isel.interp.simple) + QoShaderModuleCreateInfo vs = qoShaderModuleCreateInfoGLSL(VERTEX, + layout(location = 0) in vec4 in_color; + layout(location = 0) out vec4 out_color; + void main() { + out_color = in_color; + } + ); + QoShaderModuleCreateInfo fs = qoShaderModuleCreateInfoGLSL(FRAGMENT, + layout(location = 0) in vec4 in_color; + layout(location = 0) out vec4 out_color; + void main() { + //>> v1: %a_tmp = v_interp_p1_f32 %bx, %pm:m0 attr0.w + //! v1: %a = v_interp_p2_f32 %by, %pm:m0, %a_tmp attr0.w + //! v1: %b_tmp = v_interp_p1_f32 %bx, %pm:m0 attr0.z + //! v1: %b = v_interp_p2_f32 %by, %pm:m0, %b_tmp attr0.z + //! v1: %g_tmp = v_interp_p1_f32 %bx, %pm:m0 attr0.y + //! v1: %g = v_interp_p2_f32 %by, %pm:m0, %g_tmp attr0.y + //! v1: %r_tmp = v_interp_p1_f32 %bx, %pm:m0 attr0.x + //! v1: %r = v_interp_p2_f32 %by, %pm:m0, %r_tmp attr0.x + //! exp %r, %g, %b, %a mrt0 + out_color = in_color; + } + ); + + PipelineBuilder bld(get_vk_device(GFX9)); + bld.add_vsfs(vs, fs); + bld.print_ir(VK_SHADER_STAGE_FRAGMENT_BIT, "ACO IR"); +END_TEST + +BEGIN_TEST(isel.compute.simple) + for (unsigned i = GFX7; i <= GFX8; i++) { + if (!set_variant((chip_class)i)) + continue; + + QoShaderModuleCreateInfo cs = qoShaderModuleCreateInfoGLSL(COMPUTE, + layout(local_size_x=1) in; + layout(binding=0) buffer Buf { + uint res; + }; + void main() { + //~gfx7>> v1: %data = v_mov_b32 42 + //~gfx7>> buffer_store_dword %_, v1: undef, 0, %data disable_wqm storage:buffer semantics: scope:invocation + //~gfx8>> s1: %data = s_mov_b32 42 + //~gfx8>> s_buffer_store_dword %_, 0, %data storage:buffer semantics: scope:invocation + res = 42; + } + ); + + PipelineBuilder bld(get_vk_device((chip_class)i)); + bld.add_cs(cs); + bld.print_ir(VK_SHADER_STAGE_COMPUTE_BIT, "ACO IR", true); + } +END_TEST diff --git a/src/vulkan/overlay-layer/meson.build b/src/vulkan/overlay-layer/meson.build index 73e1e8346d3..3225b3f512b 100644 --- a/src/vulkan/overlay-layer/meson.build +++ b/src/vulkan/overlay-layer/meson.build @@ -18,8 +18,6 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. -glslang = find_program('glslangValidator') - overlay_shaders = [ 'overlay.frag', 'overlay.vert', @@ -28,7 +26,7 @@ overlay_spv = [] foreach s : ['overlay.frag', 'overlay.vert'] overlay_spv += custom_target( s + '.spv.h', input : s, output : s + '.spv.h', - command : [glslang, '-V', '-x', '-o', '@OUTPUT@', '@INPUT@']) + command : [prog_glslang, '-V', '-x', '-o', '@OUTPUT@', '@INPUT@']) endforeach vklayer_files = files(