LCOV - code coverage report
Current view: top level - src/include/kompute - Algorithm.hpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 61 63 96.8 %
Date: 2024-01-20 13:42:20 Functions: 13 15 86.7 %

          Line data    Source code
       1             : // SPDX-License-Identifier: Apache-2.0
       2             : #pragma once
       3             : 
       4             : #include "kompute/Core.hpp"
       5             : 
       6             : #include "fmt/format.h"
       7             : #include "kompute/Tensor.hpp"
       8             : #include "logger/Logger.hpp"
       9             : 
      10             : namespace kp {
      11             : 
      12             : /**
      13             :     Abstraction for compute shaders that are run on top of tensors grouped via
      14             :    ParameterGroups (which group descriptorsets)
      15             : */
      16             : class Algorithm
      17             : {
      18             :   public:
      19             :     /**
      20             :      *  Main constructor for algorithm with configuration parameters to create
      21             :      *  the underlying resources.
      22             :      *
      23             :      *  @param device The Vulkan device to use for creating resources
      24             :      *  @param tensors (optional) The tensors to use to create the descriptor
      25             :      * resources
      26             :      *  @param spirv (optional) The spirv code to use to create the algorithm
      27             :      *  @param workgroup (optional) The kp::Workgroup to use for the dispatch
      28             :      * which defaults to kp::Workgroup(tensor[0].size(), 1, 1) if not set.
      29             :      *  @param specializationConstants (optional) The templatable param is to be
      30             :      * used to initialize the specialization constants which cannot be changed
      31             :      * once set.
      32             :      *  @param pushConstants (optional) This templatable param is to be used
      33             :      * when initializing the pipeline, which set the size of the push constants
      34             :      * - these can be modified but all new values must have the same data type
      35             :      * and length as otherwise it will result in errors.
      36             :      */
      37             :     template<typename S = float, typename P = float>
      38          37 :     Algorithm(std::shared_ptr<vk::Device> device,
      39             :               const std::vector<std::shared_ptr<Tensor>>& tensors = {},
      40             :               const std::vector<uint32_t>& spirv = {},
      41             :               const Workgroup& workgroup = {},
      42             :               const std::vector<S>& specializationConstants = {},
      43             :               const std::vector<P>& pushConstants = {})
      44          37 :     {
      45          74 :         KP_LOG_DEBUG("Kompute Algorithm Constructor with device");
      46             : 
      47          37 :         this->mDevice = device;
      48             : 
      49          37 :         if (tensors.size() && spirv.size()) {
      50          99 :             KP_LOG_INFO(
      51             :               "Kompute Algorithm initialising with tensor size: {} and "
      52             :               "spirv size: {}",
      53             :               tensors.size(),
      54             :               spirv.size());
      55          33 :             this->rebuild(tensors,
      56             :                           spirv,
      57             :                           workgroup,
      58             :                           specializationConstants,
      59             :                           pushConstants);
      60             :         } else {
      61           8 :             KP_LOG_INFO(
      62             :               "Kompute Algorithm constructor with empty tensors and or "
      63             :               "spirv so not rebuilding vulkan components");
      64             :         }
      65          37 :     }
      66             : 
      67             :     /**
      68             :      *  Rebuild function to reconstruct algorithm with configuration parameters
      69             :      * to create the underlying resources.
      70             :      *
      71             :      *  @param tensors The tensors to use to create the descriptor resources
      72             :      *  @param spirv The spirv code to use to create the algorithm
      73             :      *  @param workgroup (optional) The kp::Workgroup to use for the dispatch
      74             :      * which defaults to kp::Workgroup(tensor[0].size(), 1, 1) if not set.
      75             :      *  @param specializationConstants (optional) The std::vector<float> to use
      76             :      * to initialize the specialization constants which cannot be changed once
      77             :      * set.
      78             :      *  @param pushConstants (optional) The std::vector<float> to use when
      79             :      * initializing the pipeline, which set the size of the push constants -
      80             :      * these can be modified but all new values must have the same vector size
      81             :      * as this initial value.
      82             :      */
      83             :     template<typename S = float, typename P = float>
      84          38 :     void rebuild(const std::vector<std::shared_ptr<Tensor>>& tensors,
      85             :                  const std::vector<uint32_t>& spirv,
      86             :                  const Workgroup& workgroup = {},
      87             :                  const std::vector<S>& specializationConstants = {},
      88             :                  const std::vector<P>& pushConstants = {})
      89             :     {
      90          76 :         KP_LOG_DEBUG("Kompute Algorithm rebuild started");
      91             : 
      92          38 :         this->mTensors = tensors;
      93          38 :         this->mSpirv = spirv;
      94             : 
      95          38 :         if (specializationConstants.size()) {
      96           6 :             if (this->mSpecializationConstantsData) {
      97           0 :                 free(this->mSpecializationConstantsData);
      98             :             }
      99           6 :             uint32_t memorySize =
     100             :               sizeof(decltype(specializationConstants.back()));
     101           6 :             uint32_t size = specializationConstants.size();
     102           6 :             uint32_t totalSize = size * memorySize;
     103           6 :             this->mSpecializationConstantsData = malloc(totalSize);
     104          12 :             memcpy(this->mSpecializationConstantsData,
     105           6 :                    specializationConstants.data(),
     106             :                    totalSize);
     107           6 :             this->mSpecializationConstantsDataTypeMemorySize = memorySize;
     108           6 :             this->mSpecializationConstantsSize = size;
     109             :         }
     110             : 
     111          38 :         if (pushConstants.size()) {
     112           8 :             if (this->mPushConstantsData) {
     113           0 :                 free(this->mPushConstantsData);
     114             :             }
     115           8 :             uint32_t memorySize = sizeof(decltype(pushConstants.back()));
     116           8 :             uint32_t size = pushConstants.size();
     117           8 :             uint32_t totalSize = size * memorySize;
     118           8 :             this->mPushConstantsData = malloc(totalSize);
     119           8 :             memcpy(this->mPushConstantsData, pushConstants.data(), totalSize);
     120           8 :             this->mPushConstantsDataTypeMemorySize = memorySize;
     121           8 :             this->mPushConstantsSize = size;
     122             :         }
     123             : 
     124          76 :         this->setWorkgroup(
     125          76 :           workgroup, this->mTensors.size() ? this->mTensors[0]->size() : 1);
     126             : 
     127             :         // Descriptor pool is created first so if available then destroy all
     128             :         // before rebuild
     129          38 :         if (this->isInit()) {
     130           1 :             this->destroy();
     131             :         }
     132             : 
     133          38 :         this->createParameters();
     134          38 :         this->createShaderModule();
     135          38 :         this->createPipeline();
     136          38 :     }
     137             : 
     138             :     /**
     139             :      * Destructor for Algorithm which is responsible for freeing and desroying
     140             :      * respective pipelines and owned parameter groups.
     141             :      */
     142             :     ~Algorithm();
     143             : 
     144             :     /**
     145             :      * Records the dispatch function with the provided template parameters or
     146             :      * alternatively using the size of the tensor by default.
     147             :      *
     148             :      * @param commandBuffer Command buffer to record the algorithm resources to
     149             :      */
     150             :     void recordDispatch(const vk::CommandBuffer& commandBuffer);
     151             : 
     152             :     /**
     153             :      * Records command that binds the "core" algorithm components which consist
     154             :      * of binding the pipeline and binding the descriptorsets.
     155             :      *
     156             :      * @param commandBuffer Command buffer to record the algorithm resources to
     157             :      */
     158             :     void recordBindCore(const vk::CommandBuffer& commandBuffer);
     159             : 
     160             :     /**
     161             :      * Records command that binds the push constants to the command buffer
     162             :      * provided
     163             :      * - it is required that the pushConstants provided are of the same size as
     164             :      * the ones provided during initialization.
     165             :      *
     166             :      * @param commandBuffer Command buffer to record the algorithm resources to
     167             :      */
     168             :     void recordBindPush(const vk::CommandBuffer& commandBuffer);
     169             : 
     170             :     /**
     171             :      * function that checks all the gpu resource components to verify if these
     172             :      * have been created and returns true if all are valid.
     173             :      *
     174             :      * @returns returns true if the algorithm is currently initialized.
     175             :      */
     176             :     bool isInit();
     177             : 
     178             :     /**
     179             :      * Sets the work group to use in the recordDispatch
     180             :      *
     181             :      * @param workgroup The kp::Workgroup value to use to update the algorithm.
     182             :      * It must have a value greater than 1 on the x value (index 1) otherwise it
     183             :      * will be initialized on the size of the first tensor (ie.
     184             :      * this->mTensor[0]->size())
     185             :      */
     186             :     void setWorkgroup(const Workgroup& workgroup, uint32_t minSize = 1);
     187             :     /**
     188             :      * Sets the push constants to the new value provided to use in the next
     189             :      * bindPush()
     190             :      *
     191             :      * @param pushConstants The templatable vector is to be used to set the push
     192             :      * constants to use in the next bindPush(...) calls. The constants provided
     193             :      * must be of the same size as the ones created during initialization.
     194             :      */
     195             :     template<typename T>
     196             :     void setPushConstants(const std::vector<T>& pushConstants)
     197             :     {
     198             :         uint32_t memorySize = sizeof(decltype(pushConstants.back()));
     199             :         uint32_t size = pushConstants.size();
     200             : 
     201             :         this->setPushConstants(pushConstants.data(), size, memorySize);
     202             :     }
     203             : 
     204             :     /**
     205             :      * Sets the push constants to the new value provided to use in the next
     206             :      * bindPush() with the raw memory block location and memory size to be used.
     207             :      *
     208             :      * @param data The raw data point to copy the data from, without modifying
     209             :      * the pointer.
     210             :      * @param size The number of data elements provided in the data
     211             :      * @param memorySize The memory size of each of the data elements in bytes.
     212             :      */
     213          11 :     void setPushConstants(void* data, uint32_t size, uint32_t memorySize)
     214             :     {
     215             : 
     216          11 :         uint32_t totalSize = memorySize * size;
     217          11 :         uint32_t previousTotalSize =
     218          11 :           this->mPushConstantsDataTypeMemorySize * this->mPushConstantsSize;
     219             : 
     220          11 :         if (totalSize != previousTotalSize) {
     221           2 :             throw std::runtime_error(fmt::format(
     222             :               "Kompute Algorithm push "
     223             :               "constant total memory size provided is {} but expected {} bytes",
     224             :               totalSize,
     225           2 :               previousTotalSize));
     226             :         }
     227          10 :         if (this->mPushConstantsData) {
     228          10 :             free(this->mPushConstantsData);
     229             :         }
     230             : 
     231          10 :         this->mPushConstantsData = malloc(totalSize);
     232          10 :         memcpy(this->mPushConstantsData, data, totalSize);
     233          10 :         this->mPushConstantsDataTypeMemorySize = memorySize;
     234          10 :         this->mPushConstantsSize = size;
     235          10 :     }
     236             : 
     237             :     /**
     238             :      * Gets the current workgroup from the algorithm.
     239             :      *
     240             :      * @param The kp::Constant to use to set the push constants to use in the
     241             :      * next bindPush(...) calls. The constants provided must be of the same size
     242             :      * as the ones created during initialization.
     243             :      */
     244             :     const Workgroup& getWorkgroup();
     245             :     /**
     246             :      * Gets the specialization constants of the current algorithm.
     247             :      *
     248             :      * @returns The std::vector<float> currently set for specialization
     249             :      * constants
     250             :      */
     251             :     template<typename T>
     252           1 :     const std::vector<T> getSpecializationConstants()
     253             :     {
     254           1 :         return { (T*)this->mSpecializationConstantsData,
     255           1 :                  ((T*)this->mSpecializationConstantsData) +
     256           1 :                    this->mSpecializationConstantsSize };
     257             :     }
     258             :     /**
     259             :      * Gets the specialization constants of the current algorithm.
     260             :      *
     261             :      * @returns The std::vector<float> currently set for push constants
     262             :      */
     263             :     template<typename T>
     264           1 :     const std::vector<T> getPushConstants()
     265             :     {
     266           1 :         return { (T*)this->mPushConstantsData,
     267           1 :                  ((T*)this->mPushConstantsData) + this->mPushConstantsSize };
     268             :     }
     269             :     /**
     270             :      * Gets the current tensors that are used in the algorithm.
     271             :      *
     272             :      * @returns The list of tensors used in the algorithm.
     273             :      */
     274             :     const std::vector<std::shared_ptr<Tensor>>& getTensors();
     275             : 
     276             :     void destroy();
     277             : 
     278             :   private:
     279             :     // -------------- NEVER OWNED RESOURCES
     280             :     std::shared_ptr<vk::Device> mDevice;
     281             :     std::vector<std::shared_ptr<Tensor>> mTensors;
     282             : 
     283             :     // -------------- OPTIONALLY OWNED RESOURCES
     284             :     std::shared_ptr<vk::DescriptorSetLayout> mDescriptorSetLayout;
     285             :     bool mFreeDescriptorSetLayout = false;
     286             :     std::shared_ptr<vk::DescriptorPool> mDescriptorPool;
     287             :     bool mFreeDescriptorPool = false;
     288             :     std::shared_ptr<vk::DescriptorSet> mDescriptorSet;
     289             :     bool mFreeDescriptorSet = false;
     290             :     std::shared_ptr<vk::ShaderModule> mShaderModule;
     291             :     bool mFreeShaderModule = false;
     292             :     std::shared_ptr<vk::PipelineLayout> mPipelineLayout;
     293             :     bool mFreePipelineLayout = false;
     294             :     std::shared_ptr<vk::PipelineCache> mPipelineCache;
     295             :     bool mFreePipelineCache = false;
     296             :     std::shared_ptr<vk::Pipeline> mPipeline;
     297             :     bool mFreePipeline = false;
     298             : 
     299             :     // -------------- ALWAYS OWNED RESOURCES
     300             :     std::vector<uint32_t> mSpirv;
     301             :     void* mSpecializationConstantsData = nullptr;
     302             :     uint32_t mSpecializationConstantsDataTypeMemorySize = 0;
     303             :     uint32_t mSpecializationConstantsSize = 0;
     304             :     void* mPushConstantsData = nullptr;
     305             :     uint32_t mPushConstantsDataTypeMemorySize = 0;
     306             :     uint32_t mPushConstantsSize = 0;
     307             :     Workgroup mWorkgroup;
     308             : 
     309             :     // Create util functions
     310             :     void createShaderModule();
     311             :     void createPipeline();
     312             : 
     313             :     // Parameters
     314             :     void createParameters();
     315             : };
     316             : 
     317             : } // End namespace kp

Generated by: LCOV version 1.14