Skip to content

Commit d3ac685

Browse files
committed
Split up pipeline creation
1 parent f6ddd0b commit d3ac685

File tree

3 files changed

+200
-118
lines changed

3 files changed

+200
-118
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: 104 additions & 56 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()`:
118136

119-
// single viewport and scissor.
120-
auto const pvsci = vk::PipelineViewportStateCreateInfo({}, 1, {}, 1);
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);
121143

122-
auto pmsci = vk::PipelineMultisampleStateCreateInfo{};
123-
pmsci.setRasterizationSamples(m_info.samples)
144+
auto vertex_input_ci = vk::PipelineVertexInputStateCreateInfo{};
145+
vertex_input_ci.setVertexAttributeDescriptions(state.vertex_attributes)
146+
.setVertexBindingDescriptions(state.vertex_bindings);
147+
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 a 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
}

src/pipeline_builder.cpp

Lines changed: 95 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1,92 +1,126 @@
11
#include <pipeline_builder.hpp>
22

33
namespace lvk {
4-
PipelineBuilder::PipelineBuilder(CreateInfo const& create_info)
5-
: m_info(create_info) {}
4+
namespace {
5+
// single viewport and scissor.
6+
constexpr auto viewport_state_v =
7+
vk::PipelineViewportStateCreateInfo({}, 1, {}, 1);
68

7-
auto PipelineBuilder::build(vk::PipelineLayout const layout,
8-
PipelineState const& state) const
9-
-> vk::UniquePipeline {
9+
// these dynamic states are guaranteed to be available.
10+
constexpr auto dynamic_states_v = std::array{
11+
vk::DynamicState::eViewport,
12+
vk::DynamicState::eScissor,
13+
vk::DynamicState::eLineWidth,
14+
};
15+
16+
[[nodiscard]] constexpr auto
17+
create_shader_stages(vk::ShaderModule const vertex,
18+
vk::ShaderModule const fragment) {
1019
// set vertex (0) and fragment (1) shader stages.
11-
auto shader_stages = std::array<vk::PipelineShaderStageCreateInfo, 2>{};
12-
shader_stages[0]
20+
auto ret = std::array<vk::PipelineShaderStageCreateInfo, 2>{};
21+
ret[0]
1322
.setStage(vk::ShaderStageFlagBits::eVertex)
1423
.setPName("main")
15-
.setModule(state.vertex_shader);
16-
shader_stages[1]
24+
.setModule(vertex);
25+
ret[1]
1726
.setStage(vk::ShaderStageFlagBits::eFragment)
1827
.setPName("main")
19-
.setModule(state.fragment_shader);
20-
21-
auto pvisci = vk::PipelineVertexInputStateCreateInfo{};
22-
pvisci.setVertexAttributeDescriptions(state.vertex_attributes)
23-
.setVertexBindingDescriptions(state.vertex_bindings);
24-
25-
auto prsci = vk::PipelineRasterizationStateCreateInfo{};
26-
prsci.setPolygonMode(state.polygon_mode).setCullMode(state.cull_mode);
28+
.setModule(fragment);
29+
return ret;
30+
}
2731

28-
auto pdssci = vk::PipelineDepthStencilStateCreateInfo{};
32+
[[nodiscard]] constexpr auto
33+
create_depth_stencil_state(std::uint8_t flags,
34+
vk::CompareOp const depth_compare) {
35+
auto ret = vk::PipelineDepthStencilStateCreateInfo{};
2936
auto const depth_test =
30-
(state.flags & PipelineFlag::DepthTest) == PipelineFlag::DepthTest;
31-
pdssci.setDepthTestEnable(depth_test ? vk::True : vk::False)
32-
.setDepthCompareOp(state.depth_compare);
33-
34-
auto const piasci =
35-
vk::PipelineInputAssemblyStateCreateInfo{{}, state.topology};
37+
(flags & PipelineFlag::DepthTest) == PipelineFlag::DepthTest;
38+
ret.setDepthTestEnable(depth_test ? vk::True : vk::False)
39+
.setDepthCompareOp(depth_compare);
40+
return ret;
41+
}
3642

37-
auto pcbas = vk::PipelineColorBlendAttachmentState{};
43+
[[nodiscard]] constexpr auto
44+
create_color_blend_attachment(std::uint8_t const flags) {
45+
auto ret = vk::PipelineColorBlendAttachmentState{};
3846
auto const alpha_blend =
39-
(state.flags & PipelineFlag::AlphaBlend) == PipelineFlag::AlphaBlend;
47+
(flags & PipelineFlag::AlphaBlend) == PipelineFlag::AlphaBlend;
4048
using CCF = vk::ColorComponentFlagBits;
41-
pcbas.setColorWriteMask(CCF::eR | CCF::eG | CCF::eB | CCF::eA)
49+
ret.setColorWriteMask(CCF::eR | CCF::eG | CCF::eB | CCF::eA)
4250
.setBlendEnable(alpha_blend ? vk::True : vk::False)
51+
// standard alpha blending:
52+
// (alpha * src) + (1 - alpha) * dst
4353
.setSrcColorBlendFactor(vk::BlendFactor::eSrcAlpha)
4454
.setDstColorBlendFactor(vk::BlendFactor::eOneMinusSrcAlpha)
4555
.setColorBlendOp(vk::BlendOp::eAdd)
4656
.setSrcAlphaBlendFactor(vk::BlendFactor::eOne)
4757
.setDstAlphaBlendFactor(vk::BlendFactor::eZero)
4858
.setAlphaBlendOp(vk::BlendOp::eAdd);
49-
auto pcbsci = vk::PipelineColorBlendStateCreateInfo{};
50-
pcbsci.setAttachments(pcbas);
51-
52-
// these dynamic states are guaranteed to be available.
53-
auto const pdscis = std::array{
54-
vk::DynamicState::eViewport,
55-
vk::DynamicState::eScissor,
56-
vk::DynamicState::eLineWidth,
57-
};
58-
auto pdsci = vk::PipelineDynamicStateCreateInfo{};
59-
pdsci.setDynamicStates(pdscis);
60-
61-
// single viewport and scissor.
62-
auto const pvsci = vk::PipelineViewportStateCreateInfo({}, 1, {}, 1);
63-
64-
auto pmsci = vk::PipelineMultisampleStateCreateInfo{};
65-
pmsci.setRasterizationSamples(m_info.samples)
59+
return ret;
60+
}
61+
} // namespace
62+
63+
PipelineBuilder::PipelineBuilder(CreateInfo const& create_info)
64+
: m_info(create_info) {}
65+
66+
auto PipelineBuilder::build(vk::PipelineLayout const layout,
67+
PipelineState const& state) const
68+
-> vk::UniquePipeline {
69+
auto const shader_stage_ci =
70+
create_shader_stages(state.vertex_shader, state.fragment_shader);
71+
72+
auto vertex_input_ci = vk::PipelineVertexInputStateCreateInfo{};
73+
vertex_input_ci.setVertexAttributeDescriptions(state.vertex_attributes)
74+
.setVertexBindingDescriptions(state.vertex_bindings);
75+
76+
auto multisample_state_ci = vk::PipelineMultisampleStateCreateInfo{};
77+
multisample_state_ci.setRasterizationSamples(m_info.samples)
6678
.setSampleShadingEnable(vk::False);
6779

68-
auto prci = vk::PipelineRenderingCreateInfo{};
69-
// could be a depth-only pass.
80+
auto const input_assembly_ci =
81+
vk::PipelineInputAssemblyStateCreateInfo{{}, state.topology};
82+
83+
auto rasterization_state_ci = vk::PipelineRasterizationStateCreateInfo{};
84+
rasterization_state_ci.setPolygonMode(state.polygon_mode)
85+
.setCullMode(state.cull_mode);
86+
87+
auto const depth_stencil_state_ci =
88+
create_depth_stencil_state(state.flags, state.depth_compare);
89+
90+
auto const color_blend_attachment =
91+
create_color_blend_attachment(state.flags);
92+
auto color_blend_state_ci = vk::PipelineColorBlendStateCreateInfo{};
93+
color_blend_state_ci.setAttachments(color_blend_attachment);
94+
95+
auto dynamic_state_ci = vk::PipelineDynamicStateCreateInfo{};
96+
dynamic_state_ci.setDynamicStates(dynamic_states_v);
97+
98+
// Dynamic Rendering requires passing this in the pNext chain.
99+
auto rendering_ci = vk::PipelineRenderingCreateInfo{};
100+
// could be a depth-only pass, argument is a span-like (notice the plural
101+
// `Formats()`), only set if not Undefined.
70102
if (m_info.color_format != vk::Format::eUndefined) {
71-
prci.setColorAttachmentFormats(m_info.color_format);
103+
rendering_ci.setColorAttachmentFormats(m_info.color_format);
72104
}
73-
prci.setDepthAttachmentFormat(m_info.depth_format);
74-
75-
auto gpci = vk::GraphicsPipelineCreateInfo{};
76-
gpci.setStages(shader_stages)
77-
.setPRasterizationState(&prsci)
78-
.setPDepthStencilState(&pdssci)
79-
.setPInputAssemblyState(&piasci)
80-
.setPColorBlendState(&pcbsci)
81-
.setPDynamicState(&pdsci)
82-
.setPViewportState(&pvsci)
83-
.setPMultisampleState(&pmsci)
84-
.setLayout(layout)
85-
.setPNext(&prci);
105+
// single depth attachment format, ok to set to Undefined.
106+
rendering_ci.setDepthAttachmentFormat(m_info.depth_format);
107+
108+
auto pipeline_ci = vk::GraphicsPipelineCreateInfo{};
109+
pipeline_ci.setLayout(layout)
110+
.setStages(shader_stage_ci)
111+
.setPVertexInputState(&vertex_input_ci)
112+
.setPViewportState(&viewport_state_v)
113+
.setPMultisampleState(&multisample_state_ci)
114+
.setPInputAssemblyState(&input_assembly_ci)
115+
.setPRasterizationState(&rasterization_state_ci)
116+
.setPDepthStencilState(&depth_stencil_state_ci)
117+
.setPColorBlendState(&color_blend_state_ci)
118+
.setPDynamicState(&dynamic_state_ci)
119+
.setPNext(&rendering_ci);
86120

87121
auto ret = vk::Pipeline{};
88122
// use non-throwing API.
89-
if (m_info.device.createGraphicsPipelines({}, 1, &gpci, {}, &ret) !=
123+
if (m_info.device.createGraphicsPipelines({}, 1, &pipeline_ci, {}, &ret) !=
90124
vk::Result::eSuccess) {
91125
return {};
92126
}

0 commit comments

Comments
 (0)