VOX
A little voxel engine
Loading...
Searching...
No Matches
Pipeline.hpp
Go to the documentation of this file.
1#pragma once
2
3#include "vk_define.hpp"
4#include "logger.hpp"
5
6#include <string>
7#include <vector>
8#include <fstream>
9#include <optional>
10#include <algorithm>
11
13{
14
15public:
16
18 {
19 VkExtent2D extent;
20
21 std::string vert_path;
22 std::string geom_path;
23 std::string frag_path;
24
25 std::optional<VkVertexInputBindingDescription> binding_description = {};
26 std::vector<VkVertexInputAttributeDescription> attribute_descriptions = {};
27
28 VkPrimitiveTopology topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
29
30 VkPolygonMode polygon_mode = VK_POLYGON_MODE_FILL;
31 VkCullModeFlags cull_mode = VK_CULL_MODE_BACK_BIT;
32 VkFrontFace front_face = VK_FRONT_FACE_COUNTER_CLOCKWISE;
33
34 std::vector<VkFormat> color_formats = {};
35 VkFormat depth_format = VK_FORMAT_UNDEFINED;
36
37 VkBool32 depth_bias_enable = VK_FALSE;
39 float depth_bias_clamp = 0.0f;
41
42 std::vector<VkDescriptorSetLayout> descriptor_set_layouts = {};
43 std::vector<VkPushConstantRange> push_constant_ranges = {};
44
45 VkRenderPass render_pass = VK_NULL_HANDLE;
46 uint32_t subpass = 0;
47
48 std::vector<VkDynamicState> dynamic_states = {};
49
51 };
52
54 pipeline(VK_NULL_HANDLE),
55 layout(VK_NULL_HANDLE),
56 m_device(VK_NULL_HANDLE)
57 {
58 }
59
60 Pipeline(VkDevice device, const CreateInfo & create_info):
61 m_device(device)
62 {
63 std::vector<VkPipelineShaderStageCreateInfo> shader_stages;
64
65 if (!create_info.vert_path.empty())
66 {
67 auto vert_code = readFile(create_info.vert_path);
68 VkShaderModule vert_module = createShaderModule(vert_code);
69 VkPipelineShaderStageCreateInfo vert_stage_info = {};
70 vert_stage_info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
71 vert_stage_info.stage = VK_SHADER_STAGE_VERTEX_BIT;
72 vert_stage_info.module = vert_module;
73 vert_stage_info.pName = "main";
74
75 shader_stages.push_back(vert_stage_info);
76 }
77
78 if (!create_info.geom_path.empty())
79 {
80 auto geom_code = readFile(create_info.geom_path);
81 VkShaderModule geom_module = createShaderModule(geom_code);
82 VkPipelineShaderStageCreateInfo geom_stage_info = {};
83 geom_stage_info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
84 geom_stage_info.stage = VK_SHADER_STAGE_GEOMETRY_BIT;
85 geom_stage_info.module = geom_module;
86 geom_stage_info.pName = "main";
87
88 shader_stages.push_back(geom_stage_info);
89 }
90
91 if (!create_info.frag_path.empty())
92 {
93 auto frag_code = readFile(create_info.frag_path);
94 VkShaderModule frag_module = createShaderModule(frag_code);
95 VkPipelineShaderStageCreateInfo frag_stage_info = {};
96 frag_stage_info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
97 frag_stage_info.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
98 frag_stage_info.module = frag_module;
99 frag_stage_info.pName = "main";
100
101 shader_stages.push_back(frag_stage_info);
102 }
103
104
105 VkPipelineVertexInputStateCreateInfo vertex_input_info = {};
106 vertex_input_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
107 vertex_input_info.vertexBindingDescriptionCount = 0;
108 vertex_input_info.pVertexBindingDescriptions = nullptr;
109 vertex_input_info.vertexAttributeDescriptionCount = 0;
110 vertex_input_info.pVertexAttributeDescriptions = nullptr;
111
112 if (create_info.binding_description.has_value())
113 {
114 vertex_input_info.vertexBindingDescriptionCount = 1;
115 vertex_input_info.pVertexBindingDescriptions = &create_info.binding_description.value();
116 }
117 if (!create_info.attribute_descriptions.empty())
118 {
119 vertex_input_info.vertexAttributeDescriptionCount = static_cast<uint32_t>(create_info.attribute_descriptions.size());
120 vertex_input_info.pVertexAttributeDescriptions = create_info.attribute_descriptions.data();
121 }
122
123
124 VkPipelineInputAssemblyStateCreateInfo input_assembly = {};
125 input_assembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
126 input_assembly.topology = create_info.topology;
127 input_assembly.primitiveRestartEnable = VK_FALSE;
128
129
130 VkPipelineDynamicStateCreateInfo dynamic_state{};
131 dynamic_state.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
132 dynamic_state.dynamicStateCount = static_cast<uint32_t>(create_info.dynamic_states.size());
133 dynamic_state.pDynamicStates = create_info.dynamic_states.data();
134
135
136 VkViewport viewport = {};
137 viewport.x = 0.0f;
138 viewport.y = 0.0f;
139 viewport.width = static_cast<float>(create_info.extent.width);
140 viewport.height = static_cast<float>(create_info.extent.height);
141 viewport.minDepth = 0.0f;
142 viewport.maxDepth = 1.0f;
143
144 VkRect2D scissor = {};
145 scissor.offset = { 0, 0 };
146 scissor.extent = create_info.extent;
147
148 VkPipelineViewportStateCreateInfo viewport_state = {};
149 viewport_state.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
150 viewport_state.viewportCount = 1;
151 viewport_state.scissorCount = 1;
152 if (std::find(create_info.dynamic_states.begin(), create_info.dynamic_states.end(), VK_DYNAMIC_STATE_VIEWPORT) == create_info.dynamic_states.end())
153 {
154 viewport_state.pViewports = &viewport;
155 }
156 if (std::find(create_info.dynamic_states.begin(), create_info.dynamic_states.end(), VK_DYNAMIC_STATE_SCISSOR) == create_info.dynamic_states.end())
157 {
158 viewport_state.pScissors = &scissor;
159 }
160
161
162 VkPipelineRasterizationStateCreateInfo rasterizer = {};
163 rasterizer.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
164 rasterizer.depthClampEnable = VK_FALSE;
165 rasterizer.rasterizerDiscardEnable = VK_FALSE;
166 rasterizer.polygonMode = create_info.polygon_mode;
167 rasterizer.lineWidth = 1.0f;
168 rasterizer.cullMode = create_info.cull_mode;
169 rasterizer.frontFace = create_info.front_face;
170 rasterizer.depthBiasEnable = create_info.depth_bias_enable;
171 rasterizer.depthBiasConstantFactor = create_info.depth_bias_constant_factor;
172 rasterizer.depthBiasClamp = create_info.depth_bias_clamp;
173 rasterizer.depthBiasSlopeFactor = create_info.depth_bias_slope_factor;
174
175 VkPipelineMultisampleStateCreateInfo multisampling = {};
176 multisampling.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
177 multisampling.sampleShadingEnable = VK_FALSE;
178 multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
179
180
181 VkPipelineColorBlendAttachmentState color_blend_attachment = {};
182 color_blend_attachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
183 color_blend_attachment.blendEnable = VK_FALSE;
184
185 if (create_info.enable_alpha_blending)
186 {
187 color_blend_attachment.blendEnable = VK_TRUE;
188 color_blend_attachment.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
189 color_blend_attachment.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
190 color_blend_attachment.colorBlendOp = VK_BLEND_OP_ADD;
191 color_blend_attachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
192 color_blend_attachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO;
193 color_blend_attachment.alphaBlendOp = VK_BLEND_OP_ADD;
194 }
195
196 std::vector<VkPipelineColorBlendAttachmentState> color_blend_attachments(create_info.color_formats.size(), color_blend_attachment);
197
198 VkPipelineColorBlendStateCreateInfo color_blending = {};
199 color_blending.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
200 color_blending.logicOpEnable = VK_FALSE;
201 color_blending.attachmentCount = static_cast<uint32_t>(color_blend_attachments.size());
202 color_blending.pAttachments = color_blend_attachments.data();
203
204
205 VkPipelineDepthStencilStateCreateInfo depth_stencil = {};
206 depth_stencil.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
207 depth_stencil.depthTestEnable = VK_TRUE;
208 depth_stencil.depthWriteEnable = VK_TRUE;
209 depth_stencil.depthCompareOp = VK_COMPARE_OP_LESS_OR_EQUAL;
210 depth_stencil.depthBoundsTestEnable = VK_FALSE;
211 depth_stencil.stencilTestEnable = VK_FALSE;
212
213 if (create_info.depth_format != VK_FORMAT_UNDEFINED)
214 {
215 depth_stencil.depthTestEnable = VK_TRUE;
216 depth_stencil.depthWriteEnable = VK_TRUE;
217 }
218
219
220 VkPipelineRenderingCreateInfo rendering_info = {};
221 rendering_info.sType = VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO;
222 rendering_info.colorAttachmentCount = static_cast<uint32_t>(create_info.color_formats.size());
223 rendering_info.pColorAttachmentFormats = create_info.color_formats.data();
224 rendering_info.depthAttachmentFormat = create_info.depth_format;
225
226
227 VkPipelineLayoutCreateInfo pipeline_layout_info = {};
228 pipeline_layout_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
229 pipeline_layout_info.setLayoutCount = static_cast<uint32_t>(create_info.descriptor_set_layouts.size());
230 pipeline_layout_info.pSetLayouts = create_info.descriptor_set_layouts.data();
231 pipeline_layout_info.pushConstantRangeCount = static_cast<uint32_t>(create_info.push_constant_ranges.size());
232 pipeline_layout_info.pPushConstantRanges = create_info.push_constant_ranges.data();
233
234 VK_CHECK(
235 vkCreatePipelineLayout(m_device, &pipeline_layout_info, nullptr, &layout),
236 "Failed to create pipeline layout"
237 );
238
239 VkGraphicsPipelineCreateInfo pipeline_info = {};
240 pipeline_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
241 pipeline_info.stageCount = static_cast<uint32_t>(shader_stages.size());
242 pipeline_info.pStages = shader_stages.data();
243 pipeline_info.pVertexInputState = &vertex_input_info;
244 pipeline_info.pInputAssemblyState = &input_assembly;
245 pipeline_info.pViewportState = &viewport_state;
246 pipeline_info.pRasterizationState = &rasterizer;
247 pipeline_info.pMultisampleState = &multisampling;
248 pipeline_info.pColorBlendState = &color_blending;
249 pipeline_info.pDepthStencilState = &depth_stencil;
250 pipeline_info.pDynamicState = &dynamic_state;
251 pipeline_info.layout = layout;
252
253 if (create_info.render_pass == VK_NULL_HANDLE)
254 {
255 pipeline_info.pNext = &rendering_info;
256 }
257 else
258 {
259 pipeline_info.renderPass = create_info.render_pass;
260 pipeline_info.subpass = create_info.subpass;
261 }
262
263 VK_CHECK(
264 vkCreateGraphicsPipelines(m_device, VK_NULL_HANDLE, 1, &pipeline_info, nullptr, &pipeline),
265 "Failed to create graphics pipeline"
266 );
267
268 for (auto & shader_stage : shader_stages)
269 {
270 vkDestroyShaderModule(m_device, shader_stage.module, nullptr);
271 }
272 }
273
274
275 Pipeline(const Pipeline &) = delete;
276 Pipeline & operator=(const Pipeline &) = delete;
277
278 Pipeline(Pipeline && other) noexcept:
279 pipeline(other.pipeline),
280 layout(other.layout),
281 m_device(other.m_device)
282 {
283 other.pipeline = VK_NULL_HANDLE;
284 other.layout = VK_NULL_HANDLE;
285 other.m_device = VK_NULL_HANDLE;
286 }
287
288 Pipeline & operator=(Pipeline && other) noexcept
289 {
290 if (this != &other)
291 {
292 clear();
293
294 pipeline = other.pipeline;
295 layout = other.layout;
296 m_device = other.m_device;
297
298 other.pipeline = VK_NULL_HANDLE;
299 other.layout = VK_NULL_HANDLE;
300 other.m_device = VK_NULL_HANDLE;
301 }
302
303 return *this;
304 }
305
307 {
308 clear();
309 }
310
311 void clear()
312 {
313 if (m_device != VK_NULL_HANDLE)
314 {
315 if (pipeline != VK_NULL_HANDLE)
316 {
317 vkDestroyPipeline(m_device, pipeline, nullptr);
318 pipeline = VK_NULL_HANDLE;
319 }
320
321 if (layout != VK_NULL_HANDLE)
322 {
323 vkDestroyPipelineLayout(m_device, layout, nullptr);
324 layout = VK_NULL_HANDLE;
325 }
326 m_device = VK_NULL_HANDLE;
327 }
328 }
329
330 VkPipeline pipeline;
331 VkPipelineLayout layout;
332
333private:
334
335 VkDevice m_device;
336
337 std::vector<char> readFile(const std::string & filename)
338 {
339 std::ifstream file
340 {
341 filename,
342 std::ios::ate | std::ios::binary
343 };
344
345 if (!file.is_open())
346 {
347 throw std::runtime_error("Failed to open file: " + filename);
348 }
349
350 size_t file_size = static_cast<size_t>(file.tellg());
351 std::vector<char> buffer(file_size);
352
353 file.seekg(0);
354 file.read(buffer.data(), file_size);
355 file.close();
356
357 return buffer;
358 }
359
360 VkShaderModule createShaderModule(const std::vector<char> & code)
361 {
362 VkShaderModuleCreateInfo create_info = {};
363 create_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
364 create_info.codeSize = code.size();
365 create_info.pCode = reinterpret_cast<const uint32_t *>(code.data());
366
367 VkShaderModule shader_module;
368 VK_CHECK(
369 vkCreateShaderModule(m_device, &create_info, nullptr, &shader_module),
370 "Failed to create shader module"
371 );
372
373 return shader_module;
374 }
375
376};
Definition: Pipeline.hpp:13
Pipeline & operator=(Pipeline &&other) noexcept
Definition: Pipeline.hpp:288
VkPipeline pipeline
Definition: Pipeline.hpp:330
Pipeline(VkDevice device, const CreateInfo &create_info)
Definition: Pipeline.hpp:60
~Pipeline()
Definition: Pipeline.hpp:306
Pipeline & operator=(const Pipeline &)=delete
VkPipelineLayout layout
Definition: Pipeline.hpp:331
void clear()
Definition: Pipeline.hpp:311
Pipeline()
Definition: Pipeline.hpp:53
Pipeline(const Pipeline &)=delete
Pipeline(Pipeline &&other) noexcept
Definition: Pipeline.hpp:278
Definition: Pipeline.hpp:18
std::vector< VkVertexInputAttributeDescription > attribute_descriptions
Definition: Pipeline.hpp:26
VkPolygonMode polygon_mode
Definition: Pipeline.hpp:30
bool enable_alpha_blending
Definition: Pipeline.hpp:50
uint32_t subpass
Definition: Pipeline.hpp:46
VkCullModeFlags cull_mode
Definition: Pipeline.hpp:31
VkFormat depth_format
Definition: Pipeline.hpp:35
std::string geom_path
Definition: Pipeline.hpp:22
std::vector< VkDescriptorSetLayout > descriptor_set_layouts
Definition: Pipeline.hpp:42
VkFrontFace front_face
Definition: Pipeline.hpp:32
std::vector< VkDynamicState > dynamic_states
Definition: Pipeline.hpp:48
std::optional< VkVertexInputBindingDescription > binding_description
Definition: Pipeline.hpp:25
std::string frag_path
Definition: Pipeline.hpp:23
std::vector< VkFormat > color_formats
Definition: Pipeline.hpp:34
std::string vert_path
Definition: Pipeline.hpp:21
VkBool32 depth_bias_enable
Definition: Pipeline.hpp:37
float depth_bias_clamp
Definition: Pipeline.hpp:39
VkRenderPass render_pass
Definition: Pipeline.hpp:45
std::vector< VkPushConstantRange > push_constant_ranges
Definition: Pipeline.hpp:43
VkExtent2D extent
Definition: Pipeline.hpp:19
float depth_bias_slope_factor
Definition: Pipeline.hpp:40
float depth_bias_constant_factor
Definition: Pipeline.hpp:38
VkPrimitiveTopology topology
Definition: Pipeline.hpp:28
#define VK_CHECK(function, message)
Definition: vk_define.hpp:11