17ec681f3Smrg/*
27ec681f3Smrg * Copyright © 2020 Valve Corporation
37ec681f3Smrg *
47ec681f3Smrg * Permission is hereby granted, free of charge, to any person obtaining a
57ec681f3Smrg * copy of this software and associated documentation files (the "Software"),
67ec681f3Smrg * to deal in the Software without restriction, including without limitation
77ec681f3Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
87ec681f3Smrg * and/or sell copies of the Software, and to permit persons to whom the
97ec681f3Smrg * Software is furnished to do so, subject to the following conditions:
107ec681f3Smrg *
117ec681f3Smrg * The above copyright notice and this permission notice (including the next
127ec681f3Smrg * paragraph) shall be included in all copies or substantial portions of the
137ec681f3Smrg * Software.
147ec681f3Smrg *
157ec681f3Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
167ec681f3Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
177ec681f3Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
187ec681f3Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
197ec681f3Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
207ec681f3Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
217ec681f3Smrg * IN THE SOFTWARE.
227ec681f3Smrg *
237ec681f3Smrg */
247ec681f3Smrg#include "helpers.h"
257ec681f3Smrg#include "vulkan/vk_format.h"
267ec681f3Smrg#include "common/amd_family.h"
277ec681f3Smrg#include <stdio.h>
287ec681f3Smrg#include <sstream>
297ec681f3Smrg#include <llvm-c/Target.h>
307ec681f3Smrg#include <mutex>
317ec681f3Smrg
327ec681f3Smrgusing namespace aco;
337ec681f3Smrg
347ec681f3Smrgextern "C" {
357ec681f3SmrgPFN_vkVoidFunction VKAPI_CALL vk_icdGetInstanceProcAddr(
367ec681f3Smrg	VkInstance                                  instance,
377ec681f3Smrg	const char*                                 pName);
387ec681f3Smrg}
397ec681f3Smrg
407ec681f3Smrgac_shader_config config;
417ec681f3Smrgradv_shader_info info;
427ec681f3Smrgstd::unique_ptr<Program> program;
437ec681f3SmrgBuilder bld(NULL);
447ec681f3SmrgTemp inputs[16];
457ec681f3Smrg
467ec681f3Smrgstatic VkInstance instance_cache[CHIP_LAST] = {VK_NULL_HANDLE};
477ec681f3Smrgstatic VkDevice device_cache[CHIP_LAST] = {VK_NULL_HANDLE};
487ec681f3Smrgstatic std::mutex create_device_mutex;
497ec681f3Smrg
507ec681f3Smrg#define FUNCTION_LIST\
517ec681f3Smrg   ITEM(CreateInstance)\
527ec681f3Smrg   ITEM(DestroyInstance)\
537ec681f3Smrg   ITEM(EnumeratePhysicalDevices)\
547ec681f3Smrg   ITEM(GetPhysicalDeviceProperties2)\
557ec681f3Smrg   ITEM(CreateDevice)\
567ec681f3Smrg   ITEM(DestroyDevice)\
577ec681f3Smrg   ITEM(CreateShaderModule)\
587ec681f3Smrg   ITEM(DestroyShaderModule)\
597ec681f3Smrg   ITEM(CreateGraphicsPipelines)\
607ec681f3Smrg   ITEM(CreateComputePipelines)\
617ec681f3Smrg   ITEM(DestroyPipeline)\
627ec681f3Smrg   ITEM(CreateDescriptorSetLayout)\
637ec681f3Smrg   ITEM(DestroyDescriptorSetLayout)\
647ec681f3Smrg   ITEM(CreatePipelineLayout)\
657ec681f3Smrg   ITEM(DestroyPipelineLayout)\
667ec681f3Smrg   ITEM(CreateRenderPass)\
677ec681f3Smrg   ITEM(DestroyRenderPass)\
687ec681f3Smrg   ITEM(GetPipelineExecutablePropertiesKHR)\
697ec681f3Smrg   ITEM(GetPipelineExecutableInternalRepresentationsKHR)
707ec681f3Smrg
717ec681f3Smrg#define ITEM(n) PFN_vk##n n;
727ec681f3SmrgFUNCTION_LIST
737ec681f3Smrg#undef ITEM
747ec681f3Smrg
757ec681f3Smrgvoid create_program(enum chip_class chip_class, Stage stage, unsigned wave_size, enum radeon_family family)
767ec681f3Smrg{
777ec681f3Smrg   memset(&config, 0, sizeof(config));
787ec681f3Smrg   info.wave_size = wave_size;
797ec681f3Smrg
807ec681f3Smrg   program.reset(new Program);
817ec681f3Smrg   aco::init_program(program.get(), stage, &info, chip_class, family, false, &config);
827ec681f3Smrg   program->workgroup_size = UINT_MAX;
837ec681f3Smrg   calc_min_waves(program.get());
847ec681f3Smrg
857ec681f3Smrg   program->debug.func = nullptr;
867ec681f3Smrg   program->debug.private_data = nullptr;
877ec681f3Smrg
887ec681f3Smrg   program->debug.output = output;
897ec681f3Smrg   program->debug.shorten_messages = true;
907ec681f3Smrg   program->debug.func = nullptr;
917ec681f3Smrg   program->debug.private_data = nullptr;
927ec681f3Smrg
937ec681f3Smrg   Block *block = program->create_and_insert_block();
947ec681f3Smrg   block->kind = block_kind_top_level;
957ec681f3Smrg
967ec681f3Smrg   bld = Builder(program.get(), &program->blocks[0]);
977ec681f3Smrg
987ec681f3Smrg   config.float_mode = program->blocks[0].fp_mode.val;
997ec681f3Smrg}
1007ec681f3Smrg
1017ec681f3Smrgbool setup_cs(const char *input_spec, enum chip_class chip_class,
1027ec681f3Smrg              enum radeon_family family, const char* subvariant,
1037ec681f3Smrg              unsigned wave_size)
1047ec681f3Smrg{
1057ec681f3Smrg   if (!set_variant(chip_class, subvariant))
1067ec681f3Smrg      return false;
1077ec681f3Smrg
1087ec681f3Smrg   memset(&info, 0, sizeof(info));
1097ec681f3Smrg   info.cs.block_size[0] = 1;
1107ec681f3Smrg   info.cs.block_size[1] = 1;
1117ec681f3Smrg   info.cs.block_size[2] = 1;
1127ec681f3Smrg
1137ec681f3Smrg   create_program(chip_class, compute_cs, wave_size, family);
1147ec681f3Smrg
1157ec681f3Smrg   if (input_spec) {
1167ec681f3Smrg      unsigned num_inputs = DIV_ROUND_UP(strlen(input_spec), 3u);
1177ec681f3Smrg      aco_ptr<Instruction> startpgm{create_instruction<Pseudo_instruction>(aco_opcode::p_startpgm, Format::PSEUDO, 0, num_inputs)};
1187ec681f3Smrg      for (unsigned i = 0; i < num_inputs; i++) {
1197ec681f3Smrg         RegClass cls(input_spec[i * 3] == 'v' ? RegType::vgpr : RegType::sgpr, input_spec[i * 3 + 1] - '0');
1207ec681f3Smrg         inputs[i] = bld.tmp(cls);
1217ec681f3Smrg         startpgm->definitions[i] = Definition(inputs[i]);
1227ec681f3Smrg      }
1237ec681f3Smrg      bld.insert(std::move(startpgm));
1247ec681f3Smrg   }
1257ec681f3Smrg
1267ec681f3Smrg   return true;
1277ec681f3Smrg}
1287ec681f3Smrg
1297ec681f3Smrgvoid finish_program(Program *prog)
1307ec681f3Smrg{
1317ec681f3Smrg   for (Block& BB : prog->blocks) {
1327ec681f3Smrg      for (unsigned idx : BB.linear_preds)
1337ec681f3Smrg         prog->blocks[idx].linear_succs.emplace_back(BB.index);
1347ec681f3Smrg      for (unsigned idx : BB.logical_preds)
1357ec681f3Smrg         prog->blocks[idx].logical_succs.emplace_back(BB.index);
1367ec681f3Smrg   }
1377ec681f3Smrg
1387ec681f3Smrg   for (Block& block : prog->blocks) {
1397ec681f3Smrg      if (block.linear_succs.size() == 0) {
1407ec681f3Smrg         block.kind |= block_kind_uniform;
1417ec681f3Smrg         Builder(prog, &block).sopp(aco_opcode::s_endpgm);
1427ec681f3Smrg      }
1437ec681f3Smrg   }
1447ec681f3Smrg}
1457ec681f3Smrg
1467ec681f3Smrgvoid finish_validator_test()
1477ec681f3Smrg{
1487ec681f3Smrg   finish_program(program.get());
1497ec681f3Smrg   aco_print_program(program.get(), output);
1507ec681f3Smrg   fprintf(output, "Validation results:\n");
1517ec681f3Smrg   if (aco::validate_ir(program.get()))
1527ec681f3Smrg      fprintf(output, "Validation passed\n");
1537ec681f3Smrg   else
1547ec681f3Smrg      fprintf(output, "Validation failed\n");
1557ec681f3Smrg}
1567ec681f3Smrg
1577ec681f3Smrgvoid finish_opt_test()
1587ec681f3Smrg{
1597ec681f3Smrg   finish_program(program.get());
1607ec681f3Smrg   if (!aco::validate_ir(program.get())) {
1617ec681f3Smrg      fail_test("Validation before optimization failed");
1627ec681f3Smrg      return;
1637ec681f3Smrg   }
1647ec681f3Smrg   aco::optimize(program.get());
1657ec681f3Smrg   if (!aco::validate_ir(program.get())) {
1667ec681f3Smrg      fail_test("Validation after optimization failed");
1677ec681f3Smrg      return;
1687ec681f3Smrg   }
1697ec681f3Smrg   aco_print_program(program.get(), output);
1707ec681f3Smrg}
1717ec681f3Smrg
1727ec681f3Smrgvoid finish_ra_test(ra_test_policy policy, bool lower)
1737ec681f3Smrg{
1747ec681f3Smrg   finish_program(program.get());
1757ec681f3Smrg   if (!aco::validate_ir(program.get())) {
1767ec681f3Smrg      fail_test("Validation before register allocation failed");
1777ec681f3Smrg      return;
1787ec681f3Smrg   }
1797ec681f3Smrg
1807ec681f3Smrg   program->workgroup_size = program->wave_size;
1817ec681f3Smrg   aco::live live_vars = aco::live_var_analysis(program.get());
1827ec681f3Smrg   aco::register_allocation(program.get(), live_vars.live_out, policy);
1837ec681f3Smrg
1847ec681f3Smrg   if (aco::validate_ra(program.get())) {
1857ec681f3Smrg      fail_test("Validation after register allocation failed");
1867ec681f3Smrg      return;
1877ec681f3Smrg   }
1887ec681f3Smrg
1897ec681f3Smrg   if (lower) {
1907ec681f3Smrg      aco::ssa_elimination(program.get());
1917ec681f3Smrg      aco::lower_to_hw_instr(program.get());
1927ec681f3Smrg   }
1937ec681f3Smrg
1947ec681f3Smrg   aco_print_program(program.get(), output);
1957ec681f3Smrg}
1967ec681f3Smrg
1977ec681f3Smrgvoid finish_optimizer_postRA_test()
1987ec681f3Smrg{
1997ec681f3Smrg   finish_program(program.get());
2007ec681f3Smrg   aco::optimize_postRA(program.get());
2017ec681f3Smrg   aco_print_program(program.get(), output);
2027ec681f3Smrg}
2037ec681f3Smrg
2047ec681f3Smrgvoid finish_to_hw_instr_test()
2057ec681f3Smrg{
2067ec681f3Smrg   finish_program(program.get());
2077ec681f3Smrg   aco::lower_to_hw_instr(program.get());
2087ec681f3Smrg   aco_print_program(program.get(), output);
2097ec681f3Smrg}
2107ec681f3Smrg
2117ec681f3Smrgvoid finish_insert_nops_test()
2127ec681f3Smrg{
2137ec681f3Smrg   finish_program(program.get());
2147ec681f3Smrg   aco::insert_NOPs(program.get());
2157ec681f3Smrg   aco_print_program(program.get(), output);
2167ec681f3Smrg}
2177ec681f3Smrg
2187ec681f3Smrgvoid finish_form_hard_clause_test()
2197ec681f3Smrg{
2207ec681f3Smrg   finish_program(program.get());
2217ec681f3Smrg   aco::form_hard_clauses(program.get());
2227ec681f3Smrg   aco_print_program(program.get(), output);
2237ec681f3Smrg}
2247ec681f3Smrg
2257ec681f3Smrgvoid finish_assembler_test()
2267ec681f3Smrg{
2277ec681f3Smrg   finish_program(program.get());
2287ec681f3Smrg   std::vector<uint32_t> binary;
2297ec681f3Smrg   unsigned exec_size = emit_program(program.get(), binary);
2307ec681f3Smrg
2317ec681f3Smrg   /* we could use CLRX for disassembly but that would require it to be
2327ec681f3Smrg    * installed */
2337ec681f3Smrg   if (program->chip_class >= GFX8) {
2347ec681f3Smrg      print_asm(program.get(), binary, exec_size / 4u, output);
2357ec681f3Smrg   } else {
2367ec681f3Smrg      //TODO: maybe we should use CLRX and skip this test if it's not available?
2377ec681f3Smrg      for (uint32_t dword : binary)
2387ec681f3Smrg         fprintf(output, "%.8x\n", dword);
2397ec681f3Smrg   }
2407ec681f3Smrg}
2417ec681f3Smrg
2427ec681f3Smrgvoid writeout(unsigned i, Temp tmp)
2437ec681f3Smrg{
2447ec681f3Smrg   if (tmp.id())
2457ec681f3Smrg      bld.pseudo(aco_opcode::p_unit_test, Operand::c32(i), tmp);
2467ec681f3Smrg   else
2477ec681f3Smrg      bld.pseudo(aco_opcode::p_unit_test, Operand::c32(i));
2487ec681f3Smrg}
2497ec681f3Smrg
2507ec681f3Smrgvoid writeout(unsigned i, aco::Builder::Result res)
2517ec681f3Smrg{
2527ec681f3Smrg   bld.pseudo(aco_opcode::p_unit_test, Operand::c32(i), res);
2537ec681f3Smrg}
2547ec681f3Smrg
2557ec681f3Smrgvoid writeout(unsigned i, Operand op)
2567ec681f3Smrg{
2577ec681f3Smrg   bld.pseudo(aco_opcode::p_unit_test, Operand::c32(i), op);
2587ec681f3Smrg}
2597ec681f3Smrg
2607ec681f3Smrgvoid writeout(unsigned i, Operand op0, Operand op1)
2617ec681f3Smrg{
2627ec681f3Smrg   bld.pseudo(aco_opcode::p_unit_test, Operand::c32(i), op0, op1);
2637ec681f3Smrg}
2647ec681f3Smrg
2657ec681f3SmrgTemp fneg(Temp src)
2667ec681f3Smrg{
2677ec681f3Smrg   return bld.vop2(aco_opcode::v_mul_f32, bld.def(v1), Operand::c32(0xbf800000u), src);
2687ec681f3Smrg}
2697ec681f3Smrg
2707ec681f3SmrgTemp fabs(Temp src)
2717ec681f3Smrg{
2727ec681f3Smrg   Builder::Result res =
2737ec681f3Smrg      bld.vop2_e64(aco_opcode::v_mul_f32, bld.def(v1), Operand::c32(0x3f800000u), src);
2747ec681f3Smrg   res.instr->vop3().abs[1] = true;
2757ec681f3Smrg   return res;
2767ec681f3Smrg}
2777ec681f3Smrg
2787ec681f3SmrgVkDevice get_vk_device(enum chip_class chip_class)
2797ec681f3Smrg{
2807ec681f3Smrg   enum radeon_family family;
2817ec681f3Smrg   switch (chip_class) {
2827ec681f3Smrg   case GFX6:
2837ec681f3Smrg      family = CHIP_TAHITI;
2847ec681f3Smrg      break;
2857ec681f3Smrg   case GFX7:
2867ec681f3Smrg      family = CHIP_BONAIRE;
2877ec681f3Smrg      break;
2887ec681f3Smrg   case GFX8:
2897ec681f3Smrg      family = CHIP_POLARIS10;
2907ec681f3Smrg      break;
2917ec681f3Smrg   case GFX9:
2927ec681f3Smrg      family = CHIP_VEGA10;
2937ec681f3Smrg      break;
2947ec681f3Smrg   case GFX10:
2957ec681f3Smrg      family = CHIP_NAVI10;
2967ec681f3Smrg      break;
2977ec681f3Smrg   case GFX10_3:
2987ec681f3Smrg      family = CHIP_SIENNA_CICHLID;
2997ec681f3Smrg      break;
3007ec681f3Smrg   default:
3017ec681f3Smrg      family = CHIP_UNKNOWN;
3027ec681f3Smrg      break;
3037ec681f3Smrg   }
3047ec681f3Smrg   return get_vk_device(family);
3057ec681f3Smrg}
3067ec681f3Smrg
3077ec681f3SmrgVkDevice get_vk_device(enum radeon_family family)
3087ec681f3Smrg{
3097ec681f3Smrg   assert(family != CHIP_UNKNOWN);
3107ec681f3Smrg
3117ec681f3Smrg   std::lock_guard<std::mutex> guard(create_device_mutex);
3127ec681f3Smrg
3137ec681f3Smrg   if (device_cache[family])
3147ec681f3Smrg      return device_cache[family];
3157ec681f3Smrg
3167ec681f3Smrg   setenv("RADV_FORCE_FAMILY", ac_get_family_name(family), 1);
3177ec681f3Smrg
3187ec681f3Smrg   VkApplicationInfo app_info = {};
3197ec681f3Smrg   app_info.pApplicationName = "aco_tests";
3207ec681f3Smrg   app_info.apiVersion = VK_API_VERSION_1_2;
3217ec681f3Smrg   VkInstanceCreateInfo instance_create_info = {};
3227ec681f3Smrg   instance_create_info.pApplicationInfo = &app_info;
3237ec681f3Smrg   instance_create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
3247ec681f3Smrg   ASSERTED VkResult result = ((PFN_vkCreateInstance)vk_icdGetInstanceProcAddr(NULL, "vkCreateInstance"))(&instance_create_info, NULL, &instance_cache[family]);
3257ec681f3Smrg   assert(result == VK_SUCCESS);
3267ec681f3Smrg
3277ec681f3Smrg   #define ITEM(n) n = (PFN_vk##n)vk_icdGetInstanceProcAddr(instance_cache[family], "vk" #n);
3287ec681f3Smrg   FUNCTION_LIST
3297ec681f3Smrg   #undef ITEM
3307ec681f3Smrg
3317ec681f3Smrg   uint32_t device_count = 1;
3327ec681f3Smrg   VkPhysicalDevice device = VK_NULL_HANDLE;
3337ec681f3Smrg   result = EnumeratePhysicalDevices(instance_cache[family], &device_count, &device);
3347ec681f3Smrg   assert(result == VK_SUCCESS);
3357ec681f3Smrg   assert(device != VK_NULL_HANDLE);
3367ec681f3Smrg
3377ec681f3Smrg   VkDeviceCreateInfo device_create_info = {};
3387ec681f3Smrg   device_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
3397ec681f3Smrg   static const char *extensions[] = {"VK_KHR_pipeline_executable_properties"};
3407ec681f3Smrg   device_create_info.enabledExtensionCount = sizeof(extensions) / sizeof(extensions[0]);
3417ec681f3Smrg   device_create_info.ppEnabledExtensionNames = extensions;
3427ec681f3Smrg   result = CreateDevice(device, &device_create_info, NULL, &device_cache[family]);
3437ec681f3Smrg
3447ec681f3Smrg   return device_cache[family];
3457ec681f3Smrg}
3467ec681f3Smrg
3477ec681f3Smrgstatic struct DestroyDevices {
3487ec681f3Smrg   ~DestroyDevices() {
3497ec681f3Smrg      for (unsigned i = 0; i < CHIP_LAST; i++) {
3507ec681f3Smrg         if (!device_cache[i])
3517ec681f3Smrg            continue;
3527ec681f3Smrg         DestroyDevice(device_cache[i], NULL);
3537ec681f3Smrg         DestroyInstance(instance_cache[i], NULL);
3547ec681f3Smrg      }
3557ec681f3Smrg   }
3567ec681f3Smrg} destroy_devices;
3577ec681f3Smrg
3587ec681f3Smrgvoid print_pipeline_ir(VkDevice device, VkPipeline pipeline, VkShaderStageFlagBits stages,
3597ec681f3Smrg                       const char *name, bool remove_encoding)
3607ec681f3Smrg{
3617ec681f3Smrg   uint32_t executable_count = 16;
3627ec681f3Smrg   VkPipelineExecutablePropertiesKHR executables[16];
3637ec681f3Smrg   VkPipelineInfoKHR pipeline_info;
3647ec681f3Smrg   pipeline_info.sType = VK_STRUCTURE_TYPE_PIPELINE_INFO_KHR;
3657ec681f3Smrg   pipeline_info.pNext = NULL;
3667ec681f3Smrg   pipeline_info.pipeline = pipeline;
3677ec681f3Smrg   ASSERTED VkResult result = GetPipelineExecutablePropertiesKHR(device, &pipeline_info, &executable_count, executables);
3687ec681f3Smrg   assert(result == VK_SUCCESS);
3697ec681f3Smrg
3707ec681f3Smrg   uint32_t executable = 0;
3717ec681f3Smrg   for (; executable < executable_count; executable++) {
3727ec681f3Smrg      if (executables[executable].stages == stages)
3737ec681f3Smrg         break;
3747ec681f3Smrg   }
3757ec681f3Smrg   assert(executable != executable_count);
3767ec681f3Smrg
3777ec681f3Smrg   VkPipelineExecutableInfoKHR exec_info;
3787ec681f3Smrg   exec_info.sType = VK_STRUCTURE_TYPE_PIPELINE_EXECUTABLE_INFO_KHR;
3797ec681f3Smrg   exec_info.pNext = NULL;
3807ec681f3Smrg   exec_info.pipeline = pipeline;
3817ec681f3Smrg   exec_info.executableIndex = executable;
3827ec681f3Smrg
3837ec681f3Smrg   uint32_t ir_count = 16;
3847ec681f3Smrg   VkPipelineExecutableInternalRepresentationKHR ir[16];
3857ec681f3Smrg   memset(ir, 0, sizeof(ir));
3867ec681f3Smrg   result = GetPipelineExecutableInternalRepresentationsKHR(device, &exec_info, &ir_count, ir);
3877ec681f3Smrg   assert(result == VK_SUCCESS);
3887ec681f3Smrg
3897ec681f3Smrg   VkPipelineExecutableInternalRepresentationKHR* requested_ir = nullptr;
3907ec681f3Smrg   for (unsigned i = 0; i < ir_count; ++i) {
3917ec681f3Smrg      if (strcmp(ir[i].name, name) == 0) {
3927ec681f3Smrg         requested_ir = &ir[i];
3937ec681f3Smrg         break;
3947ec681f3Smrg      }
3957ec681f3Smrg   }
3967ec681f3Smrg   assert(requested_ir && "Could not find requested IR");
3977ec681f3Smrg
3987ec681f3Smrg   char *data = (char*)malloc(requested_ir->dataSize);
3997ec681f3Smrg   requested_ir->pData = data;
4007ec681f3Smrg   result = GetPipelineExecutableInternalRepresentationsKHR(device, &exec_info, &ir_count, ir);
4017ec681f3Smrg   assert(result == VK_SUCCESS);
4027ec681f3Smrg
4037ec681f3Smrg   if (remove_encoding) {
4047ec681f3Smrg      for (char *c = data; *c; c++) {
4057ec681f3Smrg         if (*c == ';') {
4067ec681f3Smrg            for (; *c && *c != '\n'; c++)
4077ec681f3Smrg               *c = ' ';
4087ec681f3Smrg         }
4097ec681f3Smrg      }
4107ec681f3Smrg   }
4117ec681f3Smrg
4127ec681f3Smrg   fprintf(output, "%s", data);
4137ec681f3Smrg   free(data);
4147ec681f3Smrg}
4157ec681f3Smrg
4167ec681f3SmrgVkShaderModule __qoCreateShaderModule(VkDevice dev, const QoShaderModuleCreateInfo *module_info)
4177ec681f3Smrg{
4187ec681f3Smrg    VkShaderModuleCreateInfo vk_module_info;
4197ec681f3Smrg    vk_module_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
4207ec681f3Smrg    vk_module_info.pNext = NULL;
4217ec681f3Smrg    vk_module_info.flags = 0;
4227ec681f3Smrg    vk_module_info.codeSize = module_info->spirvSize;
4237ec681f3Smrg    vk_module_info.pCode = (const uint32_t*)module_info->pSpirv;
4247ec681f3Smrg
4257ec681f3Smrg    VkShaderModule module;
4267ec681f3Smrg    ASSERTED VkResult result = CreateShaderModule(dev, &vk_module_info, NULL, &module);
4277ec681f3Smrg    assert(result == VK_SUCCESS);
4287ec681f3Smrg
4297ec681f3Smrg    return module;
4307ec681f3Smrg}
4317ec681f3Smrg
4327ec681f3SmrgPipelineBuilder::PipelineBuilder(VkDevice dev) {
4337ec681f3Smrg   memset(this, 0, sizeof(*this));
4347ec681f3Smrg   topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
4357ec681f3Smrg   device = dev;
4367ec681f3Smrg}
4377ec681f3Smrg
4387ec681f3SmrgPipelineBuilder::~PipelineBuilder()
4397ec681f3Smrg{
4407ec681f3Smrg   DestroyPipeline(device, pipeline, NULL);
4417ec681f3Smrg
4427ec681f3Smrg   for (unsigned i = 0; i < (is_compute() ? 1 : gfx_pipeline_info.stageCount); i++) {
4437ec681f3Smrg      VkPipelineShaderStageCreateInfo *stage_info = &stages[i];
4447ec681f3Smrg      if (owned_stages & stage_info->stage)
4457ec681f3Smrg         DestroyShaderModule(device, stage_info->module, NULL);
4467ec681f3Smrg   }
4477ec681f3Smrg
4487ec681f3Smrg   DestroyPipelineLayout(device, pipeline_layout, NULL);
4497ec681f3Smrg
4507ec681f3Smrg   for (unsigned i = 0; i < util_bitcount64(desc_layouts_used); i++)
4517ec681f3Smrg      DestroyDescriptorSetLayout(device, desc_layouts[i], NULL);
4527ec681f3Smrg
4537ec681f3Smrg   DestroyRenderPass(device, render_pass, NULL);
4547ec681f3Smrg}
4557ec681f3Smrg
4567ec681f3Smrgvoid PipelineBuilder::add_desc_binding(VkShaderStageFlags stage_flags, uint32_t layout,
4577ec681f3Smrg                                       uint32_t binding, VkDescriptorType type, uint32_t count)
4587ec681f3Smrg{
4597ec681f3Smrg   desc_layouts_used |= 1ull << layout;
4607ec681f3Smrg   desc_bindings[layout][num_desc_bindings[layout]++] = {binding, type, count, stage_flags, NULL};
4617ec681f3Smrg}
4627ec681f3Smrg
4637ec681f3Smrgvoid PipelineBuilder::add_vertex_binding(uint32_t binding, uint32_t stride, VkVertexInputRate rate)
4647ec681f3Smrg{
4657ec681f3Smrg   vs_bindings[vs_input.vertexBindingDescriptionCount++] = {binding, stride, rate};
4667ec681f3Smrg}
4677ec681f3Smrg
4687ec681f3Smrgvoid PipelineBuilder::add_vertex_attribute(uint32_t location, uint32_t binding, VkFormat format, uint32_t offset)
4697ec681f3Smrg{
4707ec681f3Smrg   vs_attributes[vs_input.vertexAttributeDescriptionCount++] = {location, binding, format, offset};
4717ec681f3Smrg}
4727ec681f3Smrg
4737ec681f3Smrgvoid PipelineBuilder::add_resource_decls(QoShaderModuleCreateInfo *module)
4747ec681f3Smrg{
4757ec681f3Smrg   for (unsigned i = 0; i < module->declarationCount; i++) {
4767ec681f3Smrg      const QoShaderDecl *decl = &module->pDeclarations[i];
4777ec681f3Smrg      switch (decl->decl_type) {
4787ec681f3Smrg      case QoShaderDeclType_ubo:
4797ec681f3Smrg         add_desc_binding(module->stage, decl->set, decl->binding, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER);
4807ec681f3Smrg         break;
4817ec681f3Smrg      case QoShaderDeclType_ssbo:
4827ec681f3Smrg         add_desc_binding(module->stage, decl->set, decl->binding, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
4837ec681f3Smrg         break;
4847ec681f3Smrg      case QoShaderDeclType_img_buf:
4857ec681f3Smrg         add_desc_binding(module->stage, decl->set, decl->binding, VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER);
4867ec681f3Smrg         break;
4877ec681f3Smrg      case QoShaderDeclType_img:
4887ec681f3Smrg         add_desc_binding(module->stage, decl->set, decl->binding, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE);
4897ec681f3Smrg         break;
4907ec681f3Smrg      case QoShaderDeclType_tex_buf:
4917ec681f3Smrg         add_desc_binding(module->stage, decl->set, decl->binding, VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER);
4927ec681f3Smrg         break;
4937ec681f3Smrg      case QoShaderDeclType_combined:
4947ec681f3Smrg         add_desc_binding(module->stage, decl->set, decl->binding, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER);
4957ec681f3Smrg         break;
4967ec681f3Smrg      case QoShaderDeclType_tex:
4977ec681f3Smrg         add_desc_binding(module->stage, decl->set, decl->binding, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE);
4987ec681f3Smrg         break;
4997ec681f3Smrg      case QoShaderDeclType_samp:
5007ec681f3Smrg         add_desc_binding(module->stage, decl->set, decl->binding, VK_DESCRIPTOR_TYPE_SAMPLER);
5017ec681f3Smrg         break;
5027ec681f3Smrg      default:
5037ec681f3Smrg         break;
5047ec681f3Smrg      }
5057ec681f3Smrg   }
5067ec681f3Smrg}
5077ec681f3Smrg
5087ec681f3Smrgvoid PipelineBuilder::add_io_decls(QoShaderModuleCreateInfo *module)
5097ec681f3Smrg{
5107ec681f3Smrg   unsigned next_vtx_offset = 0;
5117ec681f3Smrg   for (unsigned i = 0; i < module->declarationCount; i++) {
5127ec681f3Smrg      const QoShaderDecl *decl = &module->pDeclarations[i];
5137ec681f3Smrg      switch (decl->decl_type) {
5147ec681f3Smrg      case QoShaderDeclType_in:
5157ec681f3Smrg         if (module->stage == VK_SHADER_STAGE_VERTEX_BIT) {
5167ec681f3Smrg            if (!strcmp(decl->type, "float") || decl->type[0] == 'v')
5177ec681f3Smrg               add_vertex_attribute(decl->location, 0, VK_FORMAT_R32G32B32A32_SFLOAT, next_vtx_offset);
5187ec681f3Smrg            else if (decl->type[0] == 'u')
5197ec681f3Smrg               add_vertex_attribute(decl->location, 0, VK_FORMAT_R32G32B32A32_UINT, next_vtx_offset);
5207ec681f3Smrg            else if (decl->type[0] == 'i')
5217ec681f3Smrg               add_vertex_attribute(decl->location, 0, VK_FORMAT_R32G32B32A32_SINT, next_vtx_offset);
5227ec681f3Smrg            next_vtx_offset += 16;
5237ec681f3Smrg         }
5247ec681f3Smrg         break;
5257ec681f3Smrg      case QoShaderDeclType_out:
5267ec681f3Smrg         if (module->stage == VK_SHADER_STAGE_FRAGMENT_BIT) {
5277ec681f3Smrg            if (!strcmp(decl->type, "float") || decl->type[0] == 'v')
5287ec681f3Smrg               color_outputs[decl->location] = VK_FORMAT_R32G32B32A32_SFLOAT;
5297ec681f3Smrg            else if (decl->type[0] == 'u')
5307ec681f3Smrg               color_outputs[decl->location] = VK_FORMAT_R32G32B32A32_UINT;
5317ec681f3Smrg            else if (decl->type[0] == 'i')
5327ec681f3Smrg               color_outputs[decl->location] = VK_FORMAT_R32G32B32A32_SINT;
5337ec681f3Smrg         }
5347ec681f3Smrg         break;
5357ec681f3Smrg      default:
5367ec681f3Smrg         break;
5377ec681f3Smrg      }
5387ec681f3Smrg   }
5397ec681f3Smrg   if (next_vtx_offset)
5407ec681f3Smrg      add_vertex_binding(0, next_vtx_offset);
5417ec681f3Smrg}
5427ec681f3Smrg
5437ec681f3Smrgvoid PipelineBuilder::add_stage(VkShaderStageFlagBits stage, VkShaderModule module, const char *name)
5447ec681f3Smrg{
5457ec681f3Smrg   VkPipelineShaderStageCreateInfo *stage_info;
5467ec681f3Smrg   if (stage == VK_SHADER_STAGE_COMPUTE_BIT)
5477ec681f3Smrg      stage_info = &stages[0];
5487ec681f3Smrg   else
5497ec681f3Smrg      stage_info = &stages[gfx_pipeline_info.stageCount++];
5507ec681f3Smrg   stage_info->sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
5517ec681f3Smrg   stage_info->pNext = NULL;
5527ec681f3Smrg   stage_info->flags = 0;
5537ec681f3Smrg   stage_info->stage = stage;
5547ec681f3Smrg   stage_info->module = module;
5557ec681f3Smrg   stage_info->pName = name;
5567ec681f3Smrg   stage_info->pSpecializationInfo = NULL;
5577ec681f3Smrg   owned_stages |= stage;
5587ec681f3Smrg}
5597ec681f3Smrg
5607ec681f3Smrgvoid PipelineBuilder::add_stage(VkShaderStageFlagBits stage, QoShaderModuleCreateInfo module, const char *name)
5617ec681f3Smrg{
5627ec681f3Smrg   add_stage(stage, __qoCreateShaderModule(device, &module), name);
5637ec681f3Smrg   add_resource_decls(&module);
5647ec681f3Smrg   add_io_decls(&module);
5657ec681f3Smrg}
5667ec681f3Smrg
5677ec681f3Smrgvoid PipelineBuilder::add_vsfs(VkShaderModule vs, VkShaderModule fs)
5687ec681f3Smrg{
5697ec681f3Smrg   add_stage(VK_SHADER_STAGE_VERTEX_BIT, vs);
5707ec681f3Smrg   add_stage(VK_SHADER_STAGE_FRAGMENT_BIT, fs);
5717ec681f3Smrg}
5727ec681f3Smrg
5737ec681f3Smrgvoid PipelineBuilder::add_vsfs(QoShaderModuleCreateInfo vs, QoShaderModuleCreateInfo fs)
5747ec681f3Smrg{
5757ec681f3Smrg   add_stage(VK_SHADER_STAGE_VERTEX_BIT, vs);
5767ec681f3Smrg   add_stage(VK_SHADER_STAGE_FRAGMENT_BIT, fs);
5777ec681f3Smrg}
5787ec681f3Smrg
5797ec681f3Smrgvoid PipelineBuilder::add_cs(VkShaderModule cs)
5807ec681f3Smrg{
5817ec681f3Smrg   add_stage(VK_SHADER_STAGE_COMPUTE_BIT, cs);
5827ec681f3Smrg}
5837ec681f3Smrg
5847ec681f3Smrgvoid PipelineBuilder::add_cs(QoShaderModuleCreateInfo cs)
5857ec681f3Smrg{
5867ec681f3Smrg   add_stage(VK_SHADER_STAGE_COMPUTE_BIT, cs);
5877ec681f3Smrg}
5887ec681f3Smrg
5897ec681f3Smrgbool PipelineBuilder::is_compute() {
5907ec681f3Smrg   return gfx_pipeline_info.stageCount == 0;
5917ec681f3Smrg}
5927ec681f3Smrg
5937ec681f3Smrgvoid PipelineBuilder::create_compute_pipeline() {
5947ec681f3Smrg   VkComputePipelineCreateInfo create_info;
5957ec681f3Smrg   create_info.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO;
5967ec681f3Smrg   create_info.pNext = NULL;
5977ec681f3Smrg   create_info.flags = VK_PIPELINE_CREATE_CAPTURE_INTERNAL_REPRESENTATIONS_BIT_KHR;
5987ec681f3Smrg   create_info.stage = stages[0];
5997ec681f3Smrg   create_info.layout = pipeline_layout;
6007ec681f3Smrg   create_info.basePipelineHandle = VK_NULL_HANDLE;
6017ec681f3Smrg   create_info.basePipelineIndex = 0;
6027ec681f3Smrg
6037ec681f3Smrg   ASSERTED VkResult result = CreateComputePipelines(device, VK_NULL_HANDLE, 1, &create_info, NULL, &pipeline);
6047ec681f3Smrg   assert(result == VK_SUCCESS);
6057ec681f3Smrg}
6067ec681f3Smrg
6077ec681f3Smrgvoid PipelineBuilder::create_graphics_pipeline() {
6087ec681f3Smrg   /* create the create infos */
6097ec681f3Smrg   if (!samples)
6107ec681f3Smrg      samples = VK_SAMPLE_COUNT_1_BIT;
6117ec681f3Smrg
6127ec681f3Smrg   unsigned num_color_attachments = 0;
6137ec681f3Smrg   VkPipelineColorBlendAttachmentState blend_attachment_states[16];
6147ec681f3Smrg   VkAttachmentReference color_attachments[16];
6157ec681f3Smrg   VkAttachmentDescription attachment_descs[17];
6167ec681f3Smrg   for (unsigned i = 0; i < 16; i++) {
6177ec681f3Smrg      if (color_outputs[i] == VK_FORMAT_UNDEFINED)
6187ec681f3Smrg         continue;
6197ec681f3Smrg
6207ec681f3Smrg      VkAttachmentDescription *desc = &attachment_descs[num_color_attachments];
6217ec681f3Smrg      desc->flags = 0;
6227ec681f3Smrg      desc->format = color_outputs[i];
6237ec681f3Smrg      desc->samples = samples;
6247ec681f3Smrg      desc->loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
6257ec681f3Smrg      desc->storeOp = VK_ATTACHMENT_STORE_OP_STORE;
6267ec681f3Smrg      desc->stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
6277ec681f3Smrg      desc->stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE;
6287ec681f3Smrg      desc->initialLayout = VK_IMAGE_LAYOUT_GENERAL;
6297ec681f3Smrg      desc->finalLayout = VK_IMAGE_LAYOUT_GENERAL;
6307ec681f3Smrg
6317ec681f3Smrg      VkAttachmentReference *ref = &color_attachments[num_color_attachments];
6327ec681f3Smrg      ref->attachment = num_color_attachments;
6337ec681f3Smrg      ref->layout = VK_IMAGE_LAYOUT_GENERAL;
6347ec681f3Smrg
6357ec681f3Smrg      VkPipelineColorBlendAttachmentState *blend = &blend_attachment_states[num_color_attachments];
6367ec681f3Smrg      blend->blendEnable = false;
6377ec681f3Smrg      blend->colorWriteMask = VK_COLOR_COMPONENT_R_BIT |
6387ec681f3Smrg                              VK_COLOR_COMPONENT_G_BIT |
6397ec681f3Smrg                              VK_COLOR_COMPONENT_B_BIT |
6407ec681f3Smrg                              VK_COLOR_COMPONENT_A_BIT;
6417ec681f3Smrg
6427ec681f3Smrg      num_color_attachments++;
6437ec681f3Smrg   }
6447ec681f3Smrg
6457ec681f3Smrg   unsigned num_attachments = num_color_attachments;
6467ec681f3Smrg   VkAttachmentReference ds_attachment;
6477ec681f3Smrg   if (ds_output != VK_FORMAT_UNDEFINED) {
6487ec681f3Smrg      VkAttachmentDescription *desc = &attachment_descs[num_attachments];
6497ec681f3Smrg      desc->flags = 0;
6507ec681f3Smrg      desc->format = ds_output;
6517ec681f3Smrg      desc->samples = samples;
6527ec681f3Smrg      desc->loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
6537ec681f3Smrg      desc->storeOp = VK_ATTACHMENT_STORE_OP_STORE;
6547ec681f3Smrg      desc->stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
6557ec681f3Smrg      desc->stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE;
6567ec681f3Smrg      desc->initialLayout = VK_IMAGE_LAYOUT_GENERAL;
6577ec681f3Smrg      desc->finalLayout = VK_IMAGE_LAYOUT_GENERAL;
6587ec681f3Smrg
6597ec681f3Smrg      ds_attachment.attachment = num_color_attachments;
6607ec681f3Smrg      ds_attachment.layout = VK_IMAGE_LAYOUT_GENERAL;
6617ec681f3Smrg
6627ec681f3Smrg      num_attachments++;
6637ec681f3Smrg   }
6647ec681f3Smrg
6657ec681f3Smrg   vs_input.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
6667ec681f3Smrg   vs_input.pNext = NULL;
6677ec681f3Smrg   vs_input.flags = 0;
6687ec681f3Smrg   vs_input.pVertexBindingDescriptions = vs_bindings;
6697ec681f3Smrg   vs_input.pVertexAttributeDescriptions = vs_attributes;
6707ec681f3Smrg
6717ec681f3Smrg   VkPipelineInputAssemblyStateCreateInfo assembly_state;
6727ec681f3Smrg   assembly_state.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
6737ec681f3Smrg   assembly_state.pNext = NULL;
6747ec681f3Smrg   assembly_state.flags = 0;
6757ec681f3Smrg   assembly_state.topology = topology;
6767ec681f3Smrg   assembly_state.primitiveRestartEnable = false;
6777ec681f3Smrg
6787ec681f3Smrg   VkPipelineTessellationStateCreateInfo tess_state;
6797ec681f3Smrg   tess_state.sType = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO;
6807ec681f3Smrg   tess_state.pNext = NULL;
6817ec681f3Smrg   tess_state.flags = 0;
6827ec681f3Smrg   tess_state.patchControlPoints = patch_size;
6837ec681f3Smrg
6847ec681f3Smrg   VkPipelineViewportStateCreateInfo viewport_state;
6857ec681f3Smrg   viewport_state.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
6867ec681f3Smrg   viewport_state.pNext = NULL;
6877ec681f3Smrg   viewport_state.flags = 0;
6887ec681f3Smrg   viewport_state.viewportCount = 1;
6897ec681f3Smrg   viewport_state.pViewports = NULL;
6907ec681f3Smrg   viewport_state.scissorCount = 1;
6917ec681f3Smrg   viewport_state.pScissors = NULL;
6927ec681f3Smrg
6937ec681f3Smrg   VkPipelineRasterizationStateCreateInfo rasterization_state;
6947ec681f3Smrg   rasterization_state.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
6957ec681f3Smrg   rasterization_state.pNext = NULL;
6967ec681f3Smrg   rasterization_state.flags = 0;
6977ec681f3Smrg   rasterization_state.depthClampEnable = false;
6987ec681f3Smrg   rasterization_state.rasterizerDiscardEnable = false;
6997ec681f3Smrg   rasterization_state.polygonMode = VK_POLYGON_MODE_FILL;
7007ec681f3Smrg   rasterization_state.cullMode = VK_CULL_MODE_NONE;
7017ec681f3Smrg   rasterization_state.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
7027ec681f3Smrg   rasterization_state.depthBiasEnable = false;
7037ec681f3Smrg   rasterization_state.lineWidth = 1.0;
7047ec681f3Smrg
7057ec681f3Smrg   VkPipelineMultisampleStateCreateInfo ms_state;
7067ec681f3Smrg   ms_state.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
7077ec681f3Smrg   ms_state.pNext = NULL;
7087ec681f3Smrg   ms_state.flags = 0;
7097ec681f3Smrg   ms_state.rasterizationSamples = samples;
7107ec681f3Smrg   ms_state.sampleShadingEnable = sample_shading_enable;
7117ec681f3Smrg   ms_state.minSampleShading = min_sample_shading;
7127ec681f3Smrg   VkSampleMask sample_mask = 0xffffffff;
7137ec681f3Smrg   ms_state.pSampleMask = &sample_mask;
7147ec681f3Smrg   ms_state.alphaToCoverageEnable = false;
7157ec681f3Smrg   ms_state.alphaToOneEnable = false;
7167ec681f3Smrg
7177ec681f3Smrg   VkPipelineDepthStencilStateCreateInfo ds_state;
7187ec681f3Smrg   ds_state.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
7197ec681f3Smrg   ds_state.pNext = NULL;
7207ec681f3Smrg   ds_state.flags = 0;
7217ec681f3Smrg   ds_state.depthTestEnable = ds_output != VK_FORMAT_UNDEFINED;
7227ec681f3Smrg   ds_state.depthWriteEnable = true;
7237ec681f3Smrg   ds_state.depthCompareOp = VK_COMPARE_OP_ALWAYS;
7247ec681f3Smrg   ds_state.depthBoundsTestEnable = false;
7257ec681f3Smrg   ds_state.stencilTestEnable = true;
7267ec681f3Smrg   ds_state.front.failOp = VK_STENCIL_OP_KEEP;
7277ec681f3Smrg   ds_state.front.passOp = VK_STENCIL_OP_REPLACE;
7287ec681f3Smrg   ds_state.front.depthFailOp = VK_STENCIL_OP_REPLACE;
7297ec681f3Smrg   ds_state.front.compareOp = VK_COMPARE_OP_ALWAYS;
7307ec681f3Smrg   ds_state.front.compareMask = 0xffffffff,
7317ec681f3Smrg   ds_state.front.writeMask = 0;
7327ec681f3Smrg   ds_state.front.reference = 0;
7337ec681f3Smrg   ds_state.back = ds_state.front;
7347ec681f3Smrg
7357ec681f3Smrg   VkPipelineColorBlendStateCreateInfo color_blend_state;
7367ec681f3Smrg   color_blend_state.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
7377ec681f3Smrg   color_blend_state.pNext = NULL;
7387ec681f3Smrg   color_blend_state.flags = 0;
7397ec681f3Smrg   color_blend_state.logicOpEnable = false;
7407ec681f3Smrg   color_blend_state.attachmentCount = num_color_attachments;
7417ec681f3Smrg   color_blend_state.pAttachments = blend_attachment_states;
7427ec681f3Smrg
7437ec681f3Smrg   VkDynamicState dynamic_states[9] = {
7447ec681f3Smrg      VK_DYNAMIC_STATE_VIEWPORT,
7457ec681f3Smrg      VK_DYNAMIC_STATE_SCISSOR,
7467ec681f3Smrg      VK_DYNAMIC_STATE_LINE_WIDTH,
7477ec681f3Smrg      VK_DYNAMIC_STATE_DEPTH_BIAS,
7487ec681f3Smrg      VK_DYNAMIC_STATE_BLEND_CONSTANTS,
7497ec681f3Smrg      VK_DYNAMIC_STATE_DEPTH_BOUNDS,
7507ec681f3Smrg      VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK,
7517ec681f3Smrg      VK_DYNAMIC_STATE_STENCIL_WRITE_MASK,
7527ec681f3Smrg      VK_DYNAMIC_STATE_STENCIL_REFERENCE
7537ec681f3Smrg   };
7547ec681f3Smrg
7557ec681f3Smrg   VkPipelineDynamicStateCreateInfo dynamic_state;
7567ec681f3Smrg   dynamic_state.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
7577ec681f3Smrg   dynamic_state.pNext = NULL;
7587ec681f3Smrg   dynamic_state.flags = 0;
7597ec681f3Smrg   dynamic_state.dynamicStateCount = sizeof(dynamic_states) / sizeof(VkDynamicState);
7607ec681f3Smrg   dynamic_state.pDynamicStates = dynamic_states;
7617ec681f3Smrg
7627ec681f3Smrg   gfx_pipeline_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
7637ec681f3Smrg   gfx_pipeline_info.pNext = NULL;
7647ec681f3Smrg   gfx_pipeline_info.flags = VK_PIPELINE_CREATE_CAPTURE_INTERNAL_REPRESENTATIONS_BIT_KHR;
7657ec681f3Smrg   gfx_pipeline_info.pVertexInputState = &vs_input;
7667ec681f3Smrg   gfx_pipeline_info.pInputAssemblyState = &assembly_state;
7677ec681f3Smrg   gfx_pipeline_info.pTessellationState = &tess_state;
7687ec681f3Smrg   gfx_pipeline_info.pViewportState = &viewport_state;
7697ec681f3Smrg   gfx_pipeline_info.pRasterizationState = &rasterization_state;
7707ec681f3Smrg   gfx_pipeline_info.pMultisampleState = &ms_state;
7717ec681f3Smrg   gfx_pipeline_info.pDepthStencilState = &ds_state;
7727ec681f3Smrg   gfx_pipeline_info.pColorBlendState = &color_blend_state;
7737ec681f3Smrg   gfx_pipeline_info.pDynamicState = &dynamic_state;
7747ec681f3Smrg   gfx_pipeline_info.subpass = 0;
7757ec681f3Smrg
7767ec681f3Smrg   /* create the objects used to create the pipeline */
7777ec681f3Smrg   VkSubpassDescription subpass;
7787ec681f3Smrg   subpass.flags = 0;
7797ec681f3Smrg   subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
7807ec681f3Smrg   subpass.inputAttachmentCount = 0;
7817ec681f3Smrg   subpass.pInputAttachments = NULL;
7827ec681f3Smrg   subpass.colorAttachmentCount = num_color_attachments;
7837ec681f3Smrg   subpass.pColorAttachments = color_attachments;
7847ec681f3Smrg   subpass.pResolveAttachments = NULL;
7857ec681f3Smrg   subpass.pDepthStencilAttachment = ds_output == VK_FORMAT_UNDEFINED ? NULL : &ds_attachment;
7867ec681f3Smrg   subpass.preserveAttachmentCount = 0;
7877ec681f3Smrg   subpass.pPreserveAttachments = NULL;
7887ec681f3Smrg
7897ec681f3Smrg   VkRenderPassCreateInfo renderpass_info;
7907ec681f3Smrg   renderpass_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
7917ec681f3Smrg   renderpass_info.pNext = NULL;
7927ec681f3Smrg   renderpass_info.flags = 0;
7937ec681f3Smrg   renderpass_info.attachmentCount = num_attachments;
7947ec681f3Smrg   renderpass_info.pAttachments = attachment_descs;
7957ec681f3Smrg   renderpass_info.subpassCount = 1;
7967ec681f3Smrg   renderpass_info.pSubpasses = &subpass;
7977ec681f3Smrg   renderpass_info.dependencyCount = 0;
7987ec681f3Smrg   renderpass_info.pDependencies = NULL;
7997ec681f3Smrg
8007ec681f3Smrg   ASSERTED VkResult result = CreateRenderPass(device, &renderpass_info, NULL, &render_pass);
8017ec681f3Smrg   assert(result == VK_SUCCESS);
8027ec681f3Smrg
8037ec681f3Smrg   gfx_pipeline_info.layout = pipeline_layout;
8047ec681f3Smrg   gfx_pipeline_info.renderPass = render_pass;
8057ec681f3Smrg
8067ec681f3Smrg   /* create the pipeline */
8077ec681f3Smrg   gfx_pipeline_info.pStages = stages;
8087ec681f3Smrg
8097ec681f3Smrg   result = CreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, &gfx_pipeline_info, NULL, &pipeline);
8107ec681f3Smrg   assert(result == VK_SUCCESS);
8117ec681f3Smrg}
8127ec681f3Smrg
8137ec681f3Smrgvoid PipelineBuilder::create_pipeline() {
8147ec681f3Smrg   unsigned num_desc_layouts = 0;
8157ec681f3Smrg   for (unsigned i = 0; i < 64; i++) {
8167ec681f3Smrg      if (!(desc_layouts_used & (1ull << i)))
8177ec681f3Smrg         continue;
8187ec681f3Smrg
8197ec681f3Smrg      VkDescriptorSetLayoutCreateInfo desc_layout_info;
8207ec681f3Smrg      desc_layout_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
8217ec681f3Smrg      desc_layout_info.pNext = NULL;
8227ec681f3Smrg      desc_layout_info.flags = 0;
8237ec681f3Smrg      desc_layout_info.bindingCount = num_desc_bindings[i];
8247ec681f3Smrg      desc_layout_info.pBindings = desc_bindings[i];
8257ec681f3Smrg
8267ec681f3Smrg      ASSERTED VkResult result = CreateDescriptorSetLayout(device, &desc_layout_info, NULL, &desc_layouts[num_desc_layouts]);
8277ec681f3Smrg      assert(result == VK_SUCCESS);
8287ec681f3Smrg      num_desc_layouts++;
8297ec681f3Smrg   }
8307ec681f3Smrg
8317ec681f3Smrg   VkPipelineLayoutCreateInfo pipeline_layout_info;
8327ec681f3Smrg   pipeline_layout_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
8337ec681f3Smrg   pipeline_layout_info.pNext = NULL;
8347ec681f3Smrg   pipeline_layout_info.flags = 0;
8357ec681f3Smrg   pipeline_layout_info.pushConstantRangeCount = 1;
8367ec681f3Smrg   pipeline_layout_info.pPushConstantRanges = &push_constant_range;
8377ec681f3Smrg   pipeline_layout_info.setLayoutCount = num_desc_layouts;
8387ec681f3Smrg   pipeline_layout_info.pSetLayouts = desc_layouts;
8397ec681f3Smrg
8407ec681f3Smrg   ASSERTED VkResult result = CreatePipelineLayout(device, &pipeline_layout_info, NULL, &pipeline_layout);
8417ec681f3Smrg   assert(result == VK_SUCCESS);
8427ec681f3Smrg
8437ec681f3Smrg   if (is_compute())
8447ec681f3Smrg      create_compute_pipeline();
8457ec681f3Smrg   else
8467ec681f3Smrg      create_graphics_pipeline();
8477ec681f3Smrg}
8487ec681f3Smrg
8497ec681f3Smrgvoid PipelineBuilder::print_ir(VkShaderStageFlagBits stage_flags, const char *name, bool remove_encoding)
8507ec681f3Smrg{
8517ec681f3Smrg   if (!pipeline)
8527ec681f3Smrg      create_pipeline();
8537ec681f3Smrg   print_pipeline_ir(device, pipeline, stage_flags, name, remove_encoding);
8547ec681f3Smrg}
855