HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
gfx_pipeline_vulkan_impl.hpp
1// Copyright Take Vos 2019-2022.
2// Distributed under the Boost Software License, Version 1.0.
3// (See accompanying file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt)
4
5#pragma once
6
7#include "gfx_pipeline_vulkan_intf.hpp"
8#include "gfx_device_vulkan_impl.hpp"
9#include "gfx_surface_vulkan_intf.hpp"
10#include "../telemetry/telemetry.hpp"
11#include "../macros.hpp"
12#include <array>
13#include <vector>
14#include <vulkan/vulkan.hpp>
15
16hi_export_module(hikogui.GFX : gfx_pipeline_impl);
17
18hi_export namespace hi { inline namespace v1 {
19
20[[nodiscard]] inline gfx_device *gfx_pipeline::device() const noexcept
21{
22 hi_axiom_not_null(surface);
23 return surface->device();
24}
25
26inline void gfx_pipeline::draw_in_command_buffer(vk::CommandBuffer commandBuffer, draw_context const& context)
27{
28 commandBuffer.bindPipeline(vk::PipelineBindPoint::eGraphics, intrinsic);
29
30 if (descriptorSet) {
31 if (descriptorSetVersion < getDescriptorSetVersion()) {
32 descriptorSetVersion = getDescriptorSetVersion();
33
34 hi_axiom_not_null(device());
35 device()->updateDescriptorSets(createWriteDescriptorSet(), {});
36 }
37
38 commandBuffer.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, pipelineLayout, 0, {descriptorSet}, {});
39 }
40}
41
42inline void gfx_pipeline::build_descriptor_sets()
43{
44 auto const descriptorSetLayoutBindings = createDescriptorSetLayoutBindings();
45
46 if (ssize(descriptorSetLayoutBindings) == 0) {
47 // Make sure that there is no descriptor set.
48 descriptorSet = nullptr;
49 return;
50 }
51
52 auto const descriptorSetLayoutCreateInfo = vk::DescriptorSetLayoutCreateInfo{
53 vk::DescriptorSetLayoutCreateFlags(),
54 narrow_cast<uint32_t>(descriptorSetLayoutBindings.size()),
55 descriptorSetLayoutBindings.data()};
56
57 hi_axiom_not_null(device());
58 descriptorSetLayout = device()->createDescriptorSetLayout(descriptorSetLayoutCreateInfo);
59
60 auto const descriptorPoolSizes =
61 transform<std::vector<vk::DescriptorPoolSize>>(descriptorSetLayoutBindings, [](auto x) -> vk::DescriptorPoolSize {
62 return {x.descriptorType, narrow_cast<uint32_t>(x.descriptorCount)};
63 });
64
65 descriptorPool = device()->createDescriptorPool(
66 {vk::DescriptorPoolCreateFlags(),
67 1, // maxSets
68 narrow_cast<uint32_t>(descriptorPoolSizes.size()),
69 descriptorPoolSizes.data()});
70
71 auto const descriptorSetLayouts = std::array{descriptorSetLayout};
72
73 auto const descriptorSets = device()->allocateDescriptorSets(
74 {descriptorPool, narrow_cast<uint32_t>(descriptorSetLayouts.size()), descriptorSetLayouts.data()});
75
76 descriptorSet = descriptorSets.at(0);
77 descriptorSetVersion = 0;
78}
79
80inline void gfx_pipeline::teardown_descriptor_sets()
81{
82 if (!descriptorSet) {
83 return;
84 }
85
86 hi_axiom_not_null(device());
87 device()->destroy(descriptorPool);
88 device()->destroy(descriptorSetLayout);
89 descriptorSet = nullptr;
90}
91
92inline vk::PipelineDepthStencilStateCreateInfo gfx_pipeline::getPipelineDepthStencilStateCreateInfo() const
93{
94 // Reverse-z depth configuration
95 return {
96 vk::PipelineDepthStencilStateCreateFlags(),
97 VK_TRUE, // depthTestEnable;
98 VK_TRUE, // depthWriteEnable;
99 vk::CompareOp::eGreaterOrEqual, // depthCompareOp
100 VK_FALSE, // depthBoundsTestEnable
101 VK_FALSE, // stencilTestEnable,
102 vk::StencilOpState(), // front
103 vk::StencilOpState(), // back
104 1.0f, // minDepthBounds
105 0.0f, // maxDepthBounds
106 };
107}
108
109/* pre-multiplied alpha blending.
110 */
111inline std::vector<vk::PipelineColorBlendAttachmentState> gfx_pipeline::getPipelineColorBlendAttachmentStates() const
112{
113 return {
114 {VK_TRUE, // blendEnable
115 vk::BlendFactor::eOne, // srcColorBlendFactor
116 vk::BlendFactor::eOneMinusSrcAlpha, // dstColorBlendFactor
117 vk::BlendOp::eAdd, // colorBlendOp
118 vk::BlendFactor::eOne, // srcAlphaBlendFactor
119 vk::BlendFactor::eOneMinusSrcAlpha, // dstAlphaBlendFactor
120 vk::BlendOp::eAdd, // aphaBlendOp
121 vk::ColorComponentFlagBits::eR | vk::ColorComponentFlagBits::eG | vk::ColorComponentFlagBits::eB |
122 vk::ColorComponentFlagBits::eA}};
123}
124
125inline void gfx_pipeline::build_pipeline(vk::RenderPass renderPass, uint32_t renderSubpass, vk::Extent2D _extent)
126{
127 hi_log_info("buildPipeline previous size ({}, {})", extent.width, extent.height);
128 extent = _extent;
129
130 const auto pushConstantRanges = createPushConstantRanges();
131 const auto vertexInputBindingDescription = createVertexInputBindingDescription();
132 const auto vertexInputAttributeDescriptions = createVertexInputAttributeDescriptions();
133 const auto shaderStages = createShaderStages();
134
135 std::vector<vk::DescriptorSetLayout> descriptorSetLayouts;
136 if (descriptorSet) {
137 descriptorSetLayouts.push_back(descriptorSetLayout);
138 }
139
140 hi_axiom_not_null(device());
141 pipelineLayout = device()->createPipelineLayout(
142 {vk::PipelineLayoutCreateFlags(),
143 narrow_cast<uint32_t>(descriptorSetLayouts.size()),
144 descriptorSetLayouts.data(),
145 narrow_cast<uint32_t>(pushConstantRanges.size()),
146 pushConstantRanges.data()});
147
148 const vk::PipelineVertexInputStateCreateInfo pipelineVertexInputStateCreateInfo = {
149 vk::PipelineVertexInputStateCreateFlags(),
150 1,
151 &vertexInputBindingDescription,
152 narrow_cast<uint32_t>(vertexInputAttributeDescriptions.size()),
153 vertexInputAttributeDescriptions.data()};
154
155 const vk::PipelineInputAssemblyStateCreateInfo pipelineInputAssemblyStateCreateInfo = {
156 vk::PipelineInputAssemblyStateCreateFlags(), vk::PrimitiveTopology::eTriangleList, VK_FALSE};
157
158 const std::array<vk::Viewport, 1> viewports = {vk::Viewport{
159 0.0f,
160 0.0f,
161 narrow_cast<float>(extent.width),
162 narrow_cast<float>(extent.height),
163 // Reverse-z, with float buffer this will give a linear depth buffer.
164 1.0f,
165 0.0f}};
166
167 auto const scissor = vk::Rect2D{vk::Offset2D{0, 0}, extent};
168
169 auto const scissors = std::array{scissor};
170
171 const vk::PipelineViewportStateCreateInfo pipelineViewportStateCreateInfo = {
172 vk::PipelineViewportStateCreateFlags(),
173 narrow_cast<uint32_t>(viewports.size()),
174 viewports.data(),
175 narrow_cast<uint32_t>(scissors.size()),
176 scissors.data()};
177
178 const vk::PipelineRasterizationStateCreateInfo pipelineRasterizationStateCreateInfo = {
179 vk::PipelineRasterizationStateCreateFlags(),
180 VK_FALSE, // depthClampEnable
181 VK_FALSE, // rasterizerDiscardEnable
182 vk::PolygonMode::eFill,
183 vk::CullModeFlagBits::eBack,
184 vk::FrontFace::eCounterClockwise,
185 VK_FALSE, // depthBiasEnable
186 0.0, // depthBiasConstantFactor
187 0.0, // depthBiasClamp
188 0.0, // depthBiasSlopeFactor
189 1.0 // lineWidth
190 };
191
192 const vk::PipelineMultisampleStateCreateInfo pipelineMultisampleStateCreateInfo = {
193 vk::PipelineMultisampleStateCreateFlags(),
194 vk::SampleCountFlagBits::e1,
195 VK_FALSE, // sampleShadingEnable
196 1.0f, // minSampleShading
197 nullptr, // sampleMask
198 VK_FALSE, // alphaToCoverageEnable
199 VK_FALSE // alphaToOneEnable
200 };
201
202 auto const pipelineDepthStencilStateCreateInfo = getPipelineDepthStencilStateCreateInfo();
203
204 /* Pre-multiplied alpha blending.
205 */
206 auto const pipelineColorBlendAttachmentStates = getPipelineColorBlendAttachmentStates();
207
208 const vk::PipelineColorBlendStateCreateInfo pipelineColorBlendStateCreateInfo = {
209 vk::PipelineColorBlendStateCreateFlags(),
210 VK_FALSE, // logicOpenable
211 vk::LogicOp::eCopy,
212 narrow_cast<uint32_t>(pipelineColorBlendAttachmentStates.size()),
213 pipelineColorBlendAttachmentStates.data()};
214
215 auto const dynamicStates = std::array{vk::DynamicState::eScissor};
216
217 auto const pipelineDynamicStateInfo = vk::PipelineDynamicStateCreateInfo{
218 vk::PipelineDynamicStateCreateFlags(), narrow_cast<uint32_t>(dynamicStates.size()), dynamicStates.data()};
219
220 const vk::GraphicsPipelineCreateInfo graphicsPipelineCreateInfo = {
221 vk::PipelineCreateFlags(),
222 narrow_cast<uint32_t>(shaderStages.size()),
223 shaderStages.data(),
224 &pipelineVertexInputStateCreateInfo,
225 &pipelineInputAssemblyStateCreateInfo,
226 nullptr, // tesselationStateCreateInfo
227 &pipelineViewportStateCreateInfo,
228 &pipelineRasterizationStateCreateInfo,
229 &pipelineMultisampleStateCreateInfo,
230 &pipelineDepthStencilStateCreateInfo,
231 &pipelineColorBlendStateCreateInfo,
232 &pipelineDynamicStateInfo,
233 pipelineLayout,
234 renderPass,
235 renderSubpass, // subpass
236 vk::Pipeline(), // basePipelineHandle
237 -1 // basePipelineIndex
238 };
239
240 hi_axiom_not_null(device());
241 intrinsic = device()->createGraphicsPipeline(vk::PipelineCache(), graphicsPipelineCreateInfo);
242 hi_log_info("/buildPipeline new size ({}, {})", extent.width, extent.height);
243}
244
245inline void gfx_pipeline::teardown_pipeline()
246{
247 hi_axiom_not_null(device());
248 device()->destroy(intrinsic);
249 device()->destroy(pipelineLayout);
250}
251
252inline void gfx_pipeline::build_for_new_device()
253{
254 build_vertex_buffers();
255}
256
257inline void gfx_pipeline::teardown_for_device_lost()
258{
259 teardown_vertex_buffers();
260}
261
262inline void gfx_pipeline::build_for_new_swapchain(vk::RenderPass renderPass, uint32_t renderSubpass, vk::Extent2D _extent)
263{
264 // Input attachments described by the descriptor set will change when a
265 // new swap chain is created.
266 build_descriptor_sets();
267 build_pipeline(renderPass, renderSubpass, _extent);
268}
269
270inline void gfx_pipeline::teardown_for_swapchain_lost()
271{
272 teardown_pipeline();
273 teardown_descriptor_sets();
274}
275
276}} // namespace hi::inline v1
The HikoGUI namespace.
Definition array_generic.hpp:20
DOXYGEN BUG.
Definition algorithm_misc.hpp:20
T at(T... args)
T data(T... args)
T push_back(T... args)
T size(T... args)