Vulkan Schnee 0.0.1
High-performance rendering engine
Loading...
Searching...
No Matches
PipelineMaterialPayload.cpp
Go to the documentation of this file.
2
5
6#include <array>
8#include <iostream>
9#include <optional>
10#include <plog/Log.h>
11#include <sstream>
12
13namespace EngineCore {
14 std::vector<VkSpecializationMapEntry> ComputePipelineSpecializationData::getMapEntries() const {
15 return {
16 {
17 .constantID = 1,
18 .offset = offsetof(Data, localSizeX),
19 .size = sizeof(uint32_t),
20 }
21 };
22 }
23
24 std::vector<VkSpecializationMapEntry> DispatcherComputePipelineSpecializationData::getMapEntries() const {
25 return {
26 {
27 .constantID = 1,
28 .offset = offsetof(Data, localSizeX),
29 .size = sizeof(uint32_t),
30 },
31 {
32 .constantID = 2,
33 .offset = offsetof(Data, nextStageThreadCount),
34 .size = sizeof(uint32_t),
35 }
36 };
37 }
38
39 std::vector<VkSpecializationMapEntry> MeshShaderSpecializationData::getMapEntries() const {
40 return {
41 {
42 .constantID = 0, // SCREEN_WIDTH
43 .offset = offsetof(Data, screenWidth),
44 .size = sizeof(float),
45 },
46 {
47 .constantID = 1, // SCREEN_HEIGHT
48 .offset = offsetof(Data, screenHeight),
49 .size = sizeof(float),
50 }
51 };
52 }
53
54#if !defined(HEADLESS) && !defined(COMPUTE_DEBUG)
56 VkSampleCountFlagBits multisampling,
57 VkPipelineLayout pipelineLayout,
58 VkRenderPass renderPass,
59 const std::string& meshShaderFilename,
60 const std::string& fragmentShaderFilename,
61 const std::vector<VkVertexInputBindingDescription>& vertexInputBindingDescriptions,
62 const std::vector<VkVertexInputAttributeDescription>& vertexInputAttributeDescriptions,
64 std::optional<const MeshShaderSpecializationData*> meshShaderSpecialization,
65 bool depthOnly
66 )
68 {
69
70 this->pipelineData = pipelineData;
71 meshShaderName = meshShaderFilename;
72 fragShaderName = fragmentShaderFilename;
73
74 // Load the mesh shader
75 MeshShader shader = MeshShader(device, meshShaderFilename, fragmentShaderFilename);
76
77 // Set up mesh shader specialization info (for screen resolution)
78 VkSpecializationInfo meshSpecInfo{};
79 std::vector<VkSpecializationMapEntry> meshSpecEntries;
80 if (meshShaderSpecialization.has_value()) {
81 meshSpecEntries = meshShaderSpecialization.value()->getMapEntries();
82 meshSpecInfo = {
83 .mapEntryCount = static_cast<uint32_t>(meshSpecEntries.size()),
84 .pMapEntries = meshSpecEntries.data(),
85 .dataSize = meshShaderSpecialization.value()->getDataSize(),
86 .pData = meshShaderSpecialization.value()->getData()
87 };
88 }
89
90 VkPipelineShaderStageCreateInfo pipelineShaderStageCreateInfoMesh{
91 VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO
92 };
93 pipelineShaderStageCreateInfoMesh.module = shader.getMeshShader();
94 pipelineShaderStageCreateInfoMesh.stage = VK_SHADER_STAGE_MESH_BIT_EXT;
95 pipelineShaderStageCreateInfoMesh.pName = "main";
96 pipelineShaderStageCreateInfoMesh.pSpecializationInfo = meshShaderSpecialization.has_value() ? &meshSpecInfo : nullptr;
97
98 VkPipelineShaderStageCreateInfo pipelineShaderStageCreateInfoFragment{
99 VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO
100 };
101 pipelineShaderStageCreateInfoFragment.module = shader.getFragmentShader();
102 pipelineShaderStageCreateInfoFragment.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
103 pipelineShaderStageCreateInfoFragment.pName = "main";
104
105 const std::array shaderStages = { pipelineShaderStageCreateInfoMesh, pipelineShaderStageCreateInfoFragment };
106
107 VkPipelineViewportStateCreateInfo pipelineViewportStateCreateInfo{
108 VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO
109 };
110 pipelineViewportStateCreateInfo.viewportCount = 1u;
111 pipelineViewportStateCreateInfo.scissorCount = 1u;
112
113 VkPipelineRasterizationStateCreateInfo pipelineRasterizationStateCreateInfo{
114 VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO
115 };
116 pipelineRasterizationStateCreateInfo.polygonMode = VK_POLYGON_MODE_FILL;
117 pipelineRasterizationStateCreateInfo.lineWidth = 1.0f;
118 pipelineRasterizationStateCreateInfo.cullMode = pipelineData.cullMode;
119
120 VkPipelineMultisampleStateCreateInfo pipelineMultisampleStateCreateInfo{
121 VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO
122 };
123 pipelineMultisampleStateCreateInfo.rasterizationSamples = multisampling;
124
125 VkPipelineColorBlendStateCreateInfo pipelineColorBlendStateCreateInfo{
126 VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO
127 };
128 VkPipelineColorBlendAttachmentState pipelineColorBlendAttachmentState{};
129 pipelineColorBlendAttachmentState.colorWriteMask =
130 VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
131 pipelineColorBlendAttachmentState.blendEnable = VK_TRUE;
132 pipelineColorBlendAttachmentState.srcColorBlendFactor = pipelineData.srcColorBlendFactor;
133 pipelineColorBlendAttachmentState.dstColorBlendFactor = pipelineData.dstColorBlendFactor;
134 pipelineColorBlendAttachmentState.colorBlendOp = pipelineData.colorBlendOp;
135 pipelineColorBlendAttachmentState.srcAlphaBlendFactor = pipelineData.srcAlphaBlendFactor;
136 pipelineColorBlendAttachmentState.dstAlphaBlendFactor = pipelineData.dstAlphaBlendFactor;
137 pipelineColorBlendAttachmentState.alphaBlendOp = pipelineData.alphaBlendOp;
138
139 // Depth-only mode: no color attachments (enables "Double-Speed Z" on NVIDIA/AMD)
140 if (depthOnly) {
141 pipelineColorBlendStateCreateInfo.attachmentCount = 0;
142 pipelineColorBlendStateCreateInfo.pAttachments = nullptr;
143 } else {
144 pipelineColorBlendStateCreateInfo.attachmentCount = 1;
145 pipelineColorBlendStateCreateInfo.pAttachments = &pipelineColorBlendAttachmentState;
146 }
147
148 VkPipelineDynamicStateCreateInfo pipelineDynamicStateCreateInfo{
149 VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO
150 };
151 constexpr std::array dynamicStates = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR };
152 pipelineDynamicStateCreateInfo.dynamicStateCount = static_cast<uint32_t>(dynamicStates.size());
153 pipelineDynamicStateCreateInfo.pDynamicStates = dynamicStates.data();
154
155 VkPipelineDepthStencilStateCreateInfo pipelineDepthStencilStateCreateInfo{
156 VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO
157 };
158 pipelineDepthStencilStateCreateInfo.depthTestEnable = VK_TRUE;
159 pipelineDepthStencilStateCreateInfo.depthWriteEnable = VK_TRUE;
160 pipelineDepthStencilStateCreateInfo.depthCompareOp = VK_COMPARE_OP_GREATER; // Reverse-Z
161
162 // Dynamic rendering support - required when using vkCmdBeginRendering
163 constexpr VkFormat colorFormat = VK_FORMAT_R8G8B8A8_SRGB;
164 constexpr VkFormat depthFormat = VK_FORMAT_D32_SFLOAT;
165 VkPipelineRenderingCreateInfo pipelineRenderingCreateInfo{
166 .sType = VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO,
167 .viewMask = 0b11, // Stereo: both layers
168 .colorAttachmentCount = depthOnly ? 0u : 1u, // No color for depth-only pass
169 .pColorAttachmentFormats = depthOnly ? nullptr : &colorFormat,
170 .depthAttachmentFormat = depthFormat,
171 .stencilAttachmentFormat = VK_FORMAT_UNDEFINED
172 };
173
174 VkGraphicsPipelineCreateInfo graphicsPipelineCreateInfo{ VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO };
175 graphicsPipelineCreateInfo.pNext = (renderPass == VK_NULL_HANDLE) ? &pipelineRenderingCreateInfo : nullptr;
176 graphicsPipelineCreateInfo.layout = pipelineLayout;
177 graphicsPipelineCreateInfo.stageCount = static_cast<uint32_t>(shaderStages.size());
178 graphicsPipelineCreateInfo.pStages = shaderStages.data();
179 graphicsPipelineCreateInfo.pVertexInputState = nullptr;
180 graphicsPipelineCreateInfo.pInputAssemblyState = nullptr;
181 graphicsPipelineCreateInfo.pViewportState = &pipelineViewportStateCreateInfo;
182 graphicsPipelineCreateInfo.pRasterizationState = &pipelineRasterizationStateCreateInfo;
183 graphicsPipelineCreateInfo.pMultisampleState = &pipelineMultisampleStateCreateInfo;
184 graphicsPipelineCreateInfo.pColorBlendState = &pipelineColorBlendStateCreateInfo;
185 graphicsPipelineCreateInfo.pDynamicState = &pipelineDynamicStateCreateInfo;
186 graphicsPipelineCreateInfo.pDepthStencilState = &pipelineDepthStencilStateCreateInfo;
187 graphicsPipelineCreateInfo.renderPass = renderPass;
188
189 VkResult pipelineCreationResult = vkCreateGraphicsPipelines(device, nullptr, 1, &graphicsPipelineCreateInfo, nullptr, &pipeline);
190 if (pipelineCreationResult != VK_SUCCESS)
191 {
192 throw std::runtime_error("Failed to create vk graphics pipeline");
193 }
194
195 // These shader modules can now be destroyed
196 shader.destroyShaders(device);
197 valid = true;
198 }
199#else
201 VkDevice device,
202 VkSampleCountFlagBits multisampling,
203 VkPipelineLayout pipelineLayout,
204 VkRenderPass renderPass,
205 const std::string & vertexShaderName,
206 const std::string & fragmentShaderName
207 ) : device(device), multisampling(multisampling)
208 {
209 auto shader = VertexShader(device, vertexShaderName, fragmentShaderName);
210
211 VkPipelineShaderStageCreateInfo vertexStageInfo{
212 .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
213 .stage = VK_SHADER_STAGE_VERTEX_BIT,
214 .module = shader.getVertexShader(),
215 .pName = "main"
216 };
217
218 VkPipelineShaderStageCreateInfo fragmentStageInfo{
219 .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
220 .stage = VK_SHADER_STAGE_FRAGMENT_BIT,
221 .module = shader.getFragmentShader(),
222 .pName = "main"
223 };
224
225 const std::array shaderStages = { vertexStageInfo, fragmentStageInfo };
226
227 VkPipelineVertexInputStateCreateInfo vertexInputState{
228 .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
229 .vertexBindingDescriptionCount = 0,
230 .pVertexBindingDescriptions = nullptr,
231 .vertexAttributeDescriptionCount = 0,
232 .pVertexAttributeDescriptions = nullptr
233 };
234
235 VkPipelineInputAssemblyStateCreateInfo inputAssemblyState{
236 .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
237 .topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
238 .primitiveRestartEnable = VK_FALSE
239 };
240
241 VkPipelineViewportStateCreateInfo viewportState{
242 .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
243 .viewportCount = 1,
244 .pViewports = nullptr,
245 .scissorCount = 1,
246 .pScissors = nullptr
247 };
248
249 VkPipelineRasterizationStateCreateInfo rasterizationState{
250 .sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
251 .polygonMode = VK_POLYGON_MODE_FILL,
252 .cullMode = VK_CULL_MODE_NONE,
253 .frontFace = VK_FRONT_FACE_CLOCKWISE,
254 .lineWidth = 1.0f
255 };
256
257 VkPipelineMultisampleStateCreateInfo multisampleState{
258 .sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
259 .rasterizationSamples = multisampling
260 };
261
262 VkPipelineDepthStencilStateCreateInfo depthStencilState{
263 .sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,
264 .depthTestEnable = VK_FALSE,
265 .depthWriteEnable = VK_FALSE,
266 .depthCompareOp = VK_COMPARE_OP_GREATER // Reverse-Z
267 };
268
269 VkPipelineColorBlendAttachmentState colorBlendAttachment{
270 .blendEnable = VK_FALSE,
271 .colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT
272 };
273
274 VkPipelineColorBlendStateCreateInfo colorBlendState{
275 .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
276 .attachmentCount = 1,
277 .pAttachments = &colorBlendAttachment
278 };
279
280 constexpr std::array dynamicStates = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR };
281 VkPipelineDynamicStateCreateInfo dynamicState{
282 .sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,
283 .dynamicStateCount = static_cast<uint32_t>(dynamicStates.size()),
284 .pDynamicStates = dynamicStates.data()
285 };
286
287
288 // Define color format for dynamic rendering fallback
289 const VkFormat colorFormat = VK_FORMAT_R8G8B8A8_SRGB;
290
291 VkPipelineRenderingCreateInfo pipelineRenderingCreateInfo{
292 .sType = VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO,
293 .pNext = nullptr,
294 .viewMask = 0,
295 .colorAttachmentCount = 1,
296 .pColorAttachmentFormats = &colorFormat,
297 .depthAttachmentFormat = VK_FORMAT_UNDEFINED,
298 .stencilAttachmentFormat = VK_FORMAT_UNDEFINED
299 };
300
301 VkGraphicsPipelineCreateInfo graphicsPipelineCreateInfo{
302 .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
303 .pNext = (renderPass == VK_NULL_HANDLE) ? &pipelineRenderingCreateInfo : nullptr,
304 .flags = 0,
305 .stageCount = static_cast<uint32_t>(shaderStages.size()),
306 .pStages = shaderStages.data(),
307 .pVertexInputState = &vertexInputState,
308 .pInputAssemblyState = &inputAssemblyState,
309 .pTessellationState = nullptr,
310 .pViewportState = &viewportState,
311 .pRasterizationState = &rasterizationState,
312 .pMultisampleState = &multisampleState,
313 .pDepthStencilState = &depthStencilState,
314 .pColorBlendState = &colorBlendState,
315 .pDynamicState = &dynamicState,
316 .layout = pipelineLayout,
317 .renderPass = renderPass,
318 .subpass = 0,
319 .basePipelineHandle = VK_NULL_HANDLE,
320 .basePipelineIndex = -1
321 };
322
323 VkResult pipelineCreationResult = vkCreateGraphicsPipelines(device, nullptr, 1, &graphicsPipelineCreateInfo, nullptr, &pipeline);
324 if (pipelineCreationResult != VK_SUCCESS)
325 {
326 throw std::runtime_error("Failed to create vk graphics pipeline");
327 }
328
329 shader.destroyShaders( device );
330 valid = true;
331 }
332#endif
333
335 {
336 if (device && pipeline)
337 {
338 vkDestroyPipeline(device, pipeline, nullptr);
339 }
340 }
341
342 void GraphicsPipeline::bind(VkCommandBuffer commandBuffer) const
343 {
344 TRACY_ZONE_SCOPED_NAMED("Bind pipeline");
345 vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
346 }
347
349 {
350 return valid;
351 }
352
353 const std::string GraphicsPipeline::getMeshShaderName() const
354 {
355 return meshShaderName;
356 }
357
358 const std::string GraphicsPipeline::getFragShaderName() const
359 {
360 return fragShaderName;
361 }
362
368 {
369 return getMeshShaderName() == other.getMeshShaderName() &&
371 }
372}
373
374namespace EngineCore
375{
376 ComputePipeline::ComputePipeline(VkDevice device, VkPipelineLayout layout, std::string shaderFilename, std::optional<const PipelineSpecializationData *> pSpecializationData) : device(device), layout(layout)
377 {
378 computeShader = new ComputeShader(device, shaderFilename);
379
380 VkPipelineShaderStageCreateInfo computeShaderStageInfo{
381 .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
382 .stage = VK_SHADER_STAGE_COMPUTE_BIT,
383 .module = computeShader->getComputeShaderModule(),
384 .pName = "main",
385 .pSpecializationInfo = nullptr
386 };
387
388 VkSpecializationInfo specializationInfo{};
389 std::vector<VkSpecializationMapEntry> specializationData;
390 if (pSpecializationData.has_value()) {
391 specializationData = pSpecializationData.value()->getMapEntries();
392 specializationInfo = {
393 .mapEntryCount = static_cast<uint32_t>(specializationData.size()),
394 .pMapEntries = specializationData.data(),
395 .dataSize = pSpecializationData.value()->getDataSize(),
396 .pData = pSpecializationData.value()->getData()
397 };
398 computeShaderStageInfo.pSpecializationInfo = &specializationInfo;
399 }
400 else
401 {
402 specializationData = std::vector<VkSpecializationMapEntry>();
403 }
404
405 VkComputePipelineCreateInfo computePipelineCreateInfo{
406 .sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO,
407 .pNext = nullptr,
408 .flags = 0,
409 .stage = computeShaderStageInfo,
410 .layout = layout,
411 };
412
413 PLOG_FN_VK(vkCreateComputePipelines(device, VK_NULL_HANDLE, 1, &computePipelineCreateInfo, nullptr, &pipeline));
414 VulkanHelper::setObjectName(device, pipeline, "ComputePipeline");
415 }
416
418 {
419 // Only call cleanup if resources haven't been cleaned up yet
420 // This is safe because cleanup() properly nullifies handles
421 if (pipeline != VK_NULL_HANDLE || computeShader != nullptr) {
422 cleanup();
423 }
424 }
425
427 if (pipeline != VK_NULL_HANDLE) {
428 vkDestroyPipeline(device, pipeline, nullptr);
429 pipeline = VK_NULL_HANDLE; // Zero out the handle to prevent double-destruction
430 }
431 if (computeShader != nullptr) {
432 computeShader->destroyShaders(device);
433 delete computeShader;
434 computeShader = nullptr;
435 }
436 }
437
438 void ComputePipeline::bind(VkCommandBuffer commandBuffer)
439 {
440 vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline);
441 }
442}
#define TRACY_ZONE_SCOPED_NAMED(name)
std::vector< VkSpecializationMapEntry > getMapEntries() const override
Gets the specialization data which will be uploaded to a shader.
void bind(VkCommandBuffer commandBuffer)
Binds this pipeline to an arbitrary command buffer.
void cleanup()
Cleans up all the resource handles of this object.
ComputePipeline(VkDevice device, VkPipelineLayout layout, std::string shaderFilename, std::optional< const PipelineSpecializationData * > pSpecializationData)
std::vector< VkSpecializationMapEntry > getMapEntries() const override
Creates the list of specialization map entries which are applied to a shader.
bool operator==(const GraphicsPipeline &other) const
void bind(VkCommandBuffer commandBuffer) const
const PipelineMaterialPayload & getPipelineMaterialData() const
GraphicsPipeline(VkDevice device, VkSampleCountFlagBits multisampling, VkPipelineLayout pipelineLayout, VkRenderPass renderPass, const std::string &meshShaderFilename, const std::string &fragmentShaderFilename, const std::vector< VkVertexInputBindingDescription > &vertexInputBindingDescriptions, const std::vector< VkVertexInputAttributeDescription > &vertexInputAttributeDescriptions, PipelineMaterialPayload pipelineData, std::optional< const MeshShaderSpecializationData * > meshShaderSpecialization=std::nullopt, bool depthOnly=false)
const std::string getFragShaderName() const
const std::string getMeshShaderName() const
bool isValid() const
Checks if the object is fully constructed.
std::vector< VkSpecializationMapEntry > getMapEntries() const override
Creates the list of specialization map entries which are applied to a shader.
void destroyShaders(VkDevice device) override
Definition Shader.cpp:60
VkShaderModule getFragmentShader() const
Definition Shader.cpp:56
VkShaderModule getMeshShader() const
Definition Shader.cpp:51
static void setObjectName(VkDevice device, VulkanObjectType objectHandle, const std::string &name)
Log category system implementation.