Aeon Engine c550894
AeonGames Open Source Game Engine
Loading...
Searching...
No Matches
VulkanPipeline.cpp
1/*
2Copyright (C) 2017-2021,2025,2026 Rodrigo Jose Hernandez Cordoba
3
4Licensed under the Apache License, Version 2.0 (the "License");
5you may not use this file except in compliance with the License.
6You may obtain a copy of the License at
7
8http://www.apache.org/licenses/LICENSE-2.0
9
10Unless required by applicable law or agreed to in writing, software
11distributed under the License is distributed on an "AS IS" BASIS,
12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13See the License for the specific language governing permissions and
14limitations under the License.
15*/
16#include <cassert>
17#include <utility>
18#include <vector>
19#include <fstream>
20#include <iostream>
21#include <algorithm>
22#include "aeongames/AeonEngine.hpp"
23#include "aeongames/Utilities.hpp"
25#include "aeongames/CRC.hpp"
26#include <vulkan/vulkan.h>
27#include "VulkanPipeline.hpp"
28#include "VulkanRenderer.hpp"
29#include "VulkanUtilities.hpp"
30#include "SPIR-V/CompilerLinker.hpp"
31#include <spirv_reflect.h>
32
33namespace AeonGames
34{
35 static const std::unordered_map<SpvReflectFormat, VkFormat> SpvReflectToVulkanFormat
36 {
37 { SPV_REFLECT_FORMAT_UNDEFINED, VK_FORMAT_UNDEFINED },
38 { SPV_REFLECT_FORMAT_R16_UINT, VK_FORMAT_R16_UINT },
39 { SPV_REFLECT_FORMAT_R16_SINT, VK_FORMAT_R16_SINT },
40 { SPV_REFLECT_FORMAT_R16_SFLOAT, VK_FORMAT_R16_SFLOAT },
41 { SPV_REFLECT_FORMAT_R16G16_UINT, VK_FORMAT_R16G16_UINT },
42 { SPV_REFLECT_FORMAT_R16G16_SINT, VK_FORMAT_R16G16_SINT },
43 { SPV_REFLECT_FORMAT_R16G16_SFLOAT, VK_FORMAT_R16G16_SFLOAT },
44 { SPV_REFLECT_FORMAT_R16G16B16_UINT, VK_FORMAT_R16G16B16_UINT },
45 { SPV_REFLECT_FORMAT_R16G16B16_SINT, VK_FORMAT_R16G16B16_SINT },
46 { SPV_REFLECT_FORMAT_R16G16B16_SFLOAT, VK_FORMAT_R16G16B16_SFLOAT },
47 { SPV_REFLECT_FORMAT_R16G16B16A16_UINT, VK_FORMAT_R16G16B16A16_UINT },
48 { SPV_REFLECT_FORMAT_R16G16B16A16_SINT, VK_FORMAT_R16G16B16A16_SINT },
49 { SPV_REFLECT_FORMAT_R16G16B16A16_SFLOAT, VK_FORMAT_R16G16B16A16_SFLOAT },
50 { SPV_REFLECT_FORMAT_R32_UINT, VK_FORMAT_R32_UINT },
51 { SPV_REFLECT_FORMAT_R32_SINT, VK_FORMAT_R32_SINT },
52 { SPV_REFLECT_FORMAT_R32_SFLOAT, VK_FORMAT_R32_SFLOAT },
53 { SPV_REFLECT_FORMAT_R32G32_UINT, VK_FORMAT_R32G32_UINT },
54 { SPV_REFLECT_FORMAT_R32G32_SINT, VK_FORMAT_R32G32_SINT },
55 { SPV_REFLECT_FORMAT_R32G32_SFLOAT, VK_FORMAT_R32G32_SFLOAT },
56 { SPV_REFLECT_FORMAT_R32G32B32_UINT, VK_FORMAT_R32G32B32_UINT },
57 { SPV_REFLECT_FORMAT_R32G32B32_SINT, VK_FORMAT_R32G32B32_SINT },
58 { SPV_REFLECT_FORMAT_R32G32B32_SFLOAT, VK_FORMAT_R32G32B32_SFLOAT },
59 { SPV_REFLECT_FORMAT_R32G32B32A32_UINT, VK_FORMAT_R32G32B32A32_UINT },
60 { SPV_REFLECT_FORMAT_R32G32B32A32_SINT, VK_FORMAT_R32G32B32A32_SINT },
61 { SPV_REFLECT_FORMAT_R32G32B32A32_SFLOAT, VK_FORMAT_R32G32B32A32_SFLOAT },
62 { SPV_REFLECT_FORMAT_R64_UINT, VK_FORMAT_R64_UINT },
63 { SPV_REFLECT_FORMAT_R64_SINT, VK_FORMAT_R64_SINT },
64 { SPV_REFLECT_FORMAT_R64_SFLOAT, VK_FORMAT_R64_SFLOAT },
65 { SPV_REFLECT_FORMAT_R64G64_UINT, VK_FORMAT_R64G64_UINT },
66 { SPV_REFLECT_FORMAT_R64G64_SINT, VK_FORMAT_R64G64_SINT },
67 { SPV_REFLECT_FORMAT_R64G64_SFLOAT, VK_FORMAT_R64G64_SFLOAT },
68 { SPV_REFLECT_FORMAT_R64G64B64_UINT, VK_FORMAT_R64G64B64_UINT },
69 { SPV_REFLECT_FORMAT_R64G64B64_SINT, VK_FORMAT_R64G64B64_SINT },
70 { SPV_REFLECT_FORMAT_R64G64B64_SFLOAT, VK_FORMAT_R64G64B64_SFLOAT },
71 { SPV_REFLECT_FORMAT_R64G64B64A64_UINT, VK_FORMAT_R64G64B64A64_UINT },
72 { SPV_REFLECT_FORMAT_R64G64B64A64_SINT, VK_FORMAT_R64G64B64A64_SINT },
73 { SPV_REFLECT_FORMAT_R64G64B64A64_SFLOAT, VK_FORMAT_R64G64B64A64_SFLOAT }
74 };
75
76 static const std::unordered_map<VkFormat, uint32_t> VkFormatToVulkanSize
77 {
78 { VK_FORMAT_UNDEFINED, 0 },
79 { VK_FORMAT_R8G8B8A8_UINT, static_cast<uint32_t> ( sizeof ( uint8_t ) * 4 ) },
80 { VK_FORMAT_R8G8B8A8_UNORM, static_cast<uint32_t> ( sizeof ( uint8_t ) * 4 ) },
81 { VK_FORMAT_R16_UINT, static_cast<uint32_t> ( sizeof ( uint16_t ) ) },
82 { VK_FORMAT_R16_SINT, static_cast<uint32_t> ( sizeof ( int16_t ) ) },
83 { VK_FORMAT_R16_SFLOAT, static_cast<uint32_t> ( sizeof ( float ) ) },
84 { VK_FORMAT_R16G16_UINT, static_cast<uint32_t> ( sizeof ( uint16_t ) * 2 ) },
85 { VK_FORMAT_R16G16_SINT, static_cast<uint32_t> ( sizeof ( int16_t ) * 2 ) },
86 { VK_FORMAT_R16G16_SFLOAT, static_cast<uint32_t> ( sizeof ( float ) * 2 ) },
87 { VK_FORMAT_R16G16B16_UINT, static_cast<uint32_t> ( sizeof ( uint16_t ) * 3 ) },
88 { VK_FORMAT_R16G16B16_SINT, static_cast<uint32_t> ( sizeof ( int16_t ) * 3 ) },
89 { VK_FORMAT_R16G16B16_SFLOAT, static_cast<uint32_t> ( sizeof ( float ) * 3 ) },
90 { VK_FORMAT_R16G16B16A16_UINT, static_cast<uint32_t> ( sizeof ( uint16_t ) * 4 ) },
91 { VK_FORMAT_R16G16B16A16_SINT, static_cast<uint32_t> ( sizeof ( int16_t ) * 4 ) },
92 { VK_FORMAT_R16G16B16A16_SFLOAT, static_cast<uint32_t> ( sizeof ( float ) * 4 ) },
93 { VK_FORMAT_R32_UINT, static_cast<uint32_t> ( sizeof ( uint32_t ) ) },
94 { VK_FORMAT_R32_SINT, static_cast<uint32_t> ( sizeof ( int32_t ) ) },
95 { VK_FORMAT_R32_SFLOAT, static_cast<uint32_t> ( sizeof ( float ) ) },
96 { VK_FORMAT_R32G32_UINT, static_cast<uint32_t> ( sizeof ( uint32_t ) * 2 ) },
97 { VK_FORMAT_R32G32_SINT, static_cast<uint32_t> ( sizeof ( int32_t ) * 2 ) },
98 { VK_FORMAT_R32G32_SFLOAT, static_cast<uint32_t> ( sizeof ( float ) * 2 ) },
99 { VK_FORMAT_R32G32B32_UINT, static_cast<uint32_t> ( sizeof ( uint32_t ) * 3 ) },
100 { VK_FORMAT_R32G32B32_SINT, static_cast<uint32_t> ( sizeof ( int32_t ) * 3 ) },
101 { VK_FORMAT_R32G32B32_SFLOAT, static_cast<uint32_t> ( sizeof ( float ) * 3 ) },
102 { VK_FORMAT_R32G32B32A32_UINT, static_cast<uint32_t> ( sizeof ( uint32_t ) * 4 ) },
103 { VK_FORMAT_R32G32B32A32_SINT, static_cast<uint32_t> ( sizeof ( int32_t ) * 4 ) },
104 { VK_FORMAT_R32G32B32A32_SFLOAT, static_cast<uint32_t> ( sizeof ( float ) * 4 ) },
105 { VK_FORMAT_R64_UINT, static_cast<uint32_t> ( sizeof ( uint64_t ) ) },
106 { VK_FORMAT_R64_SINT, static_cast<uint32_t> ( sizeof ( int64_t ) ) },
107 { VK_FORMAT_R64_SFLOAT, static_cast<uint32_t> ( sizeof ( float ) ) },
108 { VK_FORMAT_R64G64_UINT, static_cast<uint32_t> ( sizeof ( uint64_t ) * 2 ) },
109 { VK_FORMAT_R64G64_SINT, static_cast<uint32_t> ( sizeof ( int64_t ) * 2 ) },
110 { VK_FORMAT_R64G64_SFLOAT, static_cast<uint32_t> ( sizeof ( float ) * 2 ) },
111 { VK_FORMAT_R64G64B64_UINT, static_cast<uint32_t> ( sizeof ( uint64_t ) * 3 ) },
112 { VK_FORMAT_R64G64B64_SINT, static_cast<uint32_t> ( sizeof ( int64_t ) * 3 ) },
113 { VK_FORMAT_R64G64B64_SFLOAT, static_cast<uint32_t> ( sizeof ( float ) * 3 ) },
114 { VK_FORMAT_R64G64B64A64_UINT, static_cast<uint32_t> ( sizeof ( uint64_t ) * 4 ) },
115 { VK_FORMAT_R64G64B64A64_SINT, static_cast<uint32_t> ( sizeof ( int64_t ) * 4 ) },
116 { VK_FORMAT_R64G64B64A64_SFLOAT, static_cast<uint32_t> ( sizeof ( float ) * 4 ) }
117 };
118
119 static const std::unordered_map<SpvReflectDescriptorType, VkDescriptorType> SpvReflectToVulkanDescriptorType
120 {
121 { SPV_REFLECT_DESCRIPTOR_TYPE_SAMPLER, VK_DESCRIPTOR_TYPE_SAMPLER },
122 { SPV_REFLECT_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER },
123 { SPV_REFLECT_DESCRIPTOR_TYPE_SAMPLED_IMAGE, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE },
124 { SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_IMAGE, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE },
125 { SPV_REFLECT_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER },
126 { SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER },
127 { SPV_REFLECT_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER },
128 { SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER },
129 { SPV_REFLECT_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC },
130 { SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC },
131 { SPV_REFLECT_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT },
132 { SPV_REFLECT_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR }
133 };
134
135 static const std::unordered_map<uint32_t, VkPrimitiveTopology> TopologyClassToVulkanTopology
136 {
137 { Pipeline::TOPOLOGY_CLASS_TRIANGLE, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST },
138 { Pipeline::TOPOLOGY_CLASS_LINE, VK_PRIMITIVE_TOPOLOGY_LINE_LIST },
139 { Pipeline::TOPOLOGY_CLASS_POINT, VK_PRIMITIVE_TOPOLOGY_POINT_LIST },
140 { Pipeline::TOPOLOGY_CLASS_PATCH, VK_PRIMITIVE_TOPOLOGY_PATCH_LIST }
141 };
142
144 bool operator!= ( const VkDescriptorSetLayoutBinding& a, const SpvReflectDescriptorBinding& b )
145 {
146 return ! ( a.binding == b.binding &&
147 a.descriptorType == SpvReflectToVulkanDescriptorType.at ( b.descriptor_type ) &&
148 a.descriptorCount == b.count &&
149 a.pImmutableSamplers == nullptr );
150 }
151
153 mVulkanRenderer{aVulkanPipeline.mVulkanRenderer}
154 {
155 std::swap ( mPipeline, aVulkanPipeline.mPipeline );
156 std::swap ( mVkPipelineLayout, aVulkanPipeline.mVkPipelineLayout );
157 std::swap ( mVkPipeline, aVulkanPipeline.mVkPipeline );
158 std::swap ( mVertexStride, aVulkanPipeline.mVertexStride );
159 std::swap ( mPushConstantModelMatrix, aVulkanPipeline.mPushConstantModelMatrix );
160 mVertexAttributes.swap ( aVulkanPipeline.mVertexAttributes );
161 mDescriptorSets.swap ( aVulkanPipeline.mDescriptorSets );
162 }
163
165 std::array<EShLanguage, ShaderType::COUNT> ShaderTypeToEShLanguage
166 {
167 EShLanguage::EShLangVertex,
168 EShLanguage::EShLangFragment,
169 EShLanguage::EShLangCompute,
170 EShLanguage::EShLangTessControl,
171 EShLanguage::EShLangTessEvaluation,
172 EShLanguage::EShLangGeometry
173 };
174
176 std::array<VkShaderStageFlagBits, ShaderType::COUNT> ShaderTypeToShaderStageFlagBit
177 {
178 VK_SHADER_STAGE_VERTEX_BIT,
179 VK_SHADER_STAGE_FRAGMENT_BIT,
180 VK_SHADER_STAGE_COMPUTE_BIT,
181 VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT,
182 VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT,
183 VK_SHADER_STAGE_GEOMETRY_BIT
184 };
185
186 VulkanPipeline::VulkanPipeline ( const VulkanRenderer& aVulkanRenderer, const Pipeline& aPipeline ) :
187 mVulkanRenderer { aVulkanRenderer }, mPipeline{&aPipeline}
188 {
189 std::array < VkShaderModule, ShaderType::COUNT > shader_modules{ { VK_NULL_HANDLE } };
190 CompilerLinker compiler_linker{static_cast<CompilerLinker::TOptions> (
191 CompilerLinker::TOptions::EOptionSpv |
192 CompilerLinker::TOptions::EOptionVulkanRules |
193 CompilerLinker::TOptions::EOptionLinkProgram
194 //| CompilerLinker::TOptions::EOptionDumpReflection
195 ) };
196
197 std::array<std::string_view, ShaderType::COUNT> shader_codes =
198 {
199 aPipeline.GetShaderCode ( VERT ),
200 aPipeline.GetShaderCode ( FRAG ),
201 aPipeline.GetShaderCode ( COMP ),
202 aPipeline.GetShaderCode ( TESC ),
203 aPipeline.GetShaderCode ( TESE ),
204 aPipeline.GetShaderCode ( GEOM )
205 };
206
207 for ( uint32_t i = 0; i < ShaderType::COUNT; ++i )
208 {
209 if ( shader_codes.at ( i ).empty() )
210 {
211 continue;
212 }
213 compiler_linker.AddShaderSource ( ShaderTypeToEShLanguage.at ( i ), shader_codes.at ( i ).data() );
214 }
215
216 if ( CompilerLinker::FailCode result = compiler_linker.CompileAndLink() )
217 {
218 std::ostringstream stream;
219 stream << ( ( result == CompilerLinker::EFailCompile ) ? "Compilation" : "Linking" ) <<
220 " Error:" << std::endl << compiler_linker.GetLog();
221 std::cout << LogLevel::Error << stream.str();
222 throw std::runtime_error ( stream.str().c_str() );
223 }
224
225 uint32_t pipeline_shader_stage_create_info_count{0};
226 std::array<VkPipelineShaderStageCreateInfo, ShaderType::COUNT> pipeline_shader_stage_create_infos{ {} };
227 for ( uint32_t i = 0; i < ShaderType::COUNT; ++i )
228 {
229 const std::vector<uint32_t>& spirv{compiler_linker.GetSpirV ( ShaderTypeToEShLanguage.at ( i ) ) };
230 if ( spirv.size() == 0 )
231 {
232 continue;
233 }
234 VkShaderModuleCreateInfo shader_module_create_info{};
235 shader_module_create_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
236 shader_module_create_info.codeSize = spirv.size() * sizeof ( uint32_t );
237 shader_module_create_info.pCode = spirv.data();
238
239 if ( VkResult result = vkCreateShaderModule ( mVulkanRenderer.GetDevice(), &shader_module_create_info, nullptr, &shader_modules[ i ] ) )
240 {
241 std::ostringstream stream;
242 stream << "Shader module creation failed: ( " << GetVulkanResultString ( result ) << " )";
243 std::cout << LogLevel::Error << stream.str();
244 throw std::runtime_error ( stream.str().c_str() );
245 }
246
247 //--------Reflection----------//
248 SpvReflectShaderModule module {};
249 SpvReflectResult result = spvReflectCreateShaderModule (
250 shader_module_create_info.codeSize,
251 shader_module_create_info.pCode,
252 &module );
253 if ( result != SPV_REFLECT_RESULT_SUCCESS )
254 {
255 std::ostringstream stream;
256 stream << "SPIR-V Reflect module creation failed: ( " << static_cast<int> ( result ) << " )";
257 std::cout << LogLevel::Error << stream.str();
258 throw std::runtime_error ( stream.str().c_str() );
259 }
260
261 if ( i == VERT )
262 {
263 // Only vertex shader needs attribute reflection
264 ReflectAttributes ( module );
265 }
266 ReflectDescriptorSets ( module, static_cast<ShaderType> ( i ) );
267 ReflectPushConstants ( module, static_cast<ShaderType> ( i ) );
268 spvReflectDestroyShaderModule ( &module );
269 //--------Reflection-END----------//
270 //----------------Shader Stages------------------//
271 pipeline_shader_stage_create_infos[pipeline_shader_stage_create_info_count].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
272 pipeline_shader_stage_create_infos[pipeline_shader_stage_create_info_count].pNext = nullptr;
273 pipeline_shader_stage_create_infos[pipeline_shader_stage_create_info_count].flags = 0;
274 pipeline_shader_stage_create_infos[pipeline_shader_stage_create_info_count].module = shader_modules[i];
275 pipeline_shader_stage_create_infos[pipeline_shader_stage_create_info_count].pName = "main";
276 pipeline_shader_stage_create_infos[pipeline_shader_stage_create_info_count].stage = ShaderTypeToShaderStageFlagBit.at ( static_cast<ShaderType> ( i ) );
277 pipeline_shader_stage_create_infos[pipeline_shader_stage_create_info_count++].pSpecializationInfo = nullptr;
278 }
279
280 //----------------Vertex Input------------------//
281 std::array<VkVertexInputBindingDescription, 1> vertex_input_binding_descriptions { {} };
282 vertex_input_binding_descriptions[0].binding = 0;
283 vertex_input_binding_descriptions[0].stride = mVertexStride;
284 vertex_input_binding_descriptions[0].inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
285
286 VkPipelineVertexInputStateCreateInfo pipeline_vertex_input_state_create_info {};
287 pipeline_vertex_input_state_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
288 pipeline_vertex_input_state_create_info.pNext = nullptr;
289 pipeline_vertex_input_state_create_info.flags = 0;
290 pipeline_vertex_input_state_create_info.vertexBindingDescriptionCount = static_cast<uint32_t> ( vertex_input_binding_descriptions.size() );
291 pipeline_vertex_input_state_create_info.pVertexBindingDescriptions = vertex_input_binding_descriptions.data();
292 pipeline_vertex_input_state_create_info.vertexAttributeDescriptionCount = static_cast<uint32_t> ( mVertexAttributes.size() );
293 pipeline_vertex_input_state_create_info.pVertexAttributeDescriptions = mVertexAttributes.data();
294
295 //----------------Input Assembly------------------//
296 VkPipelineInputAssemblyStateCreateInfo pipeline_input_assembly_state_create_info{};
297 pipeline_input_assembly_state_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
298 pipeline_input_assembly_state_create_info.pNext = nullptr;
299 pipeline_input_assembly_state_create_info.flags = 0;
300 pipeline_input_assembly_state_create_info.topology = TopologyClassToVulkanTopology.at ( mPipeline->GetTopologyClass() );
301#ifdef VK_USE_PLATFORM_METAL_EXT
302 pipeline_input_assembly_state_create_info.primitiveRestartEnable = VK_TRUE;
303#else
304 pipeline_input_assembly_state_create_info.primitiveRestartEnable = VK_FALSE;
305#endif
306 //----------------Viewport State------------------//
307 VkPipelineViewportStateCreateInfo pipeline_viewport_state_create_info {};
308 pipeline_viewport_state_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
309 pipeline_viewport_state_create_info.pNext = nullptr;
310 pipeline_viewport_state_create_info.flags = 0;
311 pipeline_viewport_state_create_info.viewportCount = 1;
312 pipeline_viewport_state_create_info.pViewports = nullptr;
313 pipeline_viewport_state_create_info.scissorCount = 1;
314 pipeline_viewport_state_create_info.pScissors = nullptr;
315
316 //----------------Rasterization State------------------//
317 VkPipelineRasterizationStateCreateInfo pipeline_rasterization_state_create_info{};
318 pipeline_rasterization_state_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
319 pipeline_rasterization_state_create_info.pNext = nullptr;
320 pipeline_rasterization_state_create_info.flags = 0;
321 pipeline_rasterization_state_create_info.depthClampEnable = VK_FALSE;
322 pipeline_rasterization_state_create_info.rasterizerDiscardEnable = VK_FALSE;
323 pipeline_rasterization_state_create_info.polygonMode = VK_POLYGON_MODE_FILL;
324 pipeline_rasterization_state_create_info.cullMode = VK_CULL_MODE_BACK_BIT;
325 pipeline_rasterization_state_create_info.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
326 pipeline_rasterization_state_create_info.depthBiasEnable = VK_TRUE;
327 pipeline_rasterization_state_create_info.depthBiasConstantFactor = 0.0f;
328 pipeline_rasterization_state_create_info.depthBiasClamp = 0.0f;
329 pipeline_rasterization_state_create_info.depthBiasSlopeFactor = 0.0f;
330 pipeline_rasterization_state_create_info.lineWidth = 1.0f;
331
332 //----------------Multisample State------------------//
333 VkPipelineMultisampleStateCreateInfo pipeline_multisample_state_create_info{};
334 pipeline_multisample_state_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
335 pipeline_multisample_state_create_info.pNext = nullptr;
336 pipeline_multisample_state_create_info.flags = 0;
337 pipeline_multisample_state_create_info.sampleShadingEnable = VK_FALSE;
338 pipeline_multisample_state_create_info.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
339 pipeline_multisample_state_create_info.minSampleShading = 0.0f;
340 pipeline_multisample_state_create_info.pSampleMask = nullptr;
341 pipeline_multisample_state_create_info.alphaToCoverageEnable = VK_TRUE;
342 pipeline_multisample_state_create_info.alphaToOneEnable = VK_FALSE;
343
344 //----------------Depth Stencil State------------------//
345 VkPipelineDepthStencilStateCreateInfo pipeline_depth_stencil_state_create_info{};
346 pipeline_depth_stencil_state_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
347 pipeline_depth_stencil_state_create_info.pNext = nullptr;
348 pipeline_depth_stencil_state_create_info.flags = 0;
349 pipeline_depth_stencil_state_create_info.depthTestEnable = VK_TRUE;
350 pipeline_depth_stencil_state_create_info.depthWriteEnable = VK_TRUE;
351 pipeline_depth_stencil_state_create_info.depthCompareOp = VK_COMPARE_OP_LESS;
352 pipeline_depth_stencil_state_create_info.depthBoundsTestEnable = VK_FALSE;
353 pipeline_depth_stencil_state_create_info.stencilTestEnable = VK_FALSE;
354 pipeline_depth_stencil_state_create_info.front = {};
355 pipeline_depth_stencil_state_create_info.back = {};
356 pipeline_depth_stencil_state_create_info.minDepthBounds = 0.0f;
357 pipeline_depth_stencil_state_create_info.maxDepthBounds = 1.0f;
358
359 //----------------Color Blend State------------------//
360 std::array<VkPipelineColorBlendAttachmentState, 1> pipeline_color_blend_attachment_states{ {} };
361 pipeline_color_blend_attachment_states[0].colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
362 pipeline_color_blend_attachment_states[0].blendEnable = VK_TRUE;
363 pipeline_color_blend_attachment_states[0].srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
364 pipeline_color_blend_attachment_states[0].dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
365 pipeline_color_blend_attachment_states[0].colorBlendOp = VK_BLEND_OP_ADD;
366 pipeline_color_blend_attachment_states[0].srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
367 pipeline_color_blend_attachment_states[0].dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO;
368 pipeline_color_blend_attachment_states[0].alphaBlendOp = VK_BLEND_OP_ADD;
369
370 VkPipelineColorBlendStateCreateInfo pipeline_color_blend_state_create_info{};
371 pipeline_color_blend_state_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
372 pipeline_color_blend_state_create_info.pNext = nullptr;
373 pipeline_color_blend_state_create_info.flags = 0;
374 pipeline_color_blend_state_create_info.logicOpEnable = VK_FALSE;
375 pipeline_color_blend_state_create_info.logicOp = VK_LOGIC_OP_COPY;
376 pipeline_color_blend_state_create_info.attachmentCount = static_cast<uint32_t> ( pipeline_color_blend_attachment_states.size() );
377 pipeline_color_blend_state_create_info.pAttachments = pipeline_color_blend_attachment_states.data();
378 memset ( pipeline_color_blend_state_create_info.blendConstants, 0, sizeof ( VkPipelineColorBlendStateCreateInfo::blendConstants ) );
379
380 //----------------Dynamic State------------------//
381 std::array<VkDynamicState, 3> dynamic_states
382 {
383 {
384 VK_DYNAMIC_STATE_VIEWPORT,
385 VK_DYNAMIC_STATE_SCISSOR,
386 VK_DYNAMIC_STATE_PRIMITIVE_TOPOLOGY
387 }
388 };
389 VkPipelineDynamicStateCreateInfo pipeline_dynamic_state_create_info{};
390 pipeline_dynamic_state_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
391 pipeline_dynamic_state_create_info.pNext = nullptr;
392 pipeline_dynamic_state_create_info.flags = 0;
393 pipeline_dynamic_state_create_info.dynamicStateCount = static_cast<uint32_t> ( dynamic_states.size() );
394 pipeline_dynamic_state_create_info.pDynamicStates = dynamic_states.data();
395
396 std::array<VkDescriptorSetLayout, 8> descriptor_set_layouts{};
397 if ( mDescriptorSets.size() > descriptor_set_layouts.size() )
398 {
399 std::cout << LogLevel::Error << "More descriptor sets than available slots" << std::endl;
400 throw std::runtime_error ( "More descriptor sets than available slots" );
401 }
402 for ( const auto& i : mDescriptorSets )
403 {
404 if ( i.set >= mDescriptorSets.size() )
405 {
406 std::cout << LogLevel::Error << "Set index out of bounds" << std::endl;
407 throw std::runtime_error ( "Set index out of bounds" );
408 }
409 descriptor_set_layouts[i.set] = mVulkanRenderer.GetDescriptorSetLayout ( i.descriptor_set_layout_create_info );
410 }
411
412 VkPipelineLayoutCreateInfo pipeline_layout_create_info{};
413 pipeline_layout_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
414 pipeline_layout_create_info.pNext = nullptr;
415 pipeline_layout_create_info.setLayoutCount = static_cast<uint32_t> ( mDescriptorSets.size() );
416 pipeline_layout_create_info.pSetLayouts = mDescriptorSets.size() ? descriptor_set_layouts.data() : nullptr;
417 pipeline_layout_create_info.pushConstantRangeCount = mPushConstantModelMatrix.offset == 0 && mPushConstantModelMatrix.size == 0 ? 0 : 1;
418 pipeline_layout_create_info.pPushConstantRanges = pipeline_layout_create_info.pushConstantRangeCount ? &mPushConstantModelMatrix : nullptr;
419 if ( VkResult result = vkCreatePipelineLayout ( mVulkanRenderer.GetDevice(), &pipeline_layout_create_info, nullptr, &mVkPipelineLayout ) )
420 {
421 std::ostringstream stream;
422 stream << "Pipeline Layout creation failed: ( " << GetVulkanResultString ( result ) << " )";
423 std::cout << LogLevel::Error << stream.str() << std::endl;
424 throw std::runtime_error ( stream.str().c_str() );
425 }
426
427 //----------------Shader Stages------------------//
428 VkGraphicsPipelineCreateInfo graphics_pipeline_create_info {};
429 graphics_pipeline_create_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
430 graphics_pipeline_create_info.pNext = nullptr;
431 graphics_pipeline_create_info.flags = 0;
432 graphics_pipeline_create_info.stageCount = pipeline_shader_stage_create_info_count;
433 graphics_pipeline_create_info.pStages = pipeline_shader_stage_create_infos.data();
434 graphics_pipeline_create_info.pVertexInputState = &pipeline_vertex_input_state_create_info;
435 graphics_pipeline_create_info.pInputAssemblyState = &pipeline_input_assembly_state_create_info;
436 graphics_pipeline_create_info.pTessellationState = nullptr;
437 graphics_pipeline_create_info.pViewportState = &pipeline_viewport_state_create_info;
438 graphics_pipeline_create_info.pRasterizationState = &pipeline_rasterization_state_create_info;
439 graphics_pipeline_create_info.pMultisampleState = &pipeline_multisample_state_create_info;
440 graphics_pipeline_create_info.pDepthStencilState = &pipeline_depth_stencil_state_create_info;
441 graphics_pipeline_create_info.pColorBlendState = &pipeline_color_blend_state_create_info;
442 graphics_pipeline_create_info.pDynamicState = &pipeline_dynamic_state_create_info;
443 graphics_pipeline_create_info.layout = mVkPipelineLayout;
444 graphics_pipeline_create_info.renderPass = mVulkanRenderer.GetRenderPass();
445 graphics_pipeline_create_info.subpass = 0;
446 graphics_pipeline_create_info.basePipelineHandle = VK_NULL_HANDLE;
447 graphics_pipeline_create_info.basePipelineIndex = 0;
448
449 if ( VkResult result = vkCreateGraphicsPipelines ( mVulkanRenderer.GetDevice(), VK_NULL_HANDLE, 1, &graphics_pipeline_create_info, nullptr, &mVkPipeline ) )
450 {
451 std::ostringstream stream;
452 stream << "Pipeline creation failed: ( " << GetVulkanResultString ( result ) << " )";
453 std::cout << LogLevel::Error << stream.str() << std::endl;
454 throw std::runtime_error ( stream.str().c_str() );
455 }
456 for ( auto& i : shader_modules )
457 {
458 if ( i != VK_NULL_HANDLE )
459 {
460 vkDestroyShaderModule ( mVulkanRenderer.GetDevice(), i, nullptr );
461 i = VK_NULL_HANDLE;
462 }
463 }
464 }
465
466 VulkanPipeline::~VulkanPipeline()
467 {
468 vkDestroyPipeline ( mVulkanRenderer.GetDevice(), mVkPipeline, nullptr );
469 vkDestroyPipelineLayout ( mVulkanRenderer.GetDevice(), mVkPipelineLayout, nullptr );
470 }
471
472 const VkPipelineLayout VulkanPipeline::GetPipelineLayout() const
473 {
474 return mVkPipelineLayout;
475 }
476
477 const VkPipeline VulkanPipeline::GetVkPipeline() const
478 {
479 return mVkPipeline;
480 }
481
483 {
484 return mPipeline;
485 }
486
487 const VkDescriptorSetLayout VulkanPipeline::GetDescriptorSetLayout ( uint32_t name ) const
488 {
489 auto it = std::lower_bound ( mDescriptorSets.begin(), mDescriptorSets.end(), name,
490 [] ( const VulkanDescriptorSetInfo & a, const uint32_t b )
491 {
492 return a.hash < b;
493 } );
494 if ( it != mDescriptorSets.end() && it->hash == name )
495 {
496 return mVulkanRenderer.GetDescriptorSetLayout ( it->descriptor_set_layout_create_info );
497 }
498 return VK_NULL_HANDLE;
499 }
500
501 void VulkanPipeline::ReflectAttributes ( SpvReflectShaderModule& module )
502 {
503 uint32_t var_count{0};
504 SpvReflectResult result{spvReflectEnumerateInputVariables ( &module, &var_count, nullptr ) };
505 if ( result != SPV_REFLECT_RESULT_SUCCESS )
506 {
507 std::ostringstream stream;
508 stream << "SPIR-V Reflect input variable enumeration failed: ( " << static_cast<int> ( result ) << " )";
509 std::cout << LogLevel::Error << stream.str();
510 throw std::runtime_error ( stream.str().c_str() );
511 }
512 std::vector<SpvReflectInterfaceVariable*> input_vars ( var_count );
513 result = spvReflectEnumerateInputVariables ( &module, &var_count, input_vars.data() );
514 if ( result != SPV_REFLECT_RESULT_SUCCESS )
515 {
516 std::ostringstream stream;
517 stream << "SPIR-V Reflect input variable enumeration failed: ( " << static_cast<int> ( result ) << " )";
518 std::cout << LogLevel::Error << stream.str();
519 throw std::runtime_error ( stream.str().c_str() );
520 }
521 mVertexAttributes.reserve ( mVertexAttributes.capacity() + input_vars.size() );
522 for ( const auto& i : input_vars )
523 {
524 if ( i->built_in < 0 )
525 {
526 const uint32_t name_crc{crc32i ( i->name, strlen ( i->name ) ) };
527 // Override format for weight attributes - they use 8-bit data even though shader declares 32-bit
528 VkFormat format;
529 if ( name_crc == Mesh::WEIGHT_INDEX )
530 {
531 format = VK_FORMAT_R8G8B8A8_UINT; // uint8_t indices
532 }
533 else if ( name_crc == Mesh::WEIGHT_VALUE )
534 {
535 format = VK_FORMAT_R8G8B8A8_UNORM; // normalized uint8_t weights (0-255 -> 0.0-1.0)
536 }
537 else
538 {
539 format = SpvReflectToVulkanFormat.at ( i->format );
540 }
541
542 auto it = std::lower_bound ( mVertexAttributes.begin(), mVertexAttributes.end(), i->location,
543 [] ( const VkVertexInputAttributeDescription & a, const uint32_t b )
544 {
545 return a.location < b;
546 } );
547 mVertexAttributes.insert ( it,
548 {
549 i->location,
550 0,
551 format,
552 0
553 } );
554 }
555 }
556 for ( auto& attr : mVertexAttributes )
557 {
558 // Calculate offsets and stride
559 attr.offset = mVertexStride;
560 mVertexStride += VkFormatToVulkanSize.at ( attr.format );
561 }
562 }
563
564 void VulkanPipeline::ReflectDescriptorSets ( SpvReflectShaderModule& aModule, ShaderType aType )
565 {
566 // Get descriptor set count
567 uint32_t descriptor_set_count = 0;
568 SpvReflectResult result = spvReflectEnumerateDescriptorSets ( &aModule, &descriptor_set_count, nullptr );
569 if ( result != SPV_REFLECT_RESULT_SUCCESS )
570 {
571 std::ostringstream stream;
572 stream << "SPIR-V Reflect descriptor set enumeration failed: ( " << static_cast<int> ( result ) << " )";
573 std::cout << LogLevel::Error << stream.str();
574 throw std::runtime_error ( stream.str().c_str() );
575 }
576
577 if ( descriptor_set_count > 0 )
578 {
579 std::vector<SpvReflectDescriptorSet*> descriptor_sets ( descriptor_set_count );
580 result = spvReflectEnumerateDescriptorSets ( &aModule, &descriptor_set_count, descriptor_sets.data() );
581 if ( result != SPV_REFLECT_RESULT_SUCCESS )
582 {
583 std::ostringstream stream;
584 stream << "SPIR-V Reflect descriptor set enumeration failed: ( " << static_cast<int> ( result ) << " )";
585 std::cout << LogLevel::Error << stream.str();
586 throw std::runtime_error ( stream.str().c_str() );
587 }
588 for ( const auto& descriptor_set : descriptor_sets )
589 {
590
591 const char* type_name{ ( descriptor_set->binding_count == 1 ) && descriptor_set->bindings[0]->descriptor_type == SPV_REFLECT_DESCRIPTOR_TYPE_UNIFORM_BUFFER ?
592 descriptor_set->bindings[0]->type_description->type_name : "Samplers"};
593 uint32_t hash = crc32i ( type_name,
594 strlen ( type_name ) );
595
596 auto it = std::lower_bound ( mDescriptorSets.begin(), mDescriptorSets.end(), hash,
597 [] ( const VulkanDescriptorSetInfo & a, const uint32_t b )
598 {
599 return a.hash < b;
600 } );
601
603 if ( it != mDescriptorSets.end() && it->hash == hash && it->set == descriptor_set->set )
604 {
605#if 0
606 for ( auto& binding : it->descriptor_set_layout_bindings )
607 {
608 binding.stageFlags |= ShaderTypeToShaderStageFlagBit.at ( aType );
609 }
610#endif
611 continue;
612 }
613
614 it = mDescriptorSets.insert ( it,
615 VulkanDescriptorSetInfo
616 {
617 hash,
618 descriptor_set->set,
619 VkDescriptorSetLayoutCreateInfo
620 {
621 .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
622 .pNext = nullptr,
623 .flags = 0
624 },
625 {}
626 } );
627 it->descriptor_set_layout_bindings.reserve ( descriptor_set->binding_count );
628 std::cout << LogLevel::Debug << "Descriptor set " << descriptor_set->set << std::endl;
629
630 for ( uint32_t i = 0; i < descriptor_set->binding_count; ++i )
631 {
632 const SpvReflectDescriptorBinding& descriptor_set_binding = *descriptor_set->bindings[i];
633 auto layout_binding = std::lower_bound ( it->descriptor_set_layout_bindings.begin(), it->descriptor_set_layout_bindings.end(), descriptor_set_binding.binding,
634 [] ( const VkDescriptorSetLayoutBinding & a, const uint32_t b )
635 {
636 return a.binding < b;
637 } );
638
639 if ( layout_binding == it->descriptor_set_layout_bindings.end() || layout_binding->binding != descriptor_set_binding.binding )
640 {
641 layout_binding = it->descriptor_set_layout_bindings.insert ( layout_binding, VkDescriptorSetLayoutBinding{} );
642 layout_binding->binding = descriptor_set_binding.binding;
643 layout_binding->descriptorType = ( hash == Mesh::BindingLocations::SKELETON ) ? VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC : SpvReflectToVulkanDescriptorType.at ( descriptor_set_binding.descriptor_type );
644 layout_binding->descriptorCount = descriptor_set_binding.count;
645 //layout_binding->stageFlags = ShaderTypeToShaderStageFlagBit.at ( aType );
646 layout_binding->stageFlags = VK_SHADER_STAGE_ALL;
647 layout_binding->pImmutableSamplers = nullptr;
648 std::cout << LogLevel::Debug << "Set " << descriptor_set_binding.set << " New Binding " << descriptor_set_binding.binding << " Type Name " << type_name << " Shader Type " << ShaderTypeToString.at ( aType ) << std::endl;
649 }
650 }
651 it->descriptor_set_layout_create_info.bindingCount = static_cast<uint32_t> ( it->descriptor_set_layout_bindings.size() );
652 it->descriptor_set_layout_create_info.pBindings = it->descriptor_set_layout_bindings.data();
653 }
654 }
655 }
656
657 uint32_t VulkanPipeline::GetDescriptorSetIndex ( uint32_t hash ) const
658 {
659 auto it = std::lower_bound ( mDescriptorSets.begin(), mDescriptorSets.end(), hash,
660 [] ( const VulkanDescriptorSetInfo & a, const uint32_t b )
661 {
662 return a.hash < b;
663 } );
664 if ( it != mDescriptorSets.end() && it->hash == hash )
665 {
666 return it->set;
667 }
668 return std::numeric_limits<uint32_t>::max();
669 }
670
671 const VkPushConstantRange& VulkanPipeline::GetPushConstantModelMatrix() const
672 {
673 return mPushConstantModelMatrix;
674 }
675
676 void VulkanPipeline::ReflectPushConstants ( SpvReflectShaderModule& aModule, ShaderType aType )
677 {
678 // Get push constant block count
679 uint32_t push_constant_count{0};
680 SpvReflectResult result{spvReflectEnumeratePushConstantBlocks ( &aModule, &push_constant_count, nullptr ) };
681 if ( result != SPV_REFLECT_RESULT_SUCCESS )
682 {
683 std::ostringstream stream;
684 stream << "SPIR-V Reflect push constant enumeration failed: ( " << static_cast<int> ( result ) << " )";
685 std::cout << LogLevel::Error << stream.str();
686 throw std::runtime_error ( stream.str().c_str() );
687 }
688
689 if ( push_constant_count > 0 )
690 {
691 std::vector<SpvReflectBlockVariable*> push_constant_blocks ( push_constant_count );
692 result = spvReflectEnumeratePushConstantBlocks ( &aModule, &push_constant_count, push_constant_blocks.data() );
693 if ( result != SPV_REFLECT_RESULT_SUCCESS )
694 {
695 std::ostringstream stream;
696 stream << "SPIR-V Reflect push constant enumeration failed: ( " << static_cast<int> ( result ) << " )";
697 std::cout << LogLevel::Error << stream.str();
698 throw std::runtime_error ( stream.str().c_str() );
699 }
700 for ( const auto& push_constant_block : push_constant_blocks )
701 {
702 /* We'll keep it simple and just look for the model matrix push constant */
703 if ( push_constant_block->member_count == 1 && push_constant_block->members[0].name != nullptr &&
704 strcmp ( push_constant_block->members[0].name, "ModelMatrix" ) == 0 )
705 {
706 mPushConstantModelMatrix.stageFlags |= ShaderTypeToShaderStageFlagBit.at ( aType );
707 mPushConstantModelMatrix.offset = push_constant_block->offset;
708 mPushConstantModelMatrix.size = push_constant_block->size;
709 std::cout << LogLevel::Debug << "Model Matrix Push Constant Offset: " << mPushConstantModelMatrix.offset
710 << " Size: " << mPushConstantModelMatrix.size
711 << " Shader Type: " << ShaderTypeToString.at ( aType ) << std::endl;
712 }
713 }
714 }
715 }
716}
Defines log severity levels and stream output for the AeonGames engine.
Compiles and links GLSL shaders into SPIR-V bytecode.
FailCode
Process exit/result codes.
FailCode CompileAndLink()
Compile all added shader sources and link into a program.
const std::vector< uint32_t > & GetSpirV(EShLanguage aStage) const
Get the compiled SPIR-V bytecode for a shader stage.
void AddShaderSource(EShLanguage aStage, const char *aSource)
Add GLSL source code for a shader stage.
const std::string & GetLog() const
Get the compilation/link log output.
TOptions
Compiler/linker option flags.
@ WEIGHT_INDEX
Bone weight indices.
Definition Mesh.hpp:41
@ WEIGHT_VALUE
Bone weight values.
Definition Mesh.hpp:42
@ SKELETON
Skeleton binding.
Definition Mesh.hpp:73
Rendering pipeline resource.
Definition Pipeline.hpp:122
static const uint32_t TOPOLOGY_CLASS_POINT
Point topology class bitmask.
Definition Pipeline.hpp:124
static const uint32_t TOPOLOGY_CLASS_LINE
Line topology class bitmask.
Definition Pipeline.hpp:125
static const uint32_t TOPOLOGY_CLASS_TRIANGLE
Triangle topology class bitmask.
Definition Pipeline.hpp:126
DLL const std::string_view GetShaderCode(ShaderType aType) const
Get the shader source code for the given shader stage.
Definition Pipeline.cpp:204
static const uint32_t TOPOLOGY_CLASS_PATCH
Patch topology class bitmask.
Definition Pipeline.hpp:127
VulkanPipeline(const VulkanRenderer &aVulkanRenderer, const Pipeline &aPipeline)
Construct from a renderer and pipeline resource.
const Pipeline * GetPipeline() const
Get the source Pipeline resource.
const VkDescriptorSetLayout GetDescriptorSetLayout(uint32_t name) const
Get a descriptor set layout by its name hash.
uint32_t GetDescriptorSetIndex(uint32_t hash) const
Get the descriptor set index for a given hash.
const VkPipeline GetVkPipeline() const
Get the Vulkan pipeline handle.
const VkPushConstantRange & GetPushConstantModelMatrix() const
Get the push constant range used for the model matrix.
const VkPipelineLayout GetPipelineLayout() const
Get the Vulkan pipeline layout handle.
Vulkan rendering backend implementing the Renderer interface.
const VkDevice & GetDevice() const
Get the logical device handle.
<- This is here just for the literals
Definition AABB.hpp:31
DLL bool operator!=(const Vector3 &aLhs, const Vector3 &aRhs)
Inequality comparison operator.
Definition Vector3.cpp:239
uint32_t crc32i(const char *message, size_t size, uint32_t previous_crc)
Compute the CRC32 of a given message, continuing from a previous CRC value.
Definition CRC.cpp:27
const char * GetVulkanResultString(VkResult aResult)
Convert a VkResult code to a human-readable string.
const std::unordered_map< ShaderType, const char * > ShaderTypeToString
Map from ShaderType enum values to human-readable string names.
Definition Pipeline.hpp:108
std::array< VkShaderStageFlagBits, ShaderType::COUNT > ShaderTypeToShaderStageFlagBit
Mapping from ShaderType to VkShaderStageFlagBits.
ShaderType
Shader stage types.
Definition Pipeline.hpp:96
@ VERT
Vertex shader.
Definition Pipeline.hpp:97
@ COUNT
Number of shader types.
Definition Pipeline.hpp:103
@ FRAG
Fragment shader.
Definition Pipeline.hpp:98
@ GEOM
Geometry shader.
Definition Pipeline.hpp:102
@ TESC
Tessellation control shader.
Definition Pipeline.hpp:100
@ TESE
Tessellation evaluation shader.
Definition Pipeline.hpp:101
@ COMP
Compute shader.
Definition Pipeline.hpp:99
@ Error
Error conditions.
Definition LogLevel.hpp:33
@ Debug
Detailed diagnostic information.
Definition LogLevel.hpp:29
std::array< EShLanguage, ShaderType::COUNT > ShaderTypeToEShLanguage
Mapping from ShaderType to glslang EShLanguage.
Holds Vulkan descriptor set layout metadata for pipeline reflection.