78 log(
"Loading Vulkan library...");
79 if (!SDL_Vulkan_LoadLibrary(
nullptr)) {
83 log(
"Initializing Volk...");
84 volkInitializeCustom(
reinterpret_cast<PFN_vkGetInstanceProcAddr
>(SDL_Vulkan_GetVkGetInstanceProcAddr()));
86 uint32_t loaderVersion = VK_API_VERSION_1_0;
87 if (vkEnumerateInstanceVersion) {
88 vkEnumerateInstanceVersion(&loaderVersion);
91 uint32_t deviceVersion = GetBestDeviceVersion();
93 uint32_t apiVersion = std::min(loaderVersion, deviceVersion);
95 if (apiVersion > VK_API_VERSION_1_3) {
96 apiVersion = VK_API_VERSION_1_3;
99 log(
"API Negotiation: Loader %u.%u | Device %u.%u -> Selected %u.%u",
100 VK_VERSION_MAJOR(loaderVersion), VK_VERSION_MINOR(loaderVersion),
101 VK_VERSION_MAJOR(deviceVersion), VK_VERSION_MINOR(deviceVersion),
102 VK_VERSION_MAJOR(apiVersion), VK_VERSION_MINOR(apiVersion));
104 m_context.vulkanVersion = apiVersion;
105 m_context.currentRenderResolution = initialResolution;
106 m_context.graphicsQueueFamily = UINT32_MAX;
107 m_context.presentQueueFamily = UINT32_MAX;
109 log(
"Creating Vulkan instance...");
110 uint32_t sdlExtensionCount = 0;
111 const char*
const* sdlExtensions = SDL_Vulkan_GetInstanceExtensions(&sdlExtensionCount);
112 std::vector<const char*> extensions(sdlExtensions, sdlExtensions + sdlExtensionCount);
114 extensions.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
116 extensions.push_back(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME);
120 std::vector<const char*> validationLayers;
121 if (CheckValidationLayerSupport()) {
122 validationLayers.push_back(
"VK_LAYER_KHRONOS_validation");
124 log(LogLevel::WARNING,
"Validation layers requested but not available!");
127 const std::vector<const char*> validationLayers;
130 VkApplicationInfo appInfo = {};
131 appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
132 appInfo.pApplicationName = gInfo.projectName.c_str();
133 appInfo.applicationVersion = VK_MAKE_VERSION(gInfo.versionMajor, gInfo.versionMinor, gInfo.versionPatch);
134 appInfo.pEngineName =
"VEX";
135 appInfo.engineVersion = VK_MAKE_VERSION(VEX_VERSION_MAJOR, VEX_VERSION_MINOR, VEX_VERSION_PATCH);
136 appInfo.apiVersion = apiVersion;
138 VkInstanceCreateInfo createInfo = {};
139 createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
140 createInfo.pApplicationInfo = &appInfo;
141 createInfo.enabledExtensionCount =
static_cast<uint32_t
>(extensions.size());
142 createInfo.ppEnabledExtensionNames = extensions.data();
143 createInfo.enabledLayerCount =
static_cast<uint32_t
>(validationLayers.size());
144 createInfo.ppEnabledLayerNames = validationLayers.data();
147 createInfo.flags |= VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR;
150 if (vkCreateInstance(&createInfo,
nullptr, &m_context.instance) != VK_SUCCESS) {
154 volkLoadInstance(m_context.instance);
156 log(
"Binding window...");
157 if (!SDL_Vulkan_CreateSurface(window, m_context.instance,
nullptr, &m_context.surface)) {
158 throw_error(
"Failed to create Vulkan surface: " + std::string(SDL_GetError()));
161 uint32_t deviceCount = 0;
162 vkEnumeratePhysicalDevices(m_context.instance, &deviceCount,
nullptr);
163 if (deviceCount == 0) {
164 throw_error(
"Failed to find GPUs with Vulkan support");
167 std::vector<VkPhysicalDevice> devices(deviceCount);
168 vkEnumeratePhysicalDevices(m_context.instance, &deviceCount, devices.data());
170 VkPhysicalDevice selectedDevice = VK_NULL_HANDLE;
173 for (
const auto& device : devices) {
174 VkPhysicalDeviceProperties deviceProperties;
175 vkGetPhysicalDeviceProperties(device, &deviceProperties);
177 log(
"Avaiable GPU (%s): %s", deviceProperties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU ?
"DISCRETE" :
"INTEGRATED", deviceProperties.deviceName);
180 bool hasCore13 = deviceProperties.apiVersion >= VK_API_VERSION_1_3;
183 vkEnumerateDeviceExtensionProperties(device,
nullptr, &extCount,
nullptr);
184 std::vector<VkExtensionProperties> availableExtensions(extCount);
185 vkEnumerateDeviceExtensionProperties(device,
nullptr, &extCount, availableExtensions.data());
188 for (
const auto& ext : availableExtensions) {
189 if (strcmp(ext.extensionName, VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME) == 0) {
195 if (!hasCore13 && !hasKHR) {
196 log(
"Skipping GPU %s due to lack of Vulkan 1.3 or KHR dynamic rendering extension", deviceProperties.deviceName);
200 uint32_t formatCount;
201 vkGetPhysicalDeviceSurfaceFormatsKHR(device, m_context.surface, &formatCount,
nullptr);
203 uint32_t presentModeCount;
204 vkGetPhysicalDeviceSurfacePresentModesKHR(device, m_context.surface, &presentModeCount,
nullptr);
206 if (formatCount == 0 || presentModeCount == 0) {
207 log(
"Skipping GPU %s due to lack of formats or present modes", deviceProperties.deviceName);
212 if (deviceProperties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU)
221 uint32_t queueFamilyCount = 0;
222 vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount,
nullptr);
223 std::vector<VkQueueFamilyProperties> queueFamilies(queueFamilyCount);
224 vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, queueFamilies.data());
225 uint32_t graphicsIdx = UINT32_MAX;
226 uint32_t presentIdx = UINT32_MAX;
229 for (
const auto& queueFamily : queueFamilies) {
230 bool hasGraphics = queueFamily.queueFlags & VK_QUEUE_GRAPHICS_BIT;
231 VkBool32 hasPresent =
false;
232 vkGetPhysicalDeviceSurfaceSupportKHR(device, i, m_context.surface, &hasPresent);
234 if (hasGraphics && hasPresent) {
240 if (hasGraphics && graphicsIdx == UINT32_MAX) {
243 if (hasPresent && presentIdx == UINT32_MAX) {
249 if (graphicsIdx != UINT32_MAX && presentIdx != UINT32_MAX)
251 if (score > bestScore)
254 selectedDevice = device;
255 m_context.graphicsQueueFamily = graphicsIdx;
256 m_context.presentQueueFamily = presentIdx;
261 VkPhysicalDeviceProperties deviceProperties;
263 if (selectedDevice != VK_NULL_HANDLE)
265 vkGetPhysicalDeviceProperties(selectedDevice, &deviceProperties);
266 log(
"Selected GPU: %s", deviceProperties.deviceName);
269 deviceProperties.deviceName,
270 deviceProperties.vendorID,
271 deviceProperties.driverVersion
274 m_context.physicalDevice = selectedDevice;
277 if (m_context.physicalDevice == VK_NULL_HANDLE) {
281 if (m_context.graphicsQueueFamily == UINT32_MAX) {
282 throw_error(
"Failed to find graphics queue family - GPU may not support graphics operations");
284 if (m_context.presentQueueFamily == UINT32_MAX) {
285 throw_error(
"Failed to find present queue family - GPU may not support presentation");
288 std::vector<VkDeviceQueueCreateInfo> queueCreateInfos;
289 std::set<uint32_t> uniqueQueueFamilies = {m_context.graphicsQueueFamily, m_context.presentQueueFamily};
291 float queuePriority = 1.0f;
292 for (uint32_t queueFamily : uniqueQueueFamilies) {
293 VkDeviceQueueCreateInfo queueCreateInfo = {};
294 queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
295 queueCreateInfo.queueFamilyIndex = queueFamily;
296 queueCreateInfo.queueCount = 1;
297 queueCreateInfo.pQueuePriorities = &queuePriority;
298 queueCreateInfos.push_back(queueCreateInfo);
301 std::vector<const char*> deviceExtensions = {
302 VK_KHR_SWAPCHAIN_EXTENSION_NAME,
303 VK_EXT_EXTENDED_DYNAMIC_STATE_2_EXTENSION_NAME
306 uint32_t extCount = 0;
307 vkEnumerateDeviceExtensionProperties(m_context.physicalDevice,
nullptr, &extCount,
nullptr);
308 std::vector<VkExtensionProperties> availableExts(extCount);
309 vkEnumerateDeviceExtensionProperties(m_context.physicalDevice,
nullptr, &extCount, availableExts.data());
311 for(
const auto& ext : availableExts) {
312 if(strcmp(ext.extensionName,
"VK_KHR_portability_subset") == 0) {
313 deviceExtensions.push_back(
"VK_KHR_portability_subset");
318 if (apiVersion < VK_API_VERSION_1_3) {
319 deviceExtensions.push_back(VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME);
320 deviceExtensions.push_back(VK_KHR_DEPTH_STENCIL_RESOLVE_EXTENSION_NAME);
321 deviceExtensions.push_back(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME);
324 if (apiVersion < VK_API_VERSION_1_2) {
325 deviceExtensions.push_back(
"VK_EXT_descriptor_indexing");
328 VkPhysicalDeviceFeatures2 deviceFeatures2 = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2 };
329 VkPhysicalDeviceVulkan11Features features11 = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES };
330 VkPhysicalDeviceVulkan12Features features12 = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES };
331 VkPhysicalDeviceDynamicRenderingFeatures dynamicRenderingFeatures = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_FEATURES };
332 VkPhysicalDeviceMultiDrawFeaturesEXT multiDrawFeatures = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTI_DRAW_FEATURES_EXT };
333 VkPhysicalDeviceExtendedDynamicState2FeaturesEXT extendedDynamicState2Features = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_2_FEATURES_EXT };
335 void** tail = &deviceFeatures2.pNext;
338 tail = &features11.pNext;
340 if (apiVersion >= VK_API_VERSION_1_2) {
342 tail = &features12.pNext;
345 *tail = &dynamicRenderingFeatures;
346 tail = &dynamicRenderingFeatures.pNext;
348 *tail = &multiDrawFeatures;
349 tail = &multiDrawFeatures.pNext;
351 *tail = &extendedDynamicState2Features;
352 tail = &extendedDynamicState2Features.pNext;
356 vkGetPhysicalDeviceFeatures2(m_context.physicalDevice, &deviceFeatures2);
358 if (deviceFeatures2.features.samplerAnisotropy) {
359 deviceFeatures2.features.samplerAnisotropy = VK_TRUE;
361 log(LogLevel::WARNING,
"Sampler Anisotropy not supported.");
364 if (deviceFeatures2.features.multiDrawIndirect) {
365 m_context.supportsIndirectDraw =
true;
366 VkPhysicalDeviceProperties properties;
367 vkGetPhysicalDeviceProperties(m_context.physicalDevice, &properties);
368 m_context.maxDrawIndirectCount = properties.limits.maxDrawIndirectCount;
370 m_context.supportsIndirectDraw =
false;
371 deviceFeatures2.features.multiDrawIndirect = VK_FALSE;
374 if (features11.shaderDrawParameters) {
375 features11.shaderDrawParameters = VK_TRUE;
376 m_context.supportsShaderDrawParameters =
true;
378 features11.shaderDrawParameters = VK_FALSE;
379 m_context.supportsShaderDrawParameters =
false;
382 if (apiVersion >= VK_API_VERSION_1_2) {
383 VkPhysicalDeviceDescriptorIndexingProperties indexingProps = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_PROPERTIES };
384 VkPhysicalDeviceProperties2 props2 = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2 };
385 props2.pNext = &indexingProps;
386 vkGetPhysicalDeviceProperties2(m_context.physicalDevice, &props2);
389 uint32_t samplerLimit = indexingProps.maxPerStageDescriptorUpdateAfterBindSamplers;
390 uint32_t imageLimit = indexingProps.maxPerStageDescriptorUpdateAfterBindSampledImages;
392 log(
"Bindless Limits -> Samplers: %u | Images: %u (Req: %u)", samplerLimit, imageLimit, requiredBindlessCount);
394 if (imageLimit < requiredBindlessCount || samplerLimit < requiredBindlessCount) {
395 log(LogLevel::WARNING,
"Device limits too low. Forcing Bindless OFF to prevent validation errors.");
396 m_context.supportsBindlessTextures =
false;
398 m_context.supportsBindlessTextures =
399 features12.descriptorBindingPartiallyBound &&
400 features12.runtimeDescriptorArray;
403 m_context.supportsBindlessTextures =
false;
406 if (apiVersion >= VK_API_VERSION_1_2) {
407 if (m_context.supportsBindlessTextures) {
408 features12.descriptorBindingPartiallyBound = VK_TRUE;
409 features12.runtimeDescriptorArray = VK_TRUE;
410 features12.shaderSampledImageArrayNonUniformIndexing = VK_TRUE;
411 features12.descriptorBindingSampledImageUpdateAfterBind = VK_TRUE;
412 features12.descriptorBindingVariableDescriptorCount = VK_TRUE;
414 features12.descriptorBindingPartiallyBound = VK_FALSE;
415 features12.runtimeDescriptorArray = VK_FALSE;
416 features12.shaderSampledImageArrayNonUniformIndexing = VK_FALSE;
417 features12.descriptorBindingVariableDescriptorCount = VK_FALSE;
419 features12.descriptorBindingSampledImageUpdateAfterBind = VK_FALSE;
420 features12.descriptorBindingStorageImageUpdateAfterBind = VK_FALSE;
422 features12.descriptorBindingUniformBufferUpdateAfterBind = VK_FALSE;
423 features12.descriptorBindingStorageBufferUpdateAfterBind = VK_FALSE;
424 features12.descriptorBindingUniformTexelBufferUpdateAfterBind = VK_FALSE;
425 features12.descriptorBindingStorageTexelBufferUpdateAfterBind = VK_FALSE;
428 if (deviceFeatures2.features.robustBufferAccess) {
429 features12.descriptorBindingUniformBufferUpdateAfterBind = VK_FALSE;
430 features12.descriptorBindingStorageBufferUpdateAfterBind = VK_FALSE;
431 features12.descriptorBindingUniformTexelBufferUpdateAfterBind = VK_FALSE;
432 features12.descriptorBindingStorageTexelBufferUpdateAfterBind = VK_FALSE;
436 if (dynamicRenderingFeatures.dynamicRendering) {
437 dynamicRenderingFeatures.dynamicRendering = VK_TRUE;
439 throw_error(
"Dynamic Rendering not supported by GPU!");
442 if (multiDrawFeatures.multiDraw) {
443 m_context.supportsMultiDraw =
true;
444 multiDrawFeatures.multiDraw = VK_TRUE;
445 deviceExtensions.push_back(VK_EXT_MULTI_DRAW_EXTENSION_NAME);
447 VkPhysicalDeviceMultiDrawPropertiesEXT multiDrawProps{};
448 multiDrawProps.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTI_DRAW_PROPERTIES_EXT;
450 VkPhysicalDeviceProperties2 props2{};
451 props2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
452 props2.pNext = &multiDrawProps;
454 vkGetPhysicalDeviceProperties2(m_context.physicalDevice, &props2);
455 m_context.maxMultiDrawCount = multiDrawProps.maxMultiDrawCount;
457 m_context.supportsMultiDraw =
false;
458 multiDrawFeatures.multiDraw = VK_FALSE;
461 if (extendedDynamicState2Features.extendedDynamicState2) {
462 extendedDynamicState2Features.extendedDynamicState2 = VK_TRUE;
464 extendedDynamicState2Features.extendedDynamicState2 = VK_FALSE;
466 extendedDynamicState2Features.extendedDynamicState2LogicOp =
467 extendedDynamicState2Features.extendedDynamicState2LogicOp ? VK_TRUE : VK_FALSE;
468 extendedDynamicState2Features.extendedDynamicState2PatchControlPoints =
469 extendedDynamicState2Features.extendedDynamicState2PatchControlPoints ? VK_TRUE : VK_FALSE;
471 VkDeviceCreateInfo deviceCreateInfo = { VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO };
472 deviceCreateInfo.pNext = &deviceFeatures2;
473 deviceCreateInfo.pEnabledFeatures =
nullptr;
475 deviceCreateInfo.queueCreateInfoCount =
static_cast<uint32_t
>(queueCreateInfos.size());
476 deviceCreateInfo.pQueueCreateInfos = queueCreateInfos.data();
477 deviceCreateInfo.enabledExtensionCount =
static_cast<uint32_t
>(deviceExtensions.size());
478 deviceCreateInfo.ppEnabledExtensionNames = deviceExtensions.data();
480 if (vkCreateDevice(m_context.physicalDevice, &deviceCreateInfo,
nullptr, &m_context.device) != VK_SUCCESS) {
484 uint32_t deviceApiVersion = deviceProperties.apiVersion;
486 uint32_t major = VK_VERSION_MAJOR(deviceApiVersion);
487 uint32_t minor = VK_VERSION_MINOR(deviceApiVersion);
488 uint32_t patch = VK_VERSION_PATCH(deviceApiVersion);
490 std::stringstream deviceVerSS, reqVerSS;
491 deviceVerSS << major <<
"." << minor <<
"." << patch;
492 reqVerSS << VK_VERSION_MAJOR(apiVersion) <<
"." << VK_VERSION_MINOR(apiVersion);
497 features.
multiDraw = m_context.supportsMultiDraw;
504 log(
" ======= Supported Features =======");
506 log(
"Vulkan Device API version: %u.%u.%u", major, minor, patch);
507 log(
"Vulkan Requested API version: %u.%u", VK_VERSION_MAJOR(apiVersion), VK_VERSION_MINOR(apiVersion));
508 log(
"supportsMultiDraw: %s", m_context.supportsMultiDraw ?
"true" :
"false");
509 log(
"supportsIndirectDraw: %s", m_context.supportsIndirectDraw ?
"true" :
"false");
510 log(
"supportsBindlessTextures: %s", m_context.supportsBindlessTextures ?
"true" :
"false");
511 log(
"supportsShaderDrawParameters: %s", m_context.supportsShaderDrawParameters ?
"true" :
"false");
514 log(
" ==================================");
516 volkLoadDevice(m_context.device);
518 if (apiVersion < VK_API_VERSION_1_3) {
519 if (!vkCmdBeginRendering) {
520 vkCmdBeginRendering =
reinterpret_cast<PFN_vkCmdBeginRendering
>(vkGetDeviceProcAddr(m_context.device,
"vkCmdBeginRenderingKHR"));
522 if (!vkCmdEndRendering) {
523 vkCmdEndRendering =
reinterpret_cast<PFN_vkCmdEndRendering
>(vkGetDeviceProcAddr(m_context.device,
"vkCmdEndRenderingKHR"));
525 if (!vkCmdPipelineBarrier2) {
526 vkCmdPipelineBarrier2 =
reinterpret_cast<PFN_vkCmdPipelineBarrier2
>(vkGetDeviceProcAddr(m_context.device,
"vkCmdPipelineBarrier2KHR"));
530 vkGetDeviceQueue(m_context.device, m_context.graphicsQueueFamily, 0, &m_context.graphicsQueue);
531 vkGetDeviceQueue(m_context.device, m_context.presentQueueFamily, 0, &m_context.presentQueue);
533 if (m_context.graphicsQueue == VK_NULL_HANDLE) {
534 throw_error(
"Failed to retrieve graphics queue - device creation corrupted or driver issue");
536 if (m_context.presentQueue == VK_NULL_HANDLE) {
537 throw_error(
"Failed to retrieve present queue - device creation corrupted or driver issue");
540 VmaVulkanFunctions vmaFuncs = {};
541 vmaFuncs.vkGetInstanceProcAddr = vkGetInstanceProcAddr;
542 vmaFuncs.vkGetDeviceProcAddr = vkGetDeviceProcAddr;
543 vmaFuncs.vkGetPhysicalDeviceProperties = vkGetPhysicalDeviceProperties;
544 vmaFuncs.vkGetPhysicalDeviceMemoryProperties = vkGetPhysicalDeviceMemoryProperties;
545 vmaFuncs.vkAllocateMemory = vkAllocateMemory;
546 vmaFuncs.vkFreeMemory = vkFreeMemory;
547 vmaFuncs.vkMapMemory = vkMapMemory;
548 vmaFuncs.vkUnmapMemory = vkUnmapMemory;
549 vmaFuncs.vkFlushMappedMemoryRanges = vkFlushMappedMemoryRanges;
550 vmaFuncs.vkInvalidateMappedMemoryRanges = vkInvalidateMappedMemoryRanges;
551 vmaFuncs.vkBindBufferMemory = vkBindBufferMemory;
552 vmaFuncs.vkBindImageMemory = vkBindImageMemory;
553 vmaFuncs.vkGetBufferMemoryRequirements = vkGetBufferMemoryRequirements;
554 vmaFuncs.vkGetImageMemoryRequirements = vkGetImageMemoryRequirements;
555 vmaFuncs.vkCreateBuffer = vkCreateBuffer;
556 vmaFuncs.vkDestroyBuffer = vkDestroyBuffer;
557 vmaFuncs.vkCreateImage = vkCreateImage;
558 vmaFuncs.vkDestroyImage = vkDestroyImage;
559 vmaFuncs.vkCmdCopyBuffer = vkCmdCopyBuffer;
561 VmaAllocatorCreateInfo allocatorInfo = {};
562 allocatorInfo.physicalDevice = m_context.physicalDevice;
563 allocatorInfo.device = m_context.device;
564 allocatorInfo.instance = m_context.instance;
565 allocatorInfo.vulkanApiVersion = apiVersion;
566 allocatorInfo.pVulkanFunctions = &vmaFuncs;
568 if (vmaCreateAllocator(&allocatorInfo, &m_context.allocator) != VK_SUCCESS) {
572 log(
"Initializing Swapchain Manager...");
573 m_p_swapchainManager = std::make_unique<VulkanSwapchainManager>(m_context, m_p_window);
574 m_p_swapchainManager->createSwapchain();
576 log(
"Initializing Resources...");
577 m_p_resources = std::make_unique<VulkanResources>(m_context, m_vfs);
579 log(
"Initializing Mesh Manager...");
580 m_p_meshManager = std::make_unique<MeshManager>(m_context, m_p_resources, m_vfs);
582 log(
"Initializing Pipeline...");
583 m_p_pipeline = std::make_unique<VulkanPipeline>(m_context);
585 VkVertexInputBindingDescription bindingDesc{};
586 bindingDesc.binding = 0;
587 bindingDesc.stride =
sizeof(
Vertex);
588 bindingDesc.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
590 std::vector<VkVertexInputAttributeDescription> attributes(3);
591 attributes[0] = {0, 0, VK_FORMAT_R32G32B32_SFLOAT, offsetof(
Vertex, position)};
592 attributes[1] = {1, 0, VK_FORMAT_R32G32B32_SFLOAT, offsetof(
Vertex, normal)};
593 attributes[2] = {2, 0, VK_FORMAT_R32G32_SFLOAT, offsetof(
Vertex, uv)};
595 std::string opaqueFrag = m_context.supportsBindlessTextures
596 ?
"Engine/shaders/OpaqueFragBindless.spv"
597 :
"Engine/shaders/OpaqueFrag.spv";
599 m_p_pipeline->createGraphicsPipeline(
600 "Engine/shaders/OpaqueVert.spv",
606 log(
"Initializing Masked Pipeline...");
607 m_p_maskPipeline = std::make_unique<VulkanPipeline>(m_context);
609 std::string maskedFrag = m_context.supportsBindlessTextures
610 ?
"Engine/shaders/MaskedFragBindless.spv"
611 :
"Engine/shaders/MaskedFrag.spv";
613 m_p_maskPipeline->createMaskedPipeline(
614 "Engine/shaders/MaskedVert.spv",
620 log(
"Initializing Transparent Pipeline...");
621 m_p_transPipeline = std::make_unique<VulkanPipeline>(m_context);
623 std::string transFrag = m_context.supportsBindlessTextures
624 ?
"Engine/shaders/TransparentFragBindless.spv"
625 :
"Engine/shaders/TransparentFrag.spv";
627 m_p_transPipeline->createTransparentPipeline(
628 "Engine/shaders/TransparentVert.spv",
634 log(
"Initializing Billboard and Particle Pipelines...");
635 m_p_billboardMaskedPipeline = std::make_unique<VulkanPipeline>(m_context);
636 m_p_billboardTransPipeline = std::make_unique<VulkanPipeline>(m_context);
637 m_p_particleMaskedPipeline = std::make_unique<VulkanPipeline>(m_context);
638 m_p_particleTransPipeline = std::make_unique<VulkanPipeline>(m_context);
640 std::string spriteOpaqueFrag = m_context.supportsBindlessTextures ?
"Engine/shaders/SpriteOpaqueFragBindless.spv" :
"Engine/shaders/SpriteOpaqueFrag.spv";
641 std::string spriteTransFrag = m_context.supportsBindlessTextures ?
"Engine/shaders/SpriteTransFragBindless.spv" :
"Engine/shaders/SpriteTransFrag.spv";
643 m_p_billboardMaskedPipeline->createSpritePipeline(
"Engine/shaders/BillboardVert.spv", spriteOpaqueFrag,
false,
false);
644 m_p_billboardTransPipeline->createSpritePipeline(
"Engine/shaders/BillboardVert.spv", spriteTransFrag,
true,
false);
645 m_p_particleMaskedPipeline->createSpritePipeline(
"Engine/shaders/ParticleVert.spv", spriteOpaqueFrag,
false,
true);
646 m_p_particleTransPipeline->createSpritePipeline(
"Engine/shaders/ParticleVert.spv", spriteTransFrag,
true,
true);
648 log(
"Initializing UI Pipeline...");
649 m_p_uiPipeline = std::make_unique<VulkanPipeline>(m_context);
651 VkVertexInputBindingDescription uiBinding{};
652 uiBinding.binding = 0;
653 uiBinding.stride =
sizeof(
UIVertex);
654 uiBinding.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
656 std::vector<VkVertexInputAttributeDescription> uiAttrs(4);
657 uiAttrs[0] = {0, 0, VK_FORMAT_R32G32_SFLOAT, offsetof(
UIVertex, position)};
658 uiAttrs[1] = {1, 0, VK_FORMAT_R32G32_SFLOAT, offsetof(
UIVertex, uv)};
659 uiAttrs[2] = {2, 0, VK_FORMAT_R32G32B32A32_SFLOAT,offsetof(
UIVertex, color)};
660 uiAttrs[3] = {3, 0, VK_FORMAT_R32_SFLOAT, offsetof(
UIVertex, texIndex)};
663 std::string uiFrag = m_context.supportsBindlessTextures
664 ?
"Engine/shaders/UiFragBindless.spv"
665 :
"Engine/shaders/UiFrag.spv";
667 m_p_uiPipeline->createUIPipeline(
668 "Engine/shaders/UiVert.spv",
675 log(
"Initializing Composite Pipeline...");
676 m_p_compositePipeline = std::make_unique<VulkanPipeline>(m_context);
677 m_p_compositePipeline->createFullscreenPipeline(
678 "Engine/shaders/CompositeVert.spv",
679 "Engine/shaders/CompositeFrag.spv"
682 log(
"Initializing Fullscreen Pipeline...");
683 m_p_fullscreenPipeline = std::make_unique<VulkanPipeline>(m_context);
685 VkVertexInputBindingDescription emptyBinding{};
686 std::vector<VkVertexInputAttributeDescription> emptyAttrs;
688 m_p_fullscreenPipeline->createFullscreenPipeline(
689 "Engine/shaders/ScreenVert.spv",
690 "Engine/shaders/ScreenFrag.spv"
694 log(
"Initializing Physics Debug...");
695 m_p_physicsDebug = std::make_unique<VulkanPhysicsDebug>();
697 m_p_debugPipeline = std::make_unique<VulkanPipeline>(m_context);
698 m_p_debugPipeline->createDebugPipeline(
"Engine/shaders/DebugVert.spv",
"Engine/shaders/DebugFrag.spv");
701 log(
"Initializing Renderer...");
702 m_p_renderer = std::make_unique<Renderer>(
708 m_p_billboardTransPipeline,
709 m_p_billboardMaskedPipeline,
710 m_p_particleTransPipeline,
711 m_p_particleMaskedPipeline,
713 m_p_fullscreenPipeline,
714 m_p_compositePipeline,
715 m_p_swapchainManager,
720 m_p_renderer->setDebugPipeline(&m_p_debugPipeline);
723 log(
"Vulkan interface initialized successfully");
725 }
catch (
const std::exception& e) {