//===- VulkanRuntime.cpp - MLIR Vulkan runtime ------------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This file declares Vulkan runtime API. // //===----------------------------------------------------------------------===// #ifndef VULKAN_RUNTIME_H #define VULKAN_RUNTIME_H #include "mlir/Support/LogicalResult.h" #include #include #include using namespace mlir; using DescriptorSetIndex = uint32_t; using BindingIndex = uint32_t; /// Struct containing information regarding to a device memory buffer. struct VulkanDeviceMemoryBuffer { BindingIndex bindingIndex{0}; VkDescriptorType descriptorType{VK_DESCRIPTOR_TYPE_MAX_ENUM}; VkDescriptorBufferInfo bufferInfo{}; VkBuffer hostBuffer{VK_NULL_HANDLE}; VkDeviceMemory hostMemory{VK_NULL_HANDLE}; VkBuffer deviceBuffer{VK_NULL_HANDLE}; VkDeviceMemory deviceMemory{VK_NULL_HANDLE}; uint32_t bufferSize{0}; }; /// Struct containing information regarding to a host memory buffer. struct VulkanHostMemoryBuffer { /// Pointer to a host memory. void *ptr{nullptr}; /// Size of a host memory in bytes. uint32_t size{0}; }; /// Struct containing the number of local workgroups to dispatch for each /// dimension. struct NumWorkGroups { uint32_t x{1}; uint32_t y{1}; uint32_t z{1}; }; /// Struct containing information regarding a descriptor set. struct DescriptorSetInfo { /// Index of a descriptor set in descriptor sets. DescriptorSetIndex descriptorSet{0}; /// Number of descriptors in a set. uint32_t descriptorSize{0}; /// Type of a descriptor set. VkDescriptorType descriptorType{VK_DESCRIPTOR_TYPE_MAX_ENUM}; }; /// VulkanHostMemoryBuffer mapped into a descriptor set and a binding. using ResourceData = std::unordered_map< DescriptorSetIndex, std::unordered_map>; /// SPIR-V storage classes. /// Note that this duplicates spirv::StorageClass but it keeps the Vulkan /// runtime library detached from SPIR-V dialect, so we can avoid pick up lots /// of dependencies. enum class SPIRVStorageClass { Uniform = 2, StorageBuffer = 12, }; /// StorageClass mapped into a descriptor set and a binding. using ResourceStorageClassBindingMap = std::unordered_map>; /// Vulkan runtime. /// The purpose of this class is to run SPIR-V compute shader on Vulkan /// device. /// Before the run, user must provide and set resource data with descriptors, /// SPIR-V shader, number of work groups and entry point. After the creation of /// VulkanRuntime, special methods must be called in the following /// sequence: initRuntime(), run(), updateHostMemoryBuffers(), destroy(); /// each method in the sequence returns success or failure depends on the Vulkan /// result code. class VulkanRuntime { public: explicit VulkanRuntime() = default; VulkanRuntime(const VulkanRuntime &) = delete; VulkanRuntime &operator=(const VulkanRuntime &) = delete; /// Sets needed data for Vulkan runtime. void setResourceData(const ResourceData &resData); void setResourceData(const DescriptorSetIndex desIndex, const BindingIndex bindIndex, const VulkanHostMemoryBuffer &hostMemBuffer); void setShaderModule(uint8_t *shader, uint32_t size); void setNumWorkGroups(const NumWorkGroups &numberWorkGroups); void setResourceStorageClassBindingMap( const ResourceStorageClassBindingMap &stClassData); void setEntryPoint(const char *entryPointName); /// Runtime initialization. LogicalResult initRuntime(); /// Runs runtime. LogicalResult run(); /// Updates host memory buffers. LogicalResult updateHostMemoryBuffers(); /// Destroys all created vulkan objects and resources. LogicalResult destroy(); private: //===--------------------------------------------------------------------===// // Pipeline creation methods. //===--------------------------------------------------------------------===// LogicalResult createInstance(); LogicalResult createDevice(); LogicalResult getBestComputeQueue(); LogicalResult createMemoryBuffers(); LogicalResult createShaderModule(); void initDescriptorSetLayoutBindingMap(); LogicalResult createDescriptorSetLayout(); LogicalResult createPipelineLayout(); LogicalResult createComputePipeline(); LogicalResult createDescriptorPool(); LogicalResult allocateDescriptorSets(); LogicalResult setWriteDescriptors(); LogicalResult createCommandPool(); LogicalResult createQueryPool(); LogicalResult createComputeCommandBuffer(); LogicalResult submitCommandBuffersToQueue(); // Copy resources from host (staging buffer) to device buffer or from device // buffer to host buffer. LogicalResult copyResource(bool deviceToHost); //===--------------------------------------------------------------------===// // Helper methods. //===--------------------------------------------------------------------===// /// Maps storage class to a descriptor type. LogicalResult mapStorageClassToDescriptorType(SPIRVStorageClass storageClass, VkDescriptorType &descriptorType); /// Maps storage class to buffer usage flags. LogicalResult mapStorageClassToBufferUsageFlag(SPIRVStorageClass storageClass, VkBufferUsageFlagBits &bufferUsage); LogicalResult countDeviceMemorySize(); //===--------------------------------------------------------------------===// // Vulkan objects. //===--------------------------------------------------------------------===// VkInstance instance{VK_NULL_HANDLE}; VkPhysicalDevice physicalDevice{VK_NULL_HANDLE}; VkDevice device{VK_NULL_HANDLE}; VkQueue queue{VK_NULL_HANDLE}; /// Specifies VulkanDeviceMemoryBuffers divided into sets. std::unordered_map> deviceMemoryBufferMap; /// Specifies shader module. VkShaderModule shaderModule{VK_NULL_HANDLE}; /// Specifies layout bindings. std::unordered_map> descriptorSetLayoutBindingMap; /// Specifies layouts of descriptor sets. std::vector descriptorSetLayouts; VkPipelineLayout pipelineLayout{VK_NULL_HANDLE}; /// Specifies descriptor sets. std::vector descriptorSets; /// Specifies a pool of descriptor set info, each descriptor set must have /// information such as type, index and amount of bindings. std::vector descriptorSetInfoPool; VkDescriptorPool descriptorPool{VK_NULL_HANDLE}; /// Timestamp query. VkQueryPool queryPool{VK_NULL_HANDLE}; // Number of nonoseconds for timestamp to increase 1 float timestampPeriod{0.f}; /// Computation pipeline. VkPipeline pipeline{VK_NULL_HANDLE}; VkCommandPool commandPool{VK_NULL_HANDLE}; std::vector commandBuffers; //===--------------------------------------------------------------------===// // Vulkan memory context. //===--------------------------------------------------------------------===// uint32_t queueFamilyIndex{0}; VkQueueFamilyProperties queueFamilyProperties{}; uint32_t hostMemoryTypeIndex{VK_MAX_MEMORY_TYPES}; uint32_t deviceMemoryTypeIndex{VK_MAX_MEMORY_TYPES}; VkDeviceSize memorySize{0}; //===--------------------------------------------------------------------===// // Vulkan execution context. //===--------------------------------------------------------------------===// NumWorkGroups numWorkGroups; const char *entryPoint{nullptr}; uint8_t *binary{nullptr}; uint32_t binarySize{0}; //===--------------------------------------------------------------------===// // Vulkan resource data and storage classes. //===--------------------------------------------------------------------===// ResourceData resourceData; ResourceStorageClassBindingMap resourceStorageClassData; }; #endif