Vulkan Schnee 0.0.1
High-performance rendering engine
Loading...
Searching...
No Matches
ComputePass.cpp
Go to the documentation of this file.
2
3#include <stdexcept>
4
8
9namespace EngineCore {
10 ComputePass::ComputePass(const std::string &name ) : name( name ) {}
11
13 VkDevice device,
14 const VkPipelineLayoutCreateInfo * pPipelineLayoutCreateInfo,
15 const VkDescriptorSetLayoutCreateInfo * pDescriptorSetLayoutCreateInfo,
16 std::string shaderName,
17 const std::optional<const PipelineSpecializationData *> pSpecializationData
18 )
19 {
20 assert(pDescriptorSetLayoutCreateInfo != nullptr);
21 VulkanHelper::createDescriptorSetLayout(device, pDescriptorSetLayoutCreateInfo, nullptr, &descriptorSetLayout, name.append(" Descriptor Set Layout"));
22
23 assert(pPipelineLayoutCreateInfo != nullptr);
24
25 // Validate inputs before creation
26 if (device == VK_NULL_HANDLE) {
27 throw std::runtime_error("Invalid device handle in ComputePass::create");
28 }
29 if (descriptorSetLayout == VK_NULL_HANDLE) {
30 throw std::runtime_error("Descriptor set layout creation failed in ComputePass::create");
31 }
32
33 // Create a local copy of the pipeline layout create info and update it to use the newly created descriptor set layout
34 VkPipelineLayoutCreateInfo localPipelineLayoutCreateInfo = *pPipelineLayoutCreateInfo;
35 localPipelineLayoutCreateInfo.setLayoutCount = 1;
36 localPipelineLayoutCreateInfo.pSetLayouts = &descriptorSetLayout;
37
38 PLOGD << "Creating pipeline layout for ComputePass: " << name;
39 VulkanHelper::createPipelineLayout(device, &localPipelineLayoutCreateInfo, nullptr, &pipelineLayout, name.append(" Pipeline Layout"));
40
41 // Validate the result
42 if (pipelineLayout == VK_NULL_HANDLE) {
43 throw std::runtime_error("Pipeline layout creation failed - returned null handle in ComputePass::create");
44 }
45
46 // Log the handle value for debugging
47 PLOGD << "Created pipeline layout with handle: 0x" << std::hex << pipelineLayout;
48
49 computePipeline = new ComputePipeline(device, pipelineLayout, shaderName, pSpecializationData);
50
51 if (pSpecializationData)
52 extractSpecializationData(pSpecializationData);
53
54 PLOGI << "Created ComputePass " << name;
55 }
56
57 uint32_t ComputePass::getThreadCount() const {
58 return threadCount;
59 }
60
63
67
69 std::optional<const PipelineSpecializationData *> pSpecializationData
70 ) {
71 if (!pSpecializationData.has_value())
72 {
73 PLOGE << "Specialization Data is empty! This will cause the Dispatcher Compute Pass for " << getName() << " to have a thread count of 1. This applies for both this compute pass as well as for the assumed size of the next pass. Fix this as this will cause performance problems!";
74 threadCount = 1;
76 return;
77 }
78 const auto specializationData = dynamic_cast<const DispatcherComputePipelineSpecializationData*>(pSpecializationData.value());
79 threadCount = specializationData->getThreadCount();
80 targetThreadCount = specializationData->getThreadCount();
81 }
82
83 VkPipelineLayout& ComputePass::getPipelineLayout() {
84 return pipelineLayout;
85 }
86
90
91 VkDescriptorSetLayout& ComputePass::getDescriptorSetLayout()
92 {
94 }
95
96 VkPushConstantsInfo ComputePass::createPushConstantsInfo(uint32_t size, const void* pValues) const
97 {
98 assert(pipelineLayout);
99 return {
100 .sType = VK_STRUCTURE_TYPE_PUSH_CONSTANTS_INFO,
101 .pNext = nullptr,
102 .layout = pipelineLayout,
103 .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
104 .offset = 0,
105 .size = size,
106 .pValues = pValues
107 };
108 }
109
110 void ComputePass::createDescriptorSet(VkDevice device, uint32_t frameInFlightIndex, VkDescriptorPool descriptorPool) {
111 assert(descriptorPool != VK_NULL_HANDLE);
112 VkDescriptorSetAllocateInfo descriptorSetAllocateInfo{
113 .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
114 .descriptorPool = descriptorPool,
115 .descriptorSetCount = 1u,
116 .pSetLayouts = &descriptorSetLayout
117 };
118 VulkanHelper::allocateDescriptorSets(device, &descriptorSetAllocateInfo, &descriptorSet[frameInFlightIndex], getName());
119 PLOGI << "Created descriptor set: " << VulkanHelper::getDebugName( descriptorSet[frameInFlightIndex] );
120 }
121
123 PLOGI << "Creating descriptor set " << VulkanHelper::getDebugName( computePipeline ) << " for eye " << frameInFlightIndex;
126 }
127
128 VkDescriptorSet ComputePass::getDescriptorSet(uint32_t frameInFlightIndex) const {
129 assert(descriptorSet.size() > frameInFlightIndex);
130 return descriptorSet[frameInFlightIndex];
131 }
132
133 void ComputePass::bindDescriptorSets(VkCommandBuffer commandBuffer, uint32_t frameInFlightIndex) {
134 vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipelineLayout, 0, 1u, &descriptorSet[frameInFlightIndex], 0u, nullptr);
135 }
136
137 void ComputePass::cleanup(VkDevice device) {
138 // Guard against multiple cleanup calls
139 if (cleanedUp) {
140 PLOGW << "ComputePass::cleanup() called multiple times for " << name << ". Ignoring subsequent calls.";
141 return;
142 }
143 cleanedUp = true;
144
145 if (computePipeline != nullptr) {
146 computePipeline->cleanup();
147 delete computePipeline;
148 computePipeline = nullptr;
149 }
150
151 if (pipelineLayout != VK_NULL_HANDLE) {
152 vkDestroyPipelineLayout(device, pipelineLayout, nullptr);
153 pipelineLayout = VK_NULL_HANDLE;
154 }
155
156 if (descriptorSetLayout != VK_NULL_HANDLE) {
157 vkDestroyDescriptorSetLayout(device, descriptorSetLayout, nullptr);
158 descriptorSetLayout = VK_NULL_HANDLE;
159 }
160 }
161
163 cleanup(context->getVkDevice());
164 }
165
166 void ComputePass::extractSpecializationData(std::optional<const PipelineSpecializationData*> pSpecializationData) {
167 if ( !pSpecializationData.has_value() )
168 return;
169
170 const auto specializationPtr = dynamic_cast<const ComputePipelineSpecializationData*>(pSpecializationData.value());
171 threadCount = specializationPtr->getThreadCount();
172 }
173}
The application context is the core class which stores the basic openxr and vulkan objects.
const VkDevice getVkDevice() const
Gets the vulkan device.
std::array< VkDescriptorSet, MAX_FRAMES_IN_FLIGHT > descriptorSet
VkDescriptorSetLayout descriptorSetLayout
void createDescriptorSet(VkDevice device, uint32_t frameInFlightIndex, VkDescriptorPool descriptorPool)
Creates a vulkan descriptor set resource for a frame in flight into a specified descriptor pool.
DescriptorSetUpdater & updateDescriptorSet(uint32_t frameInFlightIndex)
Creates a descriptor set updater which is used to batch update descriptor set resources.
DescriptorSetUpdater descriptorSetBuilder
std::string getName() const
virtual void extractSpecializationData(std::optional< const PipelineSpecializationData * > pSpecializationData)
uint32_t getThreadCount() const
Gets the amount of threads this compute shader is running on on the GPU.
void bindDescriptorSets(VkCommandBuffer commandBuffer, uint32_t frameInFlightIndex)
Binds the descriptor set of a frame in flight.
void create(VkDevice device, const VkPipelineLayoutCreateInfo *pPipelineLayoutCreateInfo, const VkDescriptorSetLayoutCreateInfo *pDescriptorSetLayoutCreateInfo, std::string shaderName, std::optional< const PipelineSpecializationData * > pSpecializationData)
Creates a whole compute pass with a layout and everything. This is one of two steps needed to create ...
ComputePass(const std::string &name)
VkPipelineLayout & getPipelineLayout()
Gets the layout of this compute pipeline.
VkPipelineLayout pipelineLayout
VkPushConstantsInfo createPushConstantsInfo(uint32_t size, const void *pValues) const
Used to create preconfigured push constants where you only pass in the size of the push constant and ...
ComputePipeline * computePipeline
void cleanup(VkDevice device)
Cleanup of owned resources using direct VkDevice handle.
VkDescriptorSet getDescriptorSet(uint32_t frameInFlightIndex) const
Getter for the descriptor set of this pipeline.
VkDescriptorSetLayout & getDescriptorSetLayout()
Gets the descriptor set layout associated with this pipeline.
ComputePipeline * getComputePipeline()
Getter for the raw compute pipeline.
Wrapper for shader specialization data for compute pipelines. This usually only stores the thread cou...
A wrapper for vulkan pipeline resources. In this case a typesafe compute pipeline.
The Descriptor set updater is used to create a list of descriptor set writes which are executed with ...
void extractSpecializationData(std::optional< const PipelineSpecializationData * > pSpecializationData) override
DispatcherComputePass(const std::string &name)
static VkResult createPipelineLayout(VkDevice device, const VkPipelineLayoutCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkPipelineLayout *pPipelineLayout, const std::string &name)
static std::string getDebugName(VulkanObjectType objectHandle)
static VkResult allocateDescriptorSets(VkDevice device, const VkDescriptorSetAllocateInfo *pAllocateInfo, VkDescriptorSet *pDescriptorSets, const std::string &name)
static VkResult createDescriptorSetLayout(VkDevice device, const VkDescriptorSetLayoutCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkDescriptorSetLayout *pSetLayout, const std::string &name)
Log category system implementation.