]> git.tdb.fi Git - libs/gl.git/blobdiff - source/backends/vulkan/program_backend.cpp
Initial implementation of Vulkan backend
[libs/gl.git] / source / backends / vulkan / program_backend.cpp
diff --git a/source/backends/vulkan/program_backend.cpp b/source/backends/vulkan/program_backend.cpp
new file mode 100644 (file)
index 0000000..61b5efa
--- /dev/null
@@ -0,0 +1,160 @@
+#include <cstring>
+#include <msp/core/algorithm.h>
+#include "device.h"
+#include "error.h"
+#include "program.h"
+#include "program_backend.h"
+#include "structurebuilder.h"
+#include "vulkan.h"
+
+using namespace std;
+
+namespace Msp {
+namespace GL {
+
+VulkanProgram::VulkanProgram():
+       device(Device::get_current())
+{ }
+
+VulkanProgram::VulkanProgram(VulkanProgram &&other):
+       device(other.device),
+       n_stages(other.n_stages),
+       creation_info(move(other.creation_info)),
+       desc_set_layout_handles(move(other.desc_set_layout_handles)),
+       layout_handle(other.layout_handle)
+{
+       other.desc_set_layout_handles.clear();
+       other.layout_handle = 0;
+}
+
+VulkanProgram::~VulkanProgram()
+{
+       const VulkanFunctions &vk = device.get_functions();
+
+       if(layout_handle)
+               vk.DestroyPipelineLayout(layout_handle);
+       for(VkDescriptorSetLayout d: desc_set_layout_handles)
+               vk.DestroyDescriptorSetLayout(d);
+}
+
+bool VulkanProgram::has_stages() const
+{
+       return n_stages;
+}
+
+void VulkanProgram::add_glsl_stages(const GlslModule &, const map<string, int> &, TransientData &)
+{
+       throw invalid_operation("VulkanProgram::add_glsl_stages");
+}
+
+void VulkanProgram::add_spirv_stages(const SpirVModule &mod, const map<string, int> &spec_values)
+{
+       const vector<SpirVModule::EntryPoint> &entry_points = mod.get_entry_points();
+
+       n_stages = entry_points.size();
+       size_t entry_names_size = 0;
+       for(const SpirVModule::EntryPoint &e: entry_points)
+               entry_names_size += e.name.size()+1;
+
+       StructureBuilder sb(creation_info, 5);
+       VkPipelineShaderStageCreateInfo *&stage_infos = sb.add<VkPipelineShaderStageCreateInfo>(n_stages);
+       char *&name_table = sb.add<char>(entry_names_size);
+       VkSpecializationInfo *&spec_info = sb.add<VkSpecializationInfo>();
+       VkSpecializationMapEntry *&spec_map = sb.add<VkSpecializationMapEntry>(spec_values.size());
+       int *&spec_data = sb.add<int>(spec_values.size());
+
+       unsigned i = 0;
+       for(const SpirVModule::Constant &c: mod.get_spec_constants())
+       {
+               auto j = spec_values.find(c.name);
+               if(j!=spec_values.end())
+               {
+                       spec_map[i].constantID = c.constant_id;
+                       spec_map[i].offset = i*sizeof(int);
+                       spec_map[i].size = sizeof(int);
+                       spec_data[i] = j->second;
+                       ++i;
+               }
+       }
+
+       spec_info->mapEntryCount = i;
+       spec_info->pMapEntries = spec_map;
+       spec_info->dataSize = spec_values.size()*sizeof(int);
+       spec_info->pData = spec_data;
+
+       char *name_ptr = name_table;
+       i = 0;
+       for(const SpirVModule::EntryPoint &e: entry_points)
+       {
+               stage_infos[i].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
+               stage_infos[i].stage = static_cast<VkShaderStageFlagBits>(get_vulkan_stage(e.stage));
+               stage_infos[i].module = handle_cast<::VkShaderModule>(mod.handle);
+               strcpy(name_ptr, e.name.c_str());
+               stage_infos[i].pName = name_ptr;
+               name_ptr += e.name.size()+1;
+               stage_infos[i].pSpecializationInfo = spec_info;
+               ++i;
+       }
+}
+
+void VulkanProgram::finalize_uniforms()
+{
+       const VulkanFunctions &vk = device.get_functions();
+       const ReflectData &rd = static_cast<const Program *>(this)->reflect_data;
+
+       auto i = find_member(rd.uniform_blocks, static_cast<int>(ReflectData::PUSH_CONSTANT), &ReflectData::UniformBlockInfo::bind_point);
+       const ReflectData::UniformBlockInfo *push_const_block = (i!=rd.uniform_blocks.end() ? &*i : 0);
+
+       desc_set_layout_handles.resize(rd.n_descriptor_sets);
+       for(unsigned j=0; j<rd.n_descriptor_sets; ++j)
+       {
+               std::vector<VkDescriptorSetLayoutBinding> bindings;
+               for(const ReflectData::UniformBlockInfo &b: rd.uniform_blocks)
+                       if(b.bind_point>=0 && static_cast<unsigned>(b.bind_point>>20)==j)
+                       {
+                               bindings.emplace_back();
+                               VkDescriptorSetLayoutBinding &binding = bindings.back();
+                               binding.binding = b.bind_point;
+                               binding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
+                               binding.descriptorCount = 1;
+                               binding.stageFlags = VK_SHADER_STAGE_ALL;
+                               binding.pImmutableSamplers = 0;
+                       }
+
+               for(const ReflectData::UniformInfo &u: rd.uniforms)
+                       if(u.binding>=0 && static_cast<unsigned>(u.binding>>20)==j && is_image(u.type))
+                       {
+                               bindings.emplace_back();
+                               VkDescriptorSetLayoutBinding &binding = bindings.back();
+                               binding.binding = u.binding;
+                               binding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
+                               binding.descriptorCount = 1;
+                               binding.stageFlags = VK_SHADER_STAGE_ALL;
+                               binding.pImmutableSamplers = 0;
+                       }
+
+               VkDescriptorSetLayoutCreateInfo set_layout_info = { };
+               set_layout_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
+               set_layout_info.bindingCount = bindings.size();
+               set_layout_info.pBindings = bindings.data();
+
+               vk.CreateDescriptorSetLayout(set_layout_info, desc_set_layout_handles[j]);
+       }
+
+       VkPushConstantRange push_const_range = { };
+       push_const_range.stageFlags = VK_SHADER_STAGE_ALL;
+       push_const_range.offset = 0;
+       push_const_range.size = (push_const_block ? push_const_block->data_size : 0);
+
+       VkPipelineLayoutCreateInfo layout_info = { };
+       layout_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
+       layout_info.setLayoutCount = rd.n_descriptor_sets;
+       layout_info.pSetLayouts = handle_cast<::VkDescriptorSetLayout *>(desc_set_layout_handles.data());
+       layout_info.pushConstantRangeCount = (push_const_block ? 1 : 0);
+       layout_info.pPushConstantRanges = &push_const_range;
+
+       vk.CreatePipelineLayout(layout_info, layout_handle);
+}
+
+} // namespace GL
+} // namespace Msp