5#ifdef VISUTWIN_HAS_VULKAN
16#include "spdlog/spdlog.h"
20 VulkanRenderPipeline::VulkanRenderPipeline(VulkanGraphicsDevice* device)
26 VulkanRenderPipeline::~VulkanRenderPipeline()
28 VkDevice vk = _device->device();
29 for (
auto& [key, pipeline] : _cache) {
30 vkDestroyPipeline(vk, pipeline,
nullptr);
32 if (_pipelineLayout != VK_NULL_HANDLE)
33 vkDestroyPipelineLayout(vk, _pipelineLayout,
nullptr);
34 if (_materialSetLayout != VK_NULL_HANDLE)
35 vkDestroyDescriptorSetLayout(vk, _materialSetLayout,
nullptr);
36 if (_textureSetLayout != VK_NULL_HANDLE)
37 vkDestroyDescriptorSetLayout(vk, _textureSetLayout,
nullptr);
40 void VulkanRenderPipeline::createLayouts()
42 VkDevice vk = _device->device();
45 VkDescriptorSetLayoutBinding materialBinding{};
46 materialBinding.binding = 0;
47 materialBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
48 materialBinding.descriptorCount = 1;
49 materialBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
51 VkDescriptorSetLayoutCreateInfo materialLayoutInfo{VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO};
52 materialLayoutInfo.bindingCount = 1;
53 materialLayoutInfo.pBindings = &materialBinding;
54 vkCreateDescriptorSetLayout(vk, &materialLayoutInfo,
nullptr, &_materialSetLayout);
57 std::array<VkDescriptorSetLayoutBinding, 6> texBindings{};
58 for (uint32_t i = 0; i < texBindings.size(); i++) {
59 texBindings[i].binding = i;
60 texBindings[i].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
61 texBindings[i].descriptorCount = 1;
62 texBindings[i].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
65 VkDescriptorSetLayoutCreateInfo textureLayoutInfo{VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO};
66 textureLayoutInfo.bindingCount =
static_cast<uint32_t
>(texBindings.size());
67 textureLayoutInfo.pBindings = texBindings.data();
68 vkCreateDescriptorSetLayout(vk, &textureLayoutInfo,
nullptr, &_textureSetLayout);
71 VkPushConstantRange pushRange{};
72 pushRange.stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
76 VkDescriptorSetLayout setLayouts[] = {_materialSetLayout, _textureSetLayout};
78 VkPipelineLayoutCreateInfo layoutInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO};
79 layoutInfo.setLayoutCount = 2;
80 layoutInfo.pSetLayouts = setLayouts;
81 layoutInfo.pushConstantRangeCount = 1;
82 layoutInfo.pPushConstantRanges = &pushRange;
83 vkCreatePipelineLayout(vk, &layoutInfo,
nullptr, &_pipelineLayout);
86 VkPipeline VulkanRenderPipeline::get(
const Primitive& primitive,
87 const std::shared_ptr<VertexFormat>& vertexFormat,
88 const std::shared_ptr<VulkanShader>& shader,
89 const std::shared_ptr<BlendState>& blendState,
90 const std::shared_ptr<DepthState>& depthState,
96 uint64_t hash = 14695981039346656037ULL;
97 auto mix = [&](uint64_t v) { hash ^= v; hash *= 1099511628211ULL; };
98 mix(
static_cast<uint64_t
>(primitive.type));
99 mix(vertexFormat ? vertexFormat->renderingHash() : 0);
100 mix(shader ?
static_cast<uint64_t
>(shader->id()) : 0);
101 mix(blendState ? blendState->key() : 0);
102 mix(depthState ? depthState->key() : 0);
103 mix(
static_cast<uint64_t
>(cullMode));
104 mix(
static_cast<uint64_t
>(colorFormat));
105 mix(
static_cast<uint64_t
>(depthFormat));
107 auto it = _cache.find(hash);
108 if (it != _cache.end())
return it->second;
110 VkPipeline pipeline = create(primitive, vertexFormat, shader,
111 blendState, depthState, cullMode, colorFormat, depthFormat);
112 _cache[hash] = pipeline;
116 VkPipeline VulkanRenderPipeline::create(
const Primitive& primitive,
117 const std::shared_ptr<VertexFormat>& vertexFormat,
118 const std::shared_ptr<VulkanShader>& shader,
119 const std::shared_ptr<BlendState>& blendState,
120 const std::shared_ptr<DepthState>& depthState,
122 VkFormat colorFormat,
123 VkFormat depthFormat)
125 VkDevice vk = _device->device();
128 std::vector<VkPipelineShaderStageCreateInfo> stages;
129 if (shader->vertexModule() != VK_NULL_HANDLE) {
130 VkPipelineShaderStageCreateInfo vert{VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO};
131 vert.stage = VK_SHADER_STAGE_VERTEX_BIT;
132 vert.module = shader->vertexModule();
134 stages.push_back(vert);
136 if (shader->fragmentModule() != VK_NULL_HANDLE) {
137 VkPipelineShaderStageCreateInfo frag{VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO};
138 frag.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
139 frag.module = shader->fragmentModule();
141 stages.push_back(frag);
146 int stride = vertexFormat ? vertexFormat->size() : 56;
148 VkVertexInputBindingDescription binding{};
150 binding.stride =
static_cast<uint32_t
>(stride);
151 binding.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
154 std::vector<VkVertexInputAttributeDescription> attributes;
156 for (
int i = 0; i < vertexFormat->elementCount(); i++) {
157 auto& elem = vertexFormat->element(i);
158 VkVertexInputAttributeDescription attr{};
159 attr.location =
static_cast<uint32_t
>(i);
161 attr.offset =
static_cast<uint32_t
>(elem.offset);
164 switch (elem.numComponents) {
166 attr.format = (elem.dataType ==
TYPE_FLOAT32) ? VK_FORMAT_R32_SFLOAT : VK_FORMAT_R32_UINT;
169 attr.format = VK_FORMAT_R32G32_SFLOAT;
172 attr.format = VK_FORMAT_R32G32B32_SFLOAT;
175 attr.format = VK_FORMAT_R32G32B32A32_SFLOAT;
178 attr.format = VK_FORMAT_R32G32B32A32_SFLOAT;
181 attributes.push_back(attr);
186 {0, 0, VK_FORMAT_R32G32B32_SFLOAT, 0},
187 {1, 0, VK_FORMAT_R32G32B32_SFLOAT, 12},
188 {2, 0, VK_FORMAT_R32G32_SFLOAT, 24},
189 {3, 0, VK_FORMAT_R32G32B32A32_SFLOAT, 32},
190 {4, 0, VK_FORMAT_R32G32_SFLOAT, 48},
194 VkPipelineVertexInputStateCreateInfo vertexInput{VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO};
195 vertexInput.vertexBindingDescriptionCount = 1;
196 vertexInput.pVertexBindingDescriptions = &binding;
197 vertexInput.vertexAttributeDescriptionCount =
static_cast<uint32_t
>(attributes.size());
198 vertexInput.pVertexAttributeDescriptions = attributes.data();
201 VkPipelineInputAssemblyStateCreateInfo inputAssembly{VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO};
202 inputAssembly.topology = vulkanMapPrimitiveType(primitive.type);
203 inputAssembly.primitiveRestartEnable = VK_FALSE;
206 VkPipelineViewportStateCreateInfo viewportState{VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO};
207 viewportState.viewportCount = 1;
208 viewportState.scissorCount = 1;
211 VkPipelineRasterizationStateCreateInfo rasterization{VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO};
212 rasterization.depthClampEnable = VK_FALSE;
213 rasterization.rasterizerDiscardEnable = VK_FALSE;
214 rasterization.polygonMode = VK_POLYGON_MODE_FILL;
215 rasterization.cullMode = vulkanMapCullMode(cullMode);
216 rasterization.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
217 rasterization.depthBiasEnable = VK_FALSE;
218 rasterization.lineWidth = 1.0f;
221 VkPipelineMultisampleStateCreateInfo multisampling{VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO};
222 multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
225 VkPipelineDepthStencilStateCreateInfo depthStencil{VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO};
227 depthStencil.depthTestEnable = depthState->depthTest() ? VK_TRUE : VK_FALSE;
228 depthStencil.depthWriteEnable = depthState->depthWrite() ? VK_TRUE : VK_FALSE;
230 depthStencil.depthTestEnable = VK_TRUE;
231 depthStencil.depthWriteEnable = VK_TRUE;
233 depthStencil.depthCompareOp = VK_COMPARE_OP_LESS_OR_EQUAL;
234 depthStencil.depthBoundsTestEnable = VK_FALSE;
235 depthStencil.stencilTestEnable = VK_FALSE;
238 VkPipelineColorBlendAttachmentState blendAttachment{};
239 if (blendState && blendState->enabled()) {
240 blendAttachment.blendEnable = VK_TRUE;
241 blendAttachment.srcColorBlendFactor = vulkanMapBlendFactor(blendState->colorSrcFactor());
242 blendAttachment.dstColorBlendFactor = vulkanMapBlendFactor(blendState->colorDstFactor());
243 blendAttachment.colorBlendOp = vulkanMapBlendOp(blendState->colorOp());
244 blendAttachment.srcAlphaBlendFactor = vulkanMapBlendFactor(blendState->alphaSrcFactor());
245 blendAttachment.dstAlphaBlendFactor = vulkanMapBlendFactor(blendState->alphaDstFactor());
246 blendAttachment.alphaBlendOp = vulkanMapBlendOp(blendState->alphaOp());
248 blendAttachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
249 VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
251 VkPipelineColorBlendStateCreateInfo colorBlend{VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO};
252 colorBlend.attachmentCount = 1;
253 colorBlend.pAttachments = &blendAttachment;
256 VkDynamicState dynamicStates[] = {VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR};
257 VkPipelineDynamicStateCreateInfo dynamicState{VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO};
258 dynamicState.dynamicStateCount = 2;
259 dynamicState.pDynamicStates = dynamicStates;
262 VkPipelineRenderingCreateInfo renderingInfo{VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO};
263 renderingInfo.colorAttachmentCount = 1;
264 renderingInfo.pColorAttachmentFormats = &colorFormat;
265 renderingInfo.depthAttachmentFormat = depthFormat;
268 VkGraphicsPipelineCreateInfo pipelineInfo{VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO};
269 pipelineInfo.pNext = &renderingInfo;
270 pipelineInfo.stageCount =
static_cast<uint32_t
>(stages.size());
271 pipelineInfo.pStages = stages.data();
272 pipelineInfo.pVertexInputState = &vertexInput;
273 pipelineInfo.pInputAssemblyState = &inputAssembly;
274 pipelineInfo.pViewportState = &viewportState;
275 pipelineInfo.pRasterizationState = &rasterization;
276 pipelineInfo.pMultisampleState = &multisampling;
277 pipelineInfo.pDepthStencilState = &depthStencil;
278 pipelineInfo.pColorBlendState = &colorBlend;
279 pipelineInfo.pDynamicState = &dynamicState;
280 pipelineInfo.layout = _pipelineLayout;
281 pipelineInfo.renderPass = VK_NULL_HANDLE;
283 VkPipeline pipeline = VK_NULL_HANDLE;
284 VkResult result = vkCreateGraphicsPipelines(vk, VK_NULL_HANDLE, 1, &pipelineInfo,
nullptr, &pipeline);
285 if (result != VK_SUCCESS) {
286 spdlog::error(
"Failed to create Vulkan graphics pipeline: {}",
static_cast<int>(result));