Skip to content

Commit e5bdb50

Browse files
committed
Split up pipeline creation, update docs
1 parent f6ddd0b commit e5bdb50

File tree

5 files changed

+207
-121
lines changed

5 files changed

+207
-121
lines changed

guide/src/SUMMARY.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,4 +27,4 @@
2727
- [Graphics Pipeline](pipeline/README.md)
2828
- [Locating Assets](pipeline/locating_assets.md)
2929
- [Shaders](pipeline/shaders.md)
30-
- [Pipeline Creation](pipeline/creation.md)
30+
- [Pipeline Creation](pipeline/pipeline_creation.md)

guide/src/pipeline/creation.md renamed to guide/src/pipeline/pipeline_creation.md

Lines changed: 108 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -59,92 +59,140 @@ class PipelineBuilder {
5959
};
6060
```
6161

62-
Implement `build()`:
62+
Before implementing `build()`, add some helper functions/constants, starting with the viewport and dynamic states:
6363

6464
```cpp
65-
auto PipelineBuilder::build(vk::PipelineLayout const layout,
66-
PipelineState const& state) const
67-
-> vk::UniquePipeline {
65+
// single viewport and scissor.
66+
constexpr auto viewport_state_v =
67+
vk::PipelineViewportStateCreateInfo({}, 1, {}, 1);
68+
69+
// these dynamic states are guaranteed to be available.
70+
constexpr auto dynamic_states_v = std::array{
71+
vk::DynamicState::eViewport,
72+
vk::DynamicState::eScissor,
73+
vk::DynamicState::eLineWidth,
74+
};
75+
```
76+
77+
The shader stages:
78+
79+
```cpp
80+
[[nodiscard]] constexpr auto
81+
create_shader_stages(vk::ShaderModule const vertex,
82+
vk::ShaderModule const fragment) {
6883
// set vertex (0) and fragment (1) shader stages.
69-
auto shader_stages = std::array<vk::PipelineShaderStageCreateInfo, 2>{};
70-
shader_stages[0]
84+
auto ret = std::array<vk::PipelineShaderStageCreateInfo, 2>{};
85+
ret[0]
7186
.setStage(vk::ShaderStageFlagBits::eVertex)
7287
.setPName("main")
73-
.setModule(state.vertex_shader);
74-
shader_stages[1]
88+
.setModule(vertex);
89+
ret[1]
7590
.setStage(vk::ShaderStageFlagBits::eFragment)
7691
.setPName("main")
77-
.setModule(state.fragment_shader);
78-
79-
auto pvisci = vk::PipelineVertexInputStateCreateInfo{};
80-
pvisci.setVertexAttributeDescriptions(state.vertex_attributes)
81-
.setVertexBindingDescriptions(state.vertex_bindings);
92+
.setModule(fragment);
93+
return ret;
94+
}
95+
```
8296

83-
auto prsci = vk::PipelineRasterizationStateCreateInfo{};
84-
prsci.setPolygonMode(state.polygon_mode).setCullMode(state.cull_mode);
97+
The depth/stencil state:
8598

86-
auto pdssci = vk::PipelineDepthStencilStateCreateInfo{};
99+
```cpp
100+
[[nodiscard]] constexpr auto
101+
create_depth_stencil_state(std::uint8_t flags,
102+
vk::CompareOp const depth_compare) {
103+
auto ret = vk::PipelineDepthStencilStateCreateInfo{};
87104
auto const depth_test =
88-
(state.flags & PipelineFlag::DepthTest) == PipelineFlag::DepthTest;
89-
pdssci.setDepthTestEnable(depth_test ? vk::True : vk::False)
90-
.setDepthCompareOp(state.depth_compare);
105+
(flags & PipelineFlag::DepthTest) == PipelineFlag::DepthTest;
106+
ret.setDepthTestEnable(depth_test ? vk::True : vk::False)
107+
.setDepthCompareOp(depth_compare);
108+
return ret;
109+
}
110+
```
91111
92-
auto const piasci =
93-
vk::PipelineInputAssemblyStateCreateInfo{{}, state.topology};
112+
And a color blend attachment:
94113
95-
auto pcbas = vk::PipelineColorBlendAttachmentState{};
114+
```cpp
115+
[[nodiscard]] constexpr auto
116+
create_color_blend_attachment(std::uint8_t const flags) {
117+
auto ret = vk::PipelineColorBlendAttachmentState{};
96118
auto const alpha_blend =
97-
(state.flags & PipelineFlag::AlphaBlend) == PipelineFlag::AlphaBlend;
119+
(flags & PipelineFlag::AlphaBlend) == PipelineFlag::AlphaBlend;
98120
using CCF = vk::ColorComponentFlagBits;
99-
pcbas.setColorWriteMask(CCF::eR | CCF::eG | CCF::eB | CCF::eA)
121+
ret.setColorWriteMask(CCF::eR | CCF::eG | CCF::eB | CCF::eA)
100122
.setBlendEnable(alpha_blend ? vk::True : vk::False)
123+
// standard alpha blending:
124+
// (alpha * src) + (1 - alpha) * dst
101125
.setSrcColorBlendFactor(vk::BlendFactor::eSrcAlpha)
102126
.setDstColorBlendFactor(vk::BlendFactor::eOneMinusSrcAlpha)
103127
.setColorBlendOp(vk::BlendOp::eAdd)
104128
.setSrcAlphaBlendFactor(vk::BlendFactor::eOne)
105129
.setDstAlphaBlendFactor(vk::BlendFactor::eZero)
106130
.setAlphaBlendOp(vk::BlendOp::eAdd);
107-
auto pcbsci = vk::PipelineColorBlendStateCreateInfo{};
108-
pcbsci.setAttachments(pcbas);
109-
110-
// these dynamic states are guaranteed to be available.
111-
auto const pdscis = std::array{
112-
vk::DynamicState::eViewport,
113-
vk::DynamicState::eScissor,
114-
vk::DynamicState::eLineWidth,
115-
};
116-
auto pdsci = vk::PipelineDynamicStateCreateInfo{};
117-
pdsci.setDynamicStates(pdscis);
131+
return ret;
132+
}
133+
```
134+
135+
Now we can implement `build()`:
136+
137+
```cpp
138+
auto PipelineBuilder::build(vk::PipelineLayout const layout,
139+
PipelineState const& state) const
140+
-> vk::UniquePipeline {
141+
auto const shader_stage_ci =
142+
create_shader_stages(state.vertex_shader, state.fragment_shader);
118143

119-
// single viewport and scissor.
120-
auto const pvsci = vk::PipelineViewportStateCreateInfo({}, 1, {}, 1);
144+
auto vertex_input_ci = vk::PipelineVertexInputStateCreateInfo{};
145+
vertex_input_ci.setVertexAttributeDescriptions(state.vertex_attributes)
146+
.setVertexBindingDescriptions(state.vertex_bindings);
121147

122-
auto pmsci = vk::PipelineMultisampleStateCreateInfo{};
123-
pmsci.setRasterizationSamples(m_info.samples)
148+
auto multisample_state_ci = vk::PipelineMultisampleStateCreateInfo{};
149+
multisample_state_ci.setRasterizationSamples(m_info.samples)
124150
.setSampleShadingEnable(vk::False);
125151

126-
auto prci = vk::PipelineRenderingCreateInfo{};
127-
// could be a depth-only pass.
152+
auto const input_assembly_ci =
153+
vk::PipelineInputAssemblyStateCreateInfo{{}, state.topology};
154+
155+
auto rasterization_state_ci = vk::PipelineRasterizationStateCreateInfo{};
156+
rasterization_state_ci.setPolygonMode(state.polygon_mode)
157+
.setCullMode(state.cull_mode);
158+
159+
auto const depth_stencil_state_ci =
160+
create_depth_stencil_state(state.flags, state.depth_compare);
161+
162+
auto const color_blend_attachment =
163+
create_color_blend_attachment(state.flags);
164+
auto color_blend_state_ci = vk::PipelineColorBlendStateCreateInfo{};
165+
color_blend_state_ci.setAttachments(color_blend_attachment);
166+
167+
auto dynamic_state_ci = vk::PipelineDynamicStateCreateInfo{};
168+
dynamic_state_ci.setDynamicStates(dynamic_states_v);
169+
170+
// Dynamic Rendering requires passing this in the pNext chain.
171+
auto rendering_ci = vk::PipelineRenderingCreateInfo{};
172+
// could be a depth-only pass, argument is span-like (notice the plural
173+
// `Formats()`), only set if not Undefined.
128174
if (m_info.color_format != vk::Format::eUndefined) {
129-
prci.setColorAttachmentFormats(m_info.color_format);
175+
rendering_ci.setColorAttachmentFormats(m_info.color_format);
130176
}
131-
prci.setDepthAttachmentFormat(m_info.depth_format);
132-
133-
auto gpci = vk::GraphicsPipelineCreateInfo{};
134-
gpci.setStages(shader_stages)
135-
.setPRasterizationState(&prsci)
136-
.setPDepthStencilState(&pdssci)
137-
.setPInputAssemblyState(&piasci)
138-
.setPColorBlendState(&pcbsci)
139-
.setPDynamicState(&pdsci)
140-
.setPViewportState(&pvsci)
141-
.setPMultisampleState(&pmsci)
142-
.setLayout(layout)
143-
.setPNext(&prci);
177+
// single depth attachment format, ok to set to Undefined.
178+
rendering_ci.setDepthAttachmentFormat(m_info.depth_format);
179+
180+
auto pipeline_ci = vk::GraphicsPipelineCreateInfo{};
181+
pipeline_ci.setLayout(layout)
182+
.setStages(shader_stage_ci)
183+
.setPVertexInputState(&vertex_input_ci)
184+
.setPViewportState(&viewport_state_v)
185+
.setPMultisampleState(&multisample_state_ci)
186+
.setPInputAssemblyState(&input_assembly_ci)
187+
.setPRasterizationState(&rasterization_state_ci)
188+
.setPDepthStencilState(&depth_stencil_state_ci)
189+
.setPColorBlendState(&color_blend_state_ci)
190+
.setPDynamicState(&dynamic_state_ci)
191+
.setPNext(&rendering_ci);
144192

145193
auto ret = vk::Pipeline{};
146194
// use non-throwing API.
147-
if (m_info.device.createGraphicsPipelines({}, 1, &gpci, {}, &ret) !=
195+
if (m_info.device.createGraphicsPipelines({}, 1, &pipeline_ci, {}, &ret) !=
148196
vk::Result::eSuccess) {
149197
return {};
150198
}
@@ -195,15 +243,15 @@ if (!m_pipeline) {
195243
}
196244
```
197245
198-
We can now bind it and use it to draw the triangle in the shader. Since we used dynamic viewport and scissor during pipeline creation, we need to set those after binding the pipeline.
246+
We can now bind it and use it to draw the triangle in the shader. Since we created the pipeline with dynamic viewport and scissor states, we need to set those after binding the pipeline.
199247
200248
```cpp
201249
command_buffer.beginRendering(rendering_info);
202250
ImGui::ShowDemoWindow();
203251
204252
command_buffer.bindPipeline(vk::PipelineBindPoint::eGraphics, *m_pipeline);
205253
auto viewport = vk::Viewport{};
206-
// flip the viewport across the X-axis (negative height):
254+
// flip the viewport about the X-axis (negative height):
207255
// https://www.saschawillems.de/blog/2019/03/29/flipping-the-vulkan-viewport/
208256
viewport.setX(0.0f)
209257
.setY(static_cast<float>(m_render_target->extent.height))
@@ -242,6 +290,8 @@ layout (location = 0) in vec3 in_color;
242290
out_color = vec4(in_color, 1.0);
243291
```
244292

293+
> Make sure to recompile both the SPIR-V shaders in assets/.
294+
245295
And a black clear color:
246296

247297
```cpp

guide/src/pipeline/shaders.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ glslc src/glsl/shader.vert -o assets/shader.vert
3737
glslc src/glsl/shader.frag -o assets/shader.frag
3838
```
3939

40+
> glslc is part of the Vulkan SDK.
41+
4042
## Shader Modules
4143

4244
SPIR-V modules are binary files with a stride/alignment of 4 bytes. The Vulkan API accepts a span of `std::uint32_t`s, so we need to load it into such a buffer (and _not_ `std::vector<std::byte>` or other 1-byte equivalents).

src/app.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -304,7 +304,7 @@ void App::render(vk::CommandBuffer const command_buffer) {
304304

305305
command_buffer.bindPipeline(vk::PipelineBindPoint::eGraphics, *m_pipeline);
306306
auto viewport = vk::Viewport{};
307-
// flip the viewport across the X-axis (negative height):
307+
// flip the viewport about the X-axis (negative height):
308308
// https://www.saschawillems.de/blog/2019/03/29/flipping-the-vulkan-viewport/
309309
viewport.setX(0.0f)
310310
.setY(static_cast<float>(m_render_target->extent.height))

0 commit comments

Comments
 (0)