-
Notifications
You must be signed in to change notification settings - Fork 0
/
pipeline.cpp
264 lines (241 loc) · 10.9 KB
/
pipeline.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
//
// Created by daily on 27-12-23.
//
#include "pipeline.hpp"
namespace vkinit
{
/**
* @brief Creates a Vulkan pipeline_ layout
*
* Initializes a pipeline_ layout necessary for a Vulkan graphics pipeline_, including push constants
*
* @param device The Vulkan logical device_.
* @param debug Flag indicating whether to enable debug logging.
* @return The created Vulkan pipeline_ layout.
*/
vk::PipelineLayout make_pipeline_layout(vk::Device device, bool debug)
{
vk::PipelineLayoutCreateInfo layoutInfo;
layoutInfo.flags = vk::PipelineLayoutCreateFlags();
layoutInfo.setLayoutCount = 0;
layoutInfo.pushConstantRangeCount = 1;
vk::PushConstantRange pushConstantInfo;
pushConstantInfo.offset = 0;
pushConstantInfo.size = sizeof(vkutil::ObjectData);
pushConstantInfo.stageFlags = vk::ShaderStageFlagBits::eVertex;
layoutInfo.pPushConstantRanges = &pushConstantInfo;
try
{
return device.createPipelineLayout(layoutInfo);
}
catch(vk::SystemError &err)
{
if(debug)
{
std::cout << "Failed to create pipeline_ pipeline_layout_!" << std::endl;
}
return vk::PipelineLayout{};
}
}
/**
* @brief Creates a Vulkan render pass.
*
* Initializes a render pass for the graphics pipeline_, specifying how color and depth attachments are handled.
*
* @param device The Vulkan logical device_.
* @param swapchainImageFormat The format of the swap chain images.
* @param debug Flag indicating whether to enable debug logging.
* @return The created Vulkan render pass.
*/
vk::RenderPass make_renderpass(vk::Device device, vk::Format swapchainImageFormat, bool debug)
{
vk::AttachmentDescription colorAttachment = { };
colorAttachment.flags = vk::AttachmentDescriptionFlags();
colorAttachment.format = swapchainImageFormat;
colorAttachment.samples = vk::SampleCountFlagBits::e1;
colorAttachment.loadOp = vk::AttachmentLoadOp::eClear;
colorAttachment.storeOp = vk::AttachmentStoreOp::eStore;
colorAttachment.stencilLoadOp = vk::AttachmentLoadOp::eDontCare;
colorAttachment.stencilStoreOp = vk::AttachmentStoreOp::eDontCare;
colorAttachment.initialLayout = vk::ImageLayout::eUndefined;
colorAttachment.finalLayout = vk::ImageLayout::ePresentSrcKHR;
vk::AttachmentReference colorAttachmentRef = { };
colorAttachmentRef.attachment = 0;
colorAttachmentRef.layout = vk::ImageLayout::eColorAttachmentOptimal;
vk::SubpassDescription subpass = { };
subpass.flags = vk::SubpassDescriptionFlags();
subpass.pipelineBindPoint = vk::PipelineBindPoint::eGraphics;
subpass.colorAttachmentCount = 1;
subpass.pColorAttachments = &colorAttachmentRef;
vk::RenderPassCreateInfo renderpassInfo = { };
renderpassInfo.flags = vk::RenderPassCreateFlags();
renderpassInfo.attachmentCount = 1;
renderpassInfo.pAttachments = &colorAttachment;
renderpassInfo.subpassCount = 1;
renderpassInfo.pSubpasses = &subpass;
try
{
return device.createRenderPass(renderpassInfo);
}
catch(vk::SystemError &err)
{
if(debug)
{
std::cout << "Failed to create render_pass_!" << std::endl;
}
return vk::RenderPass{};
}
}
/**
* @brief Creates a Vulkan graphics pipeline_
*
* Sets up the entire graphics pipeline_, including shader stages, viewport and scissor states,
* rasterization, multisampling, color blending, and more, based on the provided specifications.
*
* @param specification The specifications for creating the graphics pipeline_.
* @param debug Flag indicating whether to enable debug logging.
* @return A bundle containing the components of the created graphics pipeline_.
*/
GraphicsPipelineOutBundle create_graphics_pipeline(GraphicsPipelineInBundle specification, bool debug)
{
vk::GraphicsPipelineCreateInfo pipelineInfo = { };
pipelineInfo.flags = vk::PipelineCreateFlags();
std::vector<vk::PipelineShaderStageCreateInfo> shaderStages;
// vertex input
vk::VertexInputBindingDescription bindingDescription = vkmesh::getPosColorBindingDescription();
std::array<vk::VertexInputAttributeDescription, 2> attributeDescriptions = vkmesh::getPosColorAttributeDescriptions();
vk::PipelineVertexInputStateCreateInfo vertexInputInfo = { };
vertexInputInfo.flags = vk::PipelineVertexInputStateCreateFlags();
vertexInputInfo.vertexBindingDescriptionCount = 1;
vertexInputInfo.pVertexBindingDescriptions = &bindingDescription;
vertexInputInfo.vertexAttributeDescriptionCount = 2;
vertexInputInfo.pVertexAttributeDescriptions = attributeDescriptions.data();
pipelineInfo.pVertexInputState = &vertexInputInfo;
//Input Assembly
vk::PipelineInputAssemblyStateCreateInfo inputAssemblyInfo = { };
inputAssemblyInfo.flags = vk::PipelineInputAssemblyStateCreateFlags();
// inputAssemblyInfo.topology = vk::PrimitiveTopology::eTriangleList;
inputAssemblyInfo.topology = vk::PrimitiveTopology::eTriangleStrip;
pipelineInfo.pInputAssemblyState = &inputAssemblyInfo;
//vertex shader
if(debug)
{
std::cout << "Create vertex shader module" << std::endl;
}
vk::ShaderModule vertexShader = vkutil::createModule(specification.vertexFilepath, specification.device, debug);
vk::PipelineShaderStageCreateInfo vertexShaderInfo = {};
vertexShaderInfo.flags = vk::PipelineShaderStageCreateFlags();
vertexShaderInfo.stage = vk::ShaderStageFlagBits::eVertex;
vertexShaderInfo.module = vertexShader;
vertexShaderInfo.pName = "main";
shaderStages.push_back(vertexShaderInfo);
//viewport and scissor
vk::Viewport viewport = {};
viewport.x = 0.0f;
viewport.y = 0.0f;
viewport.width = static_cast<float>(specification.swapchainExtent.width);
viewport.height = static_cast<float>(specification.swapchainExtent.height);
viewport.minDepth = 0.0f;
viewport.maxDepth = 1.0f;
vk::Rect2D scissor = { };
scissor.offset.x = 0.0f;
scissor.offset.y = 0.0f;
scissor.extent = specification.swapchainExtent;
vk::PipelineViewportStateCreateInfo viewportState = { };
viewportState.flags = vk::PipelineViewportStateCreateFlags();
viewportState.viewportCount = 1;
viewportState.pViewports = &viewport;
viewportState.scissorCount = 1;
viewportState.pScissors = &scissor;
pipelineInfo.pViewportState = &viewportState;
//rasterizer
vk::PipelineRasterizationStateCreateInfo rasterizer = {};
rasterizer.flags = vk::PipelineRasterizationStateCreateFlags();
rasterizer.depthClampEnable = VK_FALSE;
rasterizer.rasterizerDiscardEnable = VK_FALSE;
rasterizer.polygonMode = vk::PolygonMode::eFill;
rasterizer.lineWidth = 1.0f;
rasterizer.cullMode = vk::CullModeFlagBits::eBack;
rasterizer.frontFace = vk::FrontFace::eClockwise;
rasterizer.depthBiasEnable = VK_FALSE;
pipelineInfo.pRasterizationState = &rasterizer;
//vertex shader
if(debug)
{
std::cout << "Create fragment shader module" << std::endl;
}
vk::ShaderModule fragmentShader = vkutil::createModule(specification.fragmentFilepath, specification.device, debug);
vk::PipelineShaderStageCreateInfo fragmentShaderInfo = {};
fragmentShaderInfo.flags = vk::PipelineShaderStageCreateFlags();
fragmentShaderInfo.stage = vk::ShaderStageFlagBits::eFragment;
fragmentShaderInfo.module = fragmentShader;
fragmentShaderInfo.pName = "main";
shaderStages.push_back(fragmentShaderInfo);
pipelineInfo.stageCount = static_cast<uint32_t>(shaderStages.size());
pipelineInfo.pStages = shaderStages.data();
//multisampling
vk::PipelineMultisampleStateCreateInfo multisampling = { };
multisampling.flags = vk::PipelineMultisampleStateCreateFlags();
multisampling.sampleShadingEnable = VK_FALSE;
multisampling.rasterizationSamples = vk::SampleCountFlagBits::e1;
pipelineInfo.pMultisampleState = &multisampling;
//color blend
vk::PipelineColorBlendAttachmentState colorBlendAttachment = { };
colorBlendAttachment.colorWriteMask = vk::ColorComponentFlagBits::eR |
vk::ColorComponentFlagBits::eG |
vk::ColorComponentFlagBits::eB |
vk::ColorComponentFlagBits::eA;
colorBlendAttachment.blendEnable = VK_FALSE;
vk::PipelineColorBlendStateCreateInfo colorBlending = { };
colorBlending.flags = vk::PipelineColorBlendStateCreateFlags();
colorBlending.logicOpEnable = VK_FALSE;
colorBlending.logicOp = vk::LogicOp::eCopy;
colorBlending.attachmentCount = 1;
colorBlending.pAttachments = &colorBlendAttachment;
colorBlending.blendConstants[0] = 0.0f;
colorBlending.blendConstants[1] = 0.0f;
colorBlending.blendConstants[2] = 0.0f;
colorBlending.blendConstants[3] = 0.0f;
pipelineInfo.pColorBlendState = &colorBlending;
//pipeline_ pipeline_layout_
if(debug)
{
std::cout << "Create Pipeline Layout" << std::endl;
}
vk::PipelineLayout layout = make_pipeline_layout(specification.device, debug);
pipelineInfo.layout = layout;
//Renderpass
if(debug)
{
std::cout << "Create RenderPass" << std::endl;
}
vk::RenderPass renderpass = make_renderpass(specification.device, specification.swapchainImageFormat, debug);
pipelineInfo.renderPass = renderpass;
//extra stuff
pipelineInfo.basePipelineHandle = nullptr;
//make the pipeline_
if(debug)
{
std::cout << "Create Graphics Pipeline" << std::endl;
}
vk::Pipeline graphicsPipeline;
try
{
graphicsPipeline = (specification.device.createGraphicsPipeline(nullptr, pipelineInfo)).value;
}
catch(vk::SystemError &err)
{
if(debug)
{
std::cout << "Failed to create Graphics Pipeline!"<<std::endl;
}
}
GraphicsPipelineOutBundle output = {};
output.layout = layout;
output.renderpass = renderpass;
output.pipeline = graphicsPipeline;
specification.device.destroyShaderModule(vertexShader);
specification.device.destroyShaderModule(fragmentShader);
return output;
}
}