Spaces:
Runtime error
Runtime error
// SPDX-License-Identifier: Apache-2.0 | |
namespace kp { | |
Algorithm::~Algorithm() | |
{ | |
KP_LOG_DEBUG("Kompute Algorithm Destructor started"); | |
this->destroy(); | |
} | |
bool | |
Algorithm::isInit() | |
{ | |
return this->mPipeline && this->mPipelineCache && this->mPipelineLayout && | |
this->mDescriptorPool && this->mDescriptorSet && | |
this->mDescriptorSetLayout && this->mShaderModule; | |
} | |
void | |
Algorithm::destroy() | |
{ | |
// We don't have to free memory on destroy as it's freed by the | |
// commandBuffer destructor if (this->mPushConstantsData) { | |
// free(this->mPushConstantsData); | |
// } | |
// if (this->mSpecializationConstantsData) { | |
// free(this->mSpecializationConstantsData); | |
// } | |
if (!this->mDevice) { | |
KP_LOG_WARN("Kompute Algorithm destroy function reached with null " | |
"Device pointer"); | |
return; | |
} | |
if (this->mFreePipeline && this->mPipeline) { | |
KP_LOG_DEBUG("Kompute Algorithm Destroying pipeline"); | |
if (!this->mPipeline) { | |
KP_LOG_WARN("Kompute Algorithm Error requested to destroy " | |
"pipeline but it is null"); | |
} | |
this->mDevice->destroy( | |
*this->mPipeline, | |
(vk::Optional<const vk::AllocationCallbacks>)nullptr); | |
this->mPipeline = nullptr; | |
} | |
if (this->mFreePipelineLayout && this->mPipelineLayout) { | |
KP_LOG_DEBUG("Kompute Algorithm Destroying pipeline layout"); | |
if (!this->mPipelineLayout) { | |
KP_LOG_WARN("Kompute Algorithm Error requested to destroy " | |
"pipeline layout but it is null"); | |
} | |
this->mDevice->destroy( | |
*this->mPipelineLayout, | |
(vk::Optional<const vk::AllocationCallbacks>)nullptr); | |
this->mPipelineLayout = nullptr; | |
} | |
if (this->mFreeShaderModule && this->mShaderModule) { | |
KP_LOG_DEBUG("Kompute Algorithm Destroying shader module"); | |
if (!this->mShaderModule) { | |
KP_LOG_WARN("Kompute Algorithm Error requested to destroy shader " | |
"module but it is null"); | |
} | |
this->mDevice->destroy( | |
*this->mShaderModule, | |
(vk::Optional<const vk::AllocationCallbacks>)nullptr); | |
this->mShaderModule = nullptr; | |
} | |
freeParameters(); | |
} | |
void | |
Algorithm::freeParameters() | |
{ | |
if (this->mFreeDescriptorSetLayout && this->mDescriptorSetLayout) { | |
KP_LOG_DEBUG("Kompute Algorithm Destroying Descriptor Set Layout"); | |
if (!this->mDescriptorSetLayout) { | |
KP_LOG_WARN("Kompute Algorithm Error requested to destroy " | |
"descriptor set layout but it is null"); | |
} | |
this->mDevice->destroy( | |
*this->mDescriptorSetLayout, | |
(vk::Optional<const vk::AllocationCallbacks>)nullptr); | |
this->mDescriptorSetLayout = nullptr; | |
} | |
} | |
void | |
Algorithm::createParameters() | |
{ | |
KP_LOG_DEBUG("Kompute Algorithm createParameters started"); | |
if (!*this->mDescriptorPool) { | |
KP_LOG_ERROR("Kompute Algorithm can not create descriptor pool"); | |
return; | |
} | |
std::vector<vk::DescriptorSetLayoutBinding> descriptorSetBindings; | |
for (size_t i = 0; i < this->mTensors.size(); i++) { | |
descriptorSetBindings.push_back( | |
vk::DescriptorSetLayoutBinding(i, // Binding index | |
vk::DescriptorType::eStorageBuffer, | |
1, // Descriptor count | |
vk::ShaderStageFlagBits::eCompute)); | |
} | |
// This is the component that is fed into the pipeline | |
vk::DescriptorSetLayoutCreateInfo descriptorSetLayoutInfo( | |
vk::DescriptorSetLayoutCreateFlags(), | |
static_cast<uint32_t>(descriptorSetBindings.size()), | |
descriptorSetBindings.data()); | |
KP_LOG_DEBUG("Kompute Algorithm creating descriptor set layout"); | |
this->mDescriptorSetLayout = std::make_shared<vk::DescriptorSetLayout>(); | |
vk::Result result = this->mDevice->createDescriptorSetLayout( | |
&descriptorSetLayoutInfo, nullptr, this->mDescriptorSetLayout.get()); | |
if (result != vk::Result::eSuccess) { | |
KP_LOG_ERROR("Failed to create descriptor set layout. Error code: {}", vk::to_string(result)); | |
} else { | |
this->mFreeDescriptorSetLayout = true; | |
KP_LOG_DEBUG("Successfully allocated descriptor set layout."); | |
} | |
vk::DescriptorSetAllocateInfo descriptorSetAllocateInfo( | |
*this->mDescriptorPool, | |
1, // Descriptor set layout count | |
this->mDescriptorSetLayout.get()); | |
KP_LOG_DEBUG("Kompute Algorithm allocating descriptor sets"); | |
this->mDescriptorSet = std::make_shared<vk::DescriptorSet>(); | |
result = this->mDevice->allocateDescriptorSets(&descriptorSetAllocateInfo, | |
this->mDescriptorSet.get()); | |
if (result != vk::Result::eSuccess) { | |
KP_LOG_ERROR("Failed to allocate descriptor sets. Error code: {}", vk::to_string(result)); | |
} else { | |
this->mFreeDescriptorSet = true; | |
KP_LOG_DEBUG("Successfully allocated descriptor sets."); | |
} | |
this->mFreeDescriptorSet = true; | |
KP_LOG_DEBUG("Kompute Algorithm updating descriptor sets"); | |
for (size_t i = 0; i < this->mTensors.size(); i++) { | |
std::vector<vk::WriteDescriptorSet> computeWriteDescriptorSets; | |
vk::DescriptorBufferInfo descriptorBufferInfo = | |
this->mTensors[i]->constructDescriptorBufferInfo(); | |
computeWriteDescriptorSets.push_back( | |
vk::WriteDescriptorSet(*this->mDescriptorSet, | |
i, // Destination binding | |
0, // Destination array element | |
1, // Descriptor count | |
vk::DescriptorType::eStorageBuffer, | |
nullptr, // Descriptor image info | |
&descriptorBufferInfo)); | |
this->mDevice->updateDescriptorSets(computeWriteDescriptorSets, | |
nullptr); | |
} | |
KP_LOG_DEBUG("Kompute Algorithm successfully run init"); | |
} | |
void | |
Algorithm::updateParameters() | |
{ | |
KP_LOG_DEBUG("Kompute Algorithm updateParameters started"); | |
if (!*this->mDescriptorPool) { | |
KP_LOG_ERROR("Kompute Algorithm can not create descriptor pool"); | |
return; | |
} | |
vk::DescriptorSetAllocateInfo descriptorSetAllocateInfo( | |
*this->mDescriptorPool, | |
1, // Descriptor set layout count | |
this->mDescriptorSetLayout.get()); | |
KP_LOG_DEBUG("Kompute Algorithm allocating descriptor sets"); | |
this->mDescriptorSet = std::make_shared<vk::DescriptorSet>(); | |
vk::Result result = this->mDevice->allocateDescriptorSets(&descriptorSetAllocateInfo, | |
this->mDescriptorSet.get()); | |
if (result != vk::Result::eSuccess) { | |
KP_LOG_ERROR("Failed to allocate descriptor sets. Error code: {}", vk::to_string(result)); | |
} else { | |
this->mFreeDescriptorSet = true; | |
KP_LOG_DEBUG("Successfully allocated descriptor sets."); | |
} | |
this->mFreeDescriptorSet = true; | |
KP_LOG_DEBUG("Kompute Algorithm updating descriptor sets"); | |
for (size_t i = 0; i < this->mTensors.size(); i++) { | |
std::vector<vk::WriteDescriptorSet> computeWriteDescriptorSets; | |
vk::DescriptorBufferInfo descriptorBufferInfo = | |
this->mTensors[i]->constructDescriptorBufferInfo(); | |
computeWriteDescriptorSets.push_back( | |
vk::WriteDescriptorSet(*this->mDescriptorSet, | |
i, // Destination binding | |
0, // Destination array element | |
1, // Descriptor count | |
vk::DescriptorType::eStorageBuffer, | |
nullptr, // Descriptor image info | |
&descriptorBufferInfo)); | |
this->mDevice->updateDescriptorSets(computeWriteDescriptorSets, | |
nullptr); | |
} | |
KP_LOG_DEBUG("Kompute Algorithm successfully run init"); | |
} | |
void | |
Algorithm::createShaderModule() | |
{ | |
KP_LOG_DEBUG("Kompute Algorithm createShaderModule started"); | |
vk::ShaderModuleCreateInfo shaderModuleInfo(vk::ShaderModuleCreateFlags(), | |
sizeof(uint32_t) * | |
this->mSpirv.size(), | |
this->mSpirv.data()); | |
KP_LOG_DEBUG("Kompute Algorithm Creating shader module. ShaderFileSize: {}", | |
this->mSpirv.size()); | |
this->mFreeShaderModule = true; | |
this->mShaderModule = std::make_shared<vk::ShaderModule>(); | |
this->mDevice->createShaderModule( | |
&shaderModuleInfo, nullptr, this->mShaderModule.get()); | |
this->mFreeShaderModule = true; | |
KP_LOG_DEBUG("Kompute Algorithm create shader module success"); | |
} | |
void | |
Algorithm::createPipeline() | |
{ | |
KP_LOG_DEBUG("Kompute Algorithm calling create Pipeline"); | |
vk::PipelineLayoutCreateInfo pipelineLayoutInfo( | |
vk::PipelineLayoutCreateFlags(), | |
1, // Set layout count | |
this->mDescriptorSetLayout.get()); | |
vk::PushConstantRange pushConstantRange; | |
if (this->mPushConstantsSize) { | |
pushConstantRange.setStageFlags(vk::ShaderStageFlagBits::eCompute); | |
pushConstantRange.setOffset(0); | |
pushConstantRange.setSize(this->mPushConstantsDataTypeMemorySize * | |
this->mPushConstantsSize); | |
pipelineLayoutInfo.setPushConstantRangeCount(1); | |
pipelineLayoutInfo.setPPushConstantRanges(&pushConstantRange); | |
} | |
this->mPipelineLayout = std::make_shared<vk::PipelineLayout>(); | |
this->mDevice->createPipelineLayout( | |
&pipelineLayoutInfo, nullptr, this->mPipelineLayout.get()); | |
this->mFreePipelineLayout = true; | |
std::vector<vk::SpecializationMapEntry> specializationEntries; | |
for (uint32_t i = 0; i < this->mSpecializationConstantsSize; i++) { | |
vk::SpecializationMapEntry specializationEntry( | |
static_cast<uint32_t>(i), | |
static_cast<uint32_t>( | |
this->mSpecializationConstantsDataTypeMemorySize * i), | |
this->mSpecializationConstantsDataTypeMemorySize); | |
specializationEntries.push_back(specializationEntry); | |
} | |
// This passes ownership of the memory so we remove ownership from | |
// specialization container by using "transferDataOwnership" | |
vk::SpecializationInfo specializationInfo( | |
static_cast<uint32_t>(specializationEntries.size()), | |
specializationEntries.data(), | |
this->mSpecializationConstantsDataTypeMemorySize * | |
this->mSpecializationConstantsSize, | |
this->mSpecializationConstantsData); | |
vk::PipelineShaderStageCreateInfo shaderStage( | |
vk::PipelineShaderStageCreateFlags(), | |
vk::ShaderStageFlagBits::eCompute, | |
*this->mShaderModule, | |
"main", | |
&specializationInfo); | |
vk::ComputePipelineCreateInfo pipelineInfo(vk::PipelineCreateFlags(), | |
shaderStage, | |
*this->mPipelineLayout, | |
vk::Pipeline(), | |
0); | |
vk::ResultValue<vk::Pipeline> pipelineResult = | |
this->mDevice->createComputePipeline(*mPipelineCache, pipelineInfo); | |
if (pipelineResult.result != vk::Result::eSuccess) { | |
throw std::runtime_error("Failed to create pipeline result: " + | |
vk::to_string(pipelineResult.result)); | |
} | |
vk::Pipeline& pipeline = pipelineResult.value; | |
this->mPipeline = std::make_shared<vk::Pipeline>(pipeline); | |
this->mFreePipeline = true; | |
vk::Pipeline pipeline = | |
this->mDevice->createComputePipeline(*mPipelineCache, pipelineInfo) | |
.value; | |
this->mPipeline = std::make_shared<vk::Pipeline>(pipeline); | |
this->mFreePipeline = true; | |
// TODO: Update to consistent | |
// this->mPipeline = std::make_shared<vk::Pipeline>(); | |
// this->mDevice->createComputePipelines( | |
// *this->mPipelineCache, 1, &pipelineInfo, nullptr, | |
// this->mPipeline.get()); | |
KP_LOG_DEBUG("Kompute Algorithm Create Pipeline Success"); | |
} | |
void | |
Algorithm::recordBindCore(const vk::CommandBuffer& commandBuffer) | |
{ | |
KP_LOG_DEBUG("Kompute Algorithm binding pipeline"); | |
commandBuffer.bindPipeline(vk::PipelineBindPoint::eCompute, | |
*this->mPipeline); | |
KP_LOG_DEBUG("Kompute Algorithm binding descriptor sets"); | |
commandBuffer.bindDescriptorSets(vk::PipelineBindPoint::eCompute, | |
*this->mPipelineLayout, | |
0, // First set | |
*this->mDescriptorSet, | |
nullptr // Dispatcher | |
); | |
} | |
void | |
Algorithm::recordBindPush(const vk::CommandBuffer& commandBuffer) | |
{ | |
if (this->mPushConstantsSize) { | |
KP_LOG_DEBUG("Kompute Algorithm binding push constants memory size: {}", | |
this->mPushConstantsSize * | |
this->mPushConstantsDataTypeMemorySize); | |
commandBuffer.pushConstants(*this->mPipelineLayout, | |
vk::ShaderStageFlagBits::eCompute, | |
0, | |
this->mPushConstantsSize * | |
this->mPushConstantsDataTypeMemorySize, | |
this->mPushConstantsData); | |
} | |
} | |
void | |
Algorithm::recordDispatch(const vk::CommandBuffer& commandBuffer) | |
{ | |
KP_LOG_DEBUG("Kompute Algorithm recording dispatch"); | |
commandBuffer.dispatch( | |
this->mWorkgroup[0], this->mWorkgroup[1], this->mWorkgroup[2]); | |
} | |
void | |
Algorithm::setWorkgroup(const Workgroup& workgroup, uint32_t minSize) | |
{ | |
KP_LOG_INFO("Kompute OpAlgoCreate setting dispatch size"); | |
// The dispatch size is set up based on either explicitly provided template | |
// parameters or by default it would take the shape and size of the tensors | |
if (workgroup[0] > 0) { | |
// If at least the x value is provided we use mainly the parameters | |
// provided | |
this->mWorkgroup = { workgroup[0], | |
workgroup[1] > 0 ? workgroup[1] : 1, | |
workgroup[2] > 0 ? workgroup[2] : 1 }; | |
} else { | |
this->mWorkgroup = { minSize, 1, 1 }; | |
} | |
KP_LOG_INFO("Kompute OpAlgoCreate set dispatch size X: {}, Y: {}, Z: {}", | |
this->mWorkgroup[0], | |
this->mWorkgroup[1], | |
this->mWorkgroup[2]); | |
} | |
const Workgroup& | |
Algorithm::getWorkgroup() | |
{ | |
return this->mWorkgroup; | |
} | |
const std::vector<std::shared_ptr<Tensor>>& | |
Algorithm::getTensors() | |
{ | |
return this->mTensors; | |
} | |
void Algorithm::setTensors(const std::vector<std::shared_ptr<Tensor>>& tensors) | |
{ | |
this->mTensors = tensors; | |
} | |
} | |