@@ -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
201249command_buffer.beginRendering(rendering_info);
202250ImGui::ShowDemoWindow();
203251
204252command_buffer.bindPipeline(vk::PipelineBindPoint::eGraphics, *m_pipeline);
205253auto 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/
208256viewport.setX(0.0f)
209257 .setY(static_cast<float>(m_render_target->extent.height))
@@ -242,6 +290,8 @@ layout (location = 0) in vec3 in_color;
242290out_color = vec4(in_color, 1.0);
243291```
244292
293+ > Make sure to recompile both the SPIR-V shaders in assets/.
294+
245295And a black clear color:
246296
247297``` cpp
0 commit comments