31#include "VulkanRenderer.hpp"
32#include "VulkanWindow.hpp"
33#include "VulkanBuffer.hpp"
34#include "VulkanUtilities.hpp"
36#include "aeongames/Mesh.hpp"
37#include "aeongames/Pipeline.hpp"
38#include "aeongames/Material.hpp"
39#include "aeongames/Texture.hpp"
40#include "aeongames/Utilities.hpp"
41#include "aeongames/MemoryPool.hpp"
42#include "SPIR-V/CompilerLinker.hpp"
50 SetupLayersAndExtensions();
64 InitializeCommandPools();
74 VulkanRenderer::~VulkanRenderer()
76 vkQueueWaitIdle ( mVkQueue );
78 mTextureStore.clear();
79 mMaterialStore.clear();
80 mPipelineStore.clear();
82 for (
auto& i : mVkDescriptorSetLayouts )
84 vkDestroyDescriptorSetLayout ( mVkDevice, std::get<1> ( i ),
nullptr );
86 mVkDescriptorSetLayouts.clear();
87 FinalizeCommandPools();
110 return mVkPhysicalDevice;
115 return mVkPhysicalDeviceProperties;
120 return mVkPhysicalDeviceMemoryProperties;
125 auto it = mWindowStore.begin();
126 if ( it != mWindowStore.end() )
128 return it->second.GetRenderPass();
130 std::cout <<
LogLevel::Error << __FUNCTION__ <<
" No RenderPass found!" << std::endl;
131 return VK_NULL_HANDLE;
136 return mQueueFamilyIndex;
141 for ( uint32_t i = 0; i < mVkPhysicalDeviceMemoryProperties.memoryTypeCount; ++i )
143 if ( ( typeFilter & ( 1 << i ) ) && ( mVkPhysicalDeviceMemoryProperties.memoryTypes[i].propertyFlags & properties ) == properties )
148 return std::numeric_limits<uint32_t>::max();
151#if defined (VK_USE_PLATFORM_XLIB_KHR)
152 Display* VulkanRenderer::GetDisplay()
const
160 for ( uint32_t i = 0; i < mVkPhysicalDeviceMemoryProperties.memoryTypeCount; ++i )
162 if ( ( mVkPhysicalDeviceMemoryProperties.memoryTypes[i].propertyFlags &
163 ( aVkMemoryPropertyFlags ) ) == ( aVkMemoryPropertyFlags ) )
168 return std::numeric_limits<uint32_t>::max();
171 void VulkanRenderer::LoadFunctions()
173 assert ( mVkInstance &&
"mVkInstance is a nullptr." );
174 if ( !mFunctionsLoaded && mVkInstance )
177 if ( ( vkCreateDebugUtilsMessengerEXT =
reinterpret_cast<PFN_vkCreateDebugUtilsMessengerEXT
> ( vkGetInstanceProcAddr ( mVkInstance,
"vkCreateDebugUtilsMessengerEXT" ) ) ) ==
nullptr )
179 std::cout <<
LogLevel::Error <<
"vkGetInstanceProcAddr failed to load vkCreateDebugUtilsMessengerEXT" << std::endl;
180 throw std::runtime_error (
"vkGetInstanceProcAddr failed to load vkCreateDebugUtilsMessengerEXT" );
182 if ( ( vkDestroyDebugUtilsMessengerEXT =
reinterpret_cast<PFN_vkDestroyDebugUtilsMessengerEXT
> ( vkGetInstanceProcAddr ( mVkInstance,
"vkDestroyDebugUtilsMessengerEXT" ) ) ) ==
nullptr )
184 std::cout <<
LogLevel::Error <<
"vkGetInstanceProcAddr failed to load vkDestroyDebugUtilsMessengerEXT" << std::endl;
185 throw std::runtime_error (
"vkGetInstanceProcAddr failed to load vkDestroyDebugUtilsMessengerEXT" );
187 mFunctionsLoaded =
true;
192 void VulkanRenderer::SetupDebug()
194 mInstanceExtensionNames.emplace_back ( VK_EXT_DEBUG_UTILS_EXTENSION_NAME );
195 mInstanceExtensionNames.emplace_back ( VK_EXT_DEBUG_REPORT_EXTENSION_NAME );
196 mInstanceLayerNames.emplace_back (
"VK_LAYER_KHRONOS_validation" );
199 void VulkanRenderer::InitializeDebug()
201 VkDebugUtilsMessengerCreateInfoEXT debug_utils_messenger_create_info_ext
203 VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT,
206 VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT |
207 VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT |
208 VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT |
209 VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT,
210 VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT |
211 VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT |
212 VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT,
217 if ( VkResult result = vkCreateDebugUtilsMessengerEXT ( mVkInstance, &debug_utils_messenger_create_info_ext,
nullptr, &mVkDebugUtilsMessengerEXT ) )
219 std::ostringstream stream;
220 stream <<
"Could not create Debug Utils Messenger. error code: ( " <<
GetVulkanResultString ( result ) <<
" )";
221 std::string error_string = stream.str();
223 throw std::runtime_error ( error_string.c_str() );
227 void VulkanRenderer::SetupLayersAndExtensions()
229 mInstanceExtensionNames.push_back ( VK_KHR_SURFACE_EXTENSION_NAME );
230#ifdef VK_USE_PLATFORM_WIN32_KHR
231 mInstanceExtensionNames.push_back ( VK_KHR_WIN32_SURFACE_EXTENSION_NAME );
232 mDeviceExtensionNames.push_back ( VK_EXT_PRIMITIVE_TOPOLOGY_LIST_RESTART_EXTENSION_NAME );
233#elif defined (VK_USE_PLATFORM_METAL_EXT)
234 mInstanceExtensionNames.push_back ( VK_EXT_METAL_SURFACE_EXTENSION_NAME );
235 mInstanceExtensionNames.push_back ( VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME );
236 mInstanceExtensionNames.push_back ( VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME );
237 mDeviceExtensionNames.push_back (
"VK_KHR_portability_subset" );
238#elif defined (VK_USE_PLATFORM_XLIB_KHR)
239 mInstanceExtensionNames.push_back ( VK_KHR_XLIB_SURFACE_EXTENSION_NAME );
241 mDeviceExtensionNames.push_back ( VK_KHR_SWAPCHAIN_EXTENSION_NAME );
244 void VulkanRenderer::InitializeInstance()
246 VkInstanceCreateInfo instance_create_info {};
247 VkApplicationInfo application_info {};
249 application_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
250 application_info.apiVersion = VK_API_VERSION_1_3;
251 application_info.applicationVersion = VK_MAKE_VERSION ( 0, 1, 0 );
252 application_info.pApplicationName =
"AeonEngine Vulkan Renderer";
256 uint32_t available_layer_count;
257 vkEnumerateInstanceLayerProperties ( &available_layer_count,
nullptr );
258 std::vector<VkLayerProperties> available_layers ( available_layer_count );
259 vkEnumerateInstanceLayerProperties ( &available_layer_count, available_layers.data() );
260 std::cout <<
LogLevel::Info <<
"VulkanRenderer Available Layers" << std::endl;
261 for (
auto& i : available_layers )
263 std::cout <<
LogLevel::Info <<
" - " << i.layerName <<
": " << i.description << std::endl;
265 uint32_t instance_extension_layer_count;
266 vkEnumerateInstanceExtensionProperties ( i.layerName, &instance_extension_layer_count,
nullptr );
267 std::vector<VkExtensionProperties> instance_extension_layer_list ( instance_extension_layer_count );
268 vkEnumerateInstanceExtensionProperties ( i.layerName, &instance_extension_layer_count, instance_extension_layer_list.data() );
269 for (
auto& j : instance_extension_layer_list )
271 std::cout <<
LogLevel::Info <<
" - " << j.extensionName << std::endl;
276 for (
auto it = mInstanceLayerNames.begin(); it != mInstanceLayerNames.end(); )
278 bool layer_found =
false;
279 for (
const auto& available_layer : available_layers )
281 if ( strcmp ( *it, available_layer.layerName ) == 0 )
290 <<
"' is not available." << std::endl;
291 it = mInstanceLayerNames.erase ( it );
303 uint32_t available_extension_count;
304 vkEnumerateInstanceExtensionProperties (
nullptr, &available_extension_count,
nullptr );
305 std::vector<VkExtensionProperties> available_extensions ( available_extension_count );
306 vkEnumerateInstanceExtensionProperties (
nullptr, &available_extension_count, available_extensions.data() );
309 std::vector<VkExtensionProperties> layer_extensions;
310 for (
const char * layer_name : mInstanceLayerNames )
312 uint32_t layer_extension_count;
313 vkEnumerateInstanceExtensionProperties ( layer_name, &layer_extension_count,
nullptr );
314 std::vector<VkExtensionProperties> layer_ext_props ( layer_extension_count );
315 vkEnumerateInstanceExtensionProperties ( layer_name, &layer_extension_count, layer_ext_props.data() );
316 layer_extensions.insert ( layer_extensions.end(), layer_ext_props.begin(), layer_ext_props.end() );
319 std::cout <<
LogLevel::Info <<
"VulkanRenderer Available Instance Extensions" << std::endl;
320 for (
const auto& extension : available_extensions )
322 std::cout <<
LogLevel::Info <<
" - " << extension.extensionName <<
" (version " << extension.specVersion <<
")" << std::endl;
325 for (
auto it = mInstanceExtensionNames.begin(); it != mInstanceExtensionNames.end(); )
327 bool extension_found =
false;
330 for (
const auto& available_extension : available_extensions )
332 if ( strcmp ( *it, available_extension.extensionName ) == 0 )
334 extension_found =
true;
340 if ( !extension_found )
342 for (
const auto& layer_extension : layer_extensions )
344 if ( strcmp ( *it, layer_extension.extensionName ) == 0 )
346 extension_found =
true;
352 if ( !extension_found )
355 <<
"' is not available." << std::endl;
356 it = mInstanceExtensionNames.erase ( it );
365 instance_create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
366 instance_create_info.pApplicationInfo = &application_info;
367 instance_create_info.enabledLayerCount =
static_cast<uint32_t
> ( mInstanceLayerNames.size() );
368 instance_create_info.ppEnabledLayerNames = mInstanceLayerNames.data();
369 instance_create_info.enabledExtensionCount =
static_cast<uint32_t
> ( mInstanceExtensionNames.size() );
370 instance_create_info.ppEnabledExtensionNames = mInstanceExtensionNames.data();
371#ifdef VK_USE_PLATFORM_METAL_EXT
372 instance_create_info.flags = VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR;
374 if ( VkResult result = vkCreateInstance ( &instance_create_info,
nullptr, &mVkInstance ) )
376 std::ostringstream stream;
377 stream <<
"Could not create VulkanRenderer instance. error code: ( " <<
GetVulkanResultString ( result ) <<
" )";
378 std::string error_string = stream.str();
380 throw std::runtime_error ( error_string.c_str() );
384 void VulkanRenderer::InitializeDevice()
388 std::cout <<
LogLevel::Error <<
"mVkInstance is a nullptr." << std::endl;
389 throw std::runtime_error (
"mVkInstance is a nullptr." );
392 uint32_t physical_device_count;
393 vkEnumeratePhysicalDevices ( mVkInstance, &physical_device_count,
nullptr );
395 if ( physical_device_count == 0 )
397 std::cout <<
LogLevel::Error <<
"No VulkanRenderer physical device found" << std::endl;
398 throw std::runtime_error (
"No VulkanRenderer physical device found" );
401 std::vector<VkPhysicalDevice> physical_device_list ( physical_device_count );
402 vkEnumeratePhysicalDevices ( mVkInstance, &physical_device_count, physical_device_list.data() );
404 mVkPhysicalDevice = physical_device_list[0];
405 vkGetPhysicalDeviceProperties ( mVkPhysicalDevice, &mVkPhysicalDeviceProperties );
406 std::cout <<
LogLevel::Debug <<
"minUniformBufferOffsetAlignment: " << mVkPhysicalDeviceProperties.limits.minUniformBufferOffsetAlignment << std::endl;
407 std::cout <<
LogLevel::Debug <<
"maxUniformBufferRange: " << mVkPhysicalDeviceProperties.limits.maxUniformBufferRange << std::endl;
408 vkGetPhysicalDeviceMemoryProperties ( mVkPhysicalDevice, &mVkPhysicalDeviceMemoryProperties );
411 uint32_t family_properties_count;
412 vkGetPhysicalDeviceQueueFamilyProperties ( mVkPhysicalDevice, &family_properties_count,
nullptr );
413 if ( family_properties_count == 0 )
415 std::cout <<
LogLevel::Error <<
"VulkanRenderer physical device has no queue family properties." << std::endl;
416 throw std::runtime_error (
"VulkanRenderer physical device has no queue family properties." );
418 std::vector<VkQueueFamilyProperties> family_properties_list ( family_properties_count );
419 vkGetPhysicalDeviceQueueFamilyProperties ( mVkPhysicalDevice, &family_properties_count, family_properties_list.data() );
420 bool graphics_queue_family_found =
false;
421 for (
auto family_property = family_properties_list.begin();
422 family_property != family_properties_list.end();
425 if ( family_property->queueFlags & VK_QUEUE_GRAPHICS_BIT )
427 graphics_queue_family_found =
true;
429 static_cast<uint32_t
> ( family_property - family_properties_list.begin() );
433 if ( !graphics_queue_family_found )
435 std::cout <<
LogLevel::Error <<
"No graphics queue family found." << std::endl;
436 throw std::runtime_error (
"No graphics queue family found." );
441 uint32_t extension_property_count;
442 vkEnumerateDeviceExtensionProperties ( mVkPhysicalDevice,
nullptr, &extension_property_count,
nullptr );
443 std::vector<VkExtensionProperties> extension_properties ( extension_property_count );
444 vkEnumerateDeviceExtensionProperties ( mVkPhysicalDevice,
nullptr, &extension_property_count, extension_properties.data() );
445 std::cout <<
LogLevel::Info <<
"Vulkan Renderer Available Device Extensions" << std::endl;
446 for (
auto& i : extension_properties )
448 std::cout <<
LogLevel::Info <<
" - " << i.extensionName <<
" (version " << i.specVersion <<
")" << std::endl;
450 if ( !strcmp ( i.extensionName, VK_EXT_DEBUG_MARKER_EXTENSION_NAME ) )
452 mDeviceExtensionNames.emplace_back ( VK_EXT_DEBUG_MARKER_EXTENSION_NAME );
458 float queue_priorities[] {1.0f};
459 VkDeviceQueueCreateInfo device_queue_create_info{};
460 device_queue_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
461 device_queue_create_info.pNext =
nullptr;
462 device_queue_create_info.queueCount = 1;
463 device_queue_create_info.queueFamilyIndex = mQueueFamilyIndex;
464 device_queue_create_info.pQueuePriorities = queue_priorities;
466#ifdef VK_USE_PLATFORM_METAL_EXT
468 VkPhysicalDevicePrimitiveTopologyListRestartFeaturesEXT physical_device_primitive_topology_list_restart_features {};
469 physical_device_primitive_topology_list_restart_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIMITIVE_TOPOLOGY_LIST_RESTART_FEATURES_EXT;
470 physical_device_primitive_topology_list_restart_features.pNext =
nullptr;
471 physical_device_primitive_topology_list_restart_features.primitiveTopologyListRestart = VK_TRUE;
472 physical_device_primitive_topology_list_restart_features.primitiveTopologyPatchListRestart = VK_TRUE;
474 VkDeviceCreateInfo device_create_info {};
475 device_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
476#ifdef VK_USE_PLATFORM_METAL_EXT
478 device_create_info.pNext = &physical_device_primitive_topology_list_restart_features;
480 device_create_info.pNext =
nullptr;
482 device_create_info.queueCreateInfoCount = 1;
483 device_create_info.pQueueCreateInfos = &device_queue_create_info;
484 device_create_info.enabledLayerCount =
static_cast<uint32_t
> ( mDeviceLayerNames.size() );
485 device_create_info.ppEnabledLayerNames = mDeviceLayerNames.data();
486 device_create_info.enabledExtensionCount =
static_cast<uint32_t
> ( mDeviceExtensionNames.size() );
487 device_create_info.ppEnabledExtensionNames = mDeviceExtensionNames.data();
488 device_create_info.pEnabledFeatures =
nullptr;
491 if ( VkResult result = vkCreateDevice ( mVkPhysicalDevice, &device_create_info,
nullptr, &mVkDevice ) )
493 std::ostringstream stream;
494 stream <<
"Could not create VulkanRenderer device. error code: ( " <<
GetVulkanResultString ( result ) <<
" )";
496 throw std::runtime_error ( stream.str().c_str() );
498 vkGetDeviceQueue ( mVkDevice, mQueueFamilyIndex, 0, &mVkQueue );
501 void VulkanRenderer::InitializeCommandPools()
503 VkCommandPoolCreateInfo command_pool_create_info{};
504 command_pool_create_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
505 command_pool_create_info.queueFamilyIndex = mQueueFamilyIndex;
506 command_pool_create_info.flags = VK_COMMAND_POOL_CREATE_TRANSIENT_BIT;
507 vkCreateCommandPool ( mVkDevice, &command_pool_create_info,
nullptr, &mVkSingleTimeCommandPool );
510 void VulkanRenderer::FinalizeCommandPools()
512 if ( mVkSingleTimeCommandPool != VK_NULL_HANDLE )
514 vkDestroyCommandPool ( mVkDevice, mVkSingleTimeCommandPool,
nullptr );
515 mVkSingleTimeCommandPool = VK_NULL_HANDLE;
519 void VulkanRenderer::FinalizeDebug()
521 if ( mVkInstance && ( mVkDebugUtilsMessengerEXT != VK_NULL_HANDLE ) )
523 vkDestroyDebugUtilsMessengerEXT ( mVkInstance, mVkDebugUtilsMessengerEXT,
nullptr );
524 mVkDebugUtilsMessengerEXT = VK_NULL_HANDLE;
528 void VulkanRenderer::FinalizeInstance()
530 if ( mVkInstance != VK_NULL_HANDLE )
532 vkDestroyInstance ( mVkInstance,
nullptr );
533 mVkInstance = VK_NULL_HANDLE;
537 void VulkanRenderer::FinalizeDevice()
539 if ( mVkDevice != VK_NULL_HANDLE )
541 if ( VkResult result = vkDeviceWaitIdle ( mVkDevice ) )
545 vkDestroyDevice ( mVkDevice,
nullptr );
546 mVkDevice = VK_NULL_HANDLE;
552 VkCommandBufferAllocateInfo command_buffer_allocate_info{};
553 VkCommandBuffer command_buffer{};
554 VkCommandBufferBeginInfo beginInfo{};
555 command_buffer_allocate_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
556 command_buffer_allocate_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
557 command_buffer_allocate_info.commandPool = mVkSingleTimeCommandPool;
558 command_buffer_allocate_info.commandBufferCount = 1;
559 vkAllocateCommandBuffers ( mVkDevice, &command_buffer_allocate_info, &command_buffer );
560 beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
561 beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
562 vkBeginCommandBuffer ( command_buffer, &beginInfo );
563 return command_buffer;
568 vkEndCommandBuffer ( aVkCommandBuffer );
569 VkSubmitInfo submit_info = {};
570 submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
571 submit_info.commandBufferCount = 1;
572 submit_info.pCommandBuffers = &aVkCommandBuffer;
573 vkQueueSubmit ( mVkQueue, 1, &submit_info, VK_NULL_HANDLE );
574 vkQueueWaitIdle ( mVkQueue );
575 vkFreeCommandBuffers ( mVkDevice, mVkSingleTimeCommandPool, 1, &aVkCommandBuffer );
585 if ( it != mMeshStore.end() )
596 if ( it != mMeshStore.end() )
598 mMeshStore.erase ( it );
605 if ( it == mMeshStore.end() )
610 if ( it != mMeshStore.end() )
622 if ( it == mPipelineStore.end() )
627 if ( it != mPipelineStore.end() )
637 if ( it == mMaterialStore.end() )
643 if ( it != mMaterialStore.end() )
653 if ( it != mPipelineStore.end() )
664 if ( it == mPipelineStore.end() )
668 if ( mBoundPipeline == &it->second )
670 mBoundPipeline =
nullptr;
672 mPipelineStore.erase ( it );
679 if ( it != mMaterialStore.end() )
688 if ( mTextureStore.find ( texture->
GetConsecutiveId() ) == mTextureStore.end() )
699 if ( it == mMaterialStore.end() )
707 if ( mTextureStore.find ( texture->
GetConsecutiveId() ) != mTextureStore.end() )
712 mMaterialStore.erase ( it );
718 if ( it != mTextureStore.end() )
729 if ( it == mTextureStore.end() )
733 mTextureStore.erase ( it );
739 if ( it == mTextureStore.end() )
741 std::ostringstream stream;
742 stream <<
"Texture Not Found at: ( " << __FUNCTION__ <<
" )";
743 std::string error_string = stream.str();
745 throw std::runtime_error ( error_string.c_str() );
747 return &it->second.GetDescriptorImageInfo();
754 crc32i (
reinterpret_cast<const char*
> ( &aDescriptorSetLayoutCreateInfo.bindingCount ), sizeof ( uint32_t ),
755 crc32i (
reinterpret_cast<const char*
> ( &aDescriptorSetLayoutCreateInfo.flags ), sizeof ( VkDescriptorSetLayoutCreateFlags ),
756 crc32i (
reinterpret_cast<const char*
> ( &aDescriptorSetLayoutCreateInfo.sType ), sizeof ( VkStructureType ) ) ) )
759 for ( uint32_t i = 0; i < aDescriptorSetLayoutCreateInfo.bindingCount; ++i )
762 crc32i (
reinterpret_cast<const char*
> ( &aDescriptorSetLayoutCreateInfo.pBindings[i].stageFlags ), sizeof ( VkShaderStageFlags ),
763 crc32i (
reinterpret_cast<const char*
> ( &aDescriptorSetLayoutCreateInfo.pBindings[i].descriptorCount ), sizeof ( uint32_t ),
764 crc32i (
reinterpret_cast<const char*
> ( &aDescriptorSetLayoutCreateInfo.pBindings[i].descriptorType ), sizeof ( VkDescriptorType ),
765 crc32i (
reinterpret_cast<const char*
> ( &aDescriptorSetLayoutCreateInfo.pBindings[i].binding ), sizeof ( uint32_t ), key ) ) ) );
768 auto lb = std::lower_bound ( mVkDescriptorSetLayouts.begin(), mVkDescriptorSetLayouts.end(), key,
769 [] (
const std::tuple<size_t, VkDescriptorSetLayout>& a,
size_t b )
771 return std::get<0> ( a ) < b;
774 if ( lb != mVkDescriptorSetLayouts.end() && std::get<0> ( *lb ) == key )
776 return std::get<1> ( *lb );
778 VkDescriptorSetLayout descriptor_set_layout;
779 if ( VkResult result = vkCreateDescriptorSetLayout ( mVkDevice, &aDescriptorSetLayoutCreateInfo,
nullptr, &descriptor_set_layout ) )
781 std::ostringstream stream;
784 throw std::runtime_error ( stream.str().c_str() );
786 lb = mVkDescriptorSetLayouts.insert ( lb, { {key}, {descriptor_set_layout} } );
787 return std::get<1> ( *lb );
790 const VkDescriptorSetLayout& VulkanRenderer::GetSamplerDescriptorSetLayout (
size_t aSamplerCount )
const
792 auto lb = std::lower_bound ( mVkDescriptorSetLayouts.begin(), mVkDescriptorSetLayouts.end(), aSamplerCount,
793 [] (
const std::tuple<size_t, VkDescriptorSetLayout>&a,
size_t b )
795 return std::get<0> ( a ) < b;
797 if ( lb != mVkDescriptorSetLayouts.end() && std::get<0> ( *lb ) == aSamplerCount )
799 return std::get<1> ( *lb );
803 std::vector<VkDescriptorSetLayoutBinding> descriptor_set_layout_bindings;
804 descriptor_set_layout_bindings.resize ( aSamplerCount );
805 for ( uint32_t i = 0; i < aSamplerCount; ++i )
807 descriptor_set_layout_bindings[i].binding = i;
808 descriptor_set_layout_bindings[i].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
810 descriptor_set_layout_bindings[i].descriptorCount = 1;
811 descriptor_set_layout_bindings[i].stageFlags = VK_SHADER_STAGE_ALL;
812 descriptor_set_layout_bindings[i].pImmutableSamplers =
nullptr;
815 VkDescriptorSetLayoutCreateInfo descriptor_set_layout_create_info {};
816 descriptor_set_layout_create_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
817 descriptor_set_layout_create_info.pNext =
nullptr;
818 descriptor_set_layout_create_info.flags = 0;
819 descriptor_set_layout_create_info.bindingCount =
static_cast<uint32_t
> ( descriptor_set_layout_bindings.size() );
820 descriptor_set_layout_create_info.pBindings = descriptor_set_layout_bindings.data();
821 lb = mVkDescriptorSetLayouts.insert ( lb, {{aSamplerCount}, {VK_NULL_HANDLE}} );
822 if ( VkResult result = vkCreateDescriptorSetLayout ( mVkDevice, &descriptor_set_layout_create_info,
nullptr,
823 &std::get<1> ( *lb ) ) )
825 std::ostringstream stream;
827 throw std::runtime_error ( stream.str().c_str() );
829 return std::get<1> ( *lb );
831 std::cout <<
LogLevel::Error <<
"Sampler Count must be > 0" << std::endl;
832 throw std::runtime_error (
"Sampler Count must be > 0" );
835 void VulkanRenderer::InitializeDescriptorSetLayout ( VkDescriptorSetLayout& aVkDescriptorSetLayout, VkDescriptorType aVkDescriptorType )
837 VkDescriptorSetLayoutBinding descriptor_set_layout_binding;
838 descriptor_set_layout_binding.binding = 0;
839 descriptor_set_layout_binding.descriptorType = aVkDescriptorType;
841 descriptor_set_layout_binding.descriptorCount = 1;
842 descriptor_set_layout_binding.stageFlags = VK_SHADER_STAGE_ALL;
843 descriptor_set_layout_binding.pImmutableSamplers =
nullptr;
845 VkDescriptorSetLayoutCreateInfo descriptor_set_layout_create_info{};
846 descriptor_set_layout_create_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
847 descriptor_set_layout_create_info.pNext =
nullptr;
848 descriptor_set_layout_create_info.flags = 0;
849 descriptor_set_layout_create_info.bindingCount = 1;
850 descriptor_set_layout_create_info.pBindings = &descriptor_set_layout_binding;
851 if ( VkResult result = vkCreateDescriptorSetLayout ( mVkDevice, &descriptor_set_layout_create_info,
nullptr, &aVkDescriptorSetLayout ) )
853 std::ostringstream stream;
856 throw std::runtime_error ( stream.str().c_str() );
860 void VulkanRenderer::FinalizeDescriptorSetLayout ( VkDescriptorSetLayout& aVkDescriptorSetLayout )
862 if ( aVkDescriptorSetLayout != VK_NULL_HANDLE )
864 vkDestroyDescriptorSetLayout ( mVkDevice, aVkDescriptorSetLayout,
nullptr );
865 aVkDescriptorSetLayout = VK_NULL_HANDLE;
871 auto it = mWindowStore.find ( aWindowId );
872 if ( it != mWindowStore.end() )
874 std::cout <<
LogLevel::Warning <<
" Window " << aWindowId <<
" Already Loaded at: " << __FUNCTION__ << std::endl;
877 mWindowStore.emplace ( aWindowId,
VulkanWindow{*
this, aWindowId} );
881 auto it = mWindowStore.find ( aWindowId );
882 if ( it == mWindowStore.end() )
886 mWindowStore.erase ( it );
891 auto it = mWindowStore.find ( aWindowId );
892 if ( it == mWindowStore.end() )
896 it->second.SetProjectionMatrix ( aMatrix );
901 auto it = mWindowStore.find ( aWindowId );
902 if ( it == mWindowStore.end() )
906 it->second.SetViewMatrix ( aMatrix );
911 auto it = mWindowStore.find ( aWindowId );
912 if ( it == mWindowStore.end() )
916 it->second.ResizeViewport ( aX, aY, aWidth, aHeight );
921 auto it = mWindowStore.find ( aWindowId );
922 if ( it == mWindowStore.end() )
926 it->second.BeginRender();
930 auto it = mWindowStore.find ( aWindowId );
931 if ( it == mWindowStore.end() )
935 it->second.EndRender();
944 uint32_t aVertexStart,
945 uint32_t aVertexCount,
946 uint32_t aInstanceCount,
947 uint32_t aFirstInstance )
const
949 auto it = mWindowStore.find ( aWindowId );
950 if ( it == mWindowStore.end() )
954 it->second.Render ( aModelMatrix, aMesh, aPipeline, aMaterial, aSkeleton, aTopology, aVertexStart, aVertexCount, aInstanceCount, aFirstInstance );
959 auto it = mWindowStore.find ( aWindowId );
960 if ( it == mWindowStore.end() )
963 throw std::runtime_error (
"Unknown Window Id." );
965 return it->second.GetFrustum();
970 auto it = mWindowStore.find ( aWindowId );
971 if ( it == mWindowStore.end() )
974 throw std::runtime_error (
"Unknown Window Id." );
976 return it->second.AllocateSingleFrameUniformMemory ( aSize );
981 auto it = mWindowStore.find ( aWindowId );
982 if ( it == mWindowStore.end() )
Defines log severity levels and stream output for the AeonGames engine.
Provides access to a region within a memory pool buffer.
View frustum defined by six clipping planes, extracted from a projection (or view-projection) matrix.
Represents a surface material with uniform properties and texture samplers.
DLL const std::vector< std::tuple< uint32_t, ResourceId > > & GetSamplers() const
Get all sampler bindings.
4 by 4 matrix in colum mayor order.
Represents a polygon mesh with vertex attributes and index data.
DLL uint32_t GetVertexCount() const
Get the total number of vertices.
Rendering pipeline resource.
DLL size_t GetConsecutiveId() const
Get the Consecutive Id for the resource object.
Represents a 2D texture image resource.
Vulkan material binding handler for descriptor sets and uniforms.
Vulkan mesh wrapper managing vertex and index buffer resources.
Vulkan graphics pipeline with descriptor set and push constant reflection.
uint32_t GetQueueFamilyIndex() const
Get the queue family index used for graphics operations.
void UnloadMesh(const Mesh &aMesh) final
Unloads mesh data from GPU memory.
const VkDescriptorSetLayout & GetDescriptorSetLayout(const VkDescriptorSetLayoutCreateInfo &aDescriptorSetLayoutCreateInfo) const
Get or create a descriptor set layout matching the given create info.
void UnloadPipeline(const Pipeline &aPipeline) final
Unloads a rendering pipeline from the renderer.
const VkPhysicalDevice & GetPhysicalDevice() const
Get the physical device handle.
void LoadMesh(const Mesh &aMesh) final
Loads mesh data into GPU memory.
const VkInstance & GetInstance() const
Get the Vulkan instance handle.
void BeginRender(void *aWindowId) final
Begins a render pass for the given window surface.
const VulkanMesh * GetVulkanMesh(const Mesh &aMesh)
Get the cached VulkanMesh for a Mesh resource.
BufferAccessor AllocateSingleFrameUniformMemory(void *aWindowId, size_t aSize) final
Allocates uniform buffer memory that is valid for a single frame.
const VulkanMaterial * GetVulkanMaterial(const Material &aMaterial)
Get the cached VulkanMaterial for a Material resource.
const VkPhysicalDeviceMemoryProperties & GetPhysicalDeviceMemoryProperties() const
Get the physical device memory properties.
VkCommandBuffer BeginSingleTimeCommands() const
Begin recording a single-use command buffer.
VulkanRenderer(void *aWindow)
Construct from a native window handle.
void LoadPipeline(const Pipeline &aPipeline) final
Loads a rendering pipeline (shaders and state) into the renderer.
void SetClearColor(void *aWindowId, float R, float G, float B, float A) final
Sets the color to be used to clear the window background.
void AttachWindow(void *aWindowId) final
Attach a Window as a rendering surface.
const VkQueue & GetQueue() const
Get the graphics queue handle.
void ResizeViewport(void *aWindowId, int32_t aX, int32_t aY, uint32_t aWidth, uint32_t aHeight) final
Resizes the specific window surface's viewport.
void LoadTexture(const Texture &aTexture) final
Loads a texture into GPU memory.
void LoadMaterial(const Material &aMaterial) final
Loads material data into the renderer.
const VulkanPipeline * GetVulkanPipeline(const Pipeline &aPipeline)
Get the cached VulkanPipeline for a Pipeline resource.
uint32_t FindMemoryTypeIndex(uint32_t typeFilter, VkMemoryPropertyFlags properties) const
Find a memory type index matching both a type filter and property flags.
void SetViewMatrix(void *aWindowId, const Matrix4x4 &aMatrix) final
Sets the view matrix for a specific window surface.
void EndSingleTimeCommands(VkCommandBuffer commandBuffer) const
Submit and free a single-use command buffer.
void Render(void *aWindowId, const Matrix4x4 &aModelMatrix, const Mesh &aMesh, const Pipeline &aPipeline, const Material *aMaterial=nullptr, const BufferAccessor *aSkeleton=nullptr, Topology aTopology=Topology::TRIANGLE_LIST, uint32_t aVertexStart=0, uint32_t aVertexCount=0xffffffff, uint32_t aInstanceCount=1, uint32_t aFirstInstance=0) const final
Issues a draw call for a mesh with the given pipeline and optional material.
const VkPhysicalDeviceProperties & GetPhysicalDeviceProperties() const
Get the physical device properties.
const VkDescriptorImageInfo * GetTextureDescriptorImageInfo(const Texture &aTexture) const
Get the descriptor image info for a loaded texture.
void DetachWindow(void *aWindowId) final
Detach a Window as a rendering surface.
VkRenderPass GetRenderPass() const
Get the common Vulkan render pass.
void EndRender(void *aWindowId) final
Ends the current render pass for the given window surface.
const Frustum & GetFrustum(void *aWindowId) const final
Returns the view frustum for the given window surface.
void SetProjectionMatrix(void *aWindowId, const Matrix4x4 &aMatrix) final
Sets the projection matrix for a specific window surface.
uint32_t GetMemoryTypeIndex(VkMemoryPropertyFlags aVkMemoryPropertyFlags) const
Get a memory type index matching the requested property flags.
void UnloadTexture(const Texture &aTexture) final
Unloads a texture from GPU memory.
const VkDevice & GetDevice() const
Get the logical device handle.
void UnloadMaterial(const Material &aMaterial) final
Unloads material data from the renderer.
Vulkan texture resource wrapper with image and descriptor management.
Vulkan per-window swapchain, render pass, and rendering state.
<- This is here just for the literals
VKAPI_ATTR VkBool32 VKAPI_CALL DebugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT aMessageSeverity, VkDebugUtilsMessageTypeFlagsEXT aMessageTypes, const VkDebugUtilsMessengerCallbackDataEXT *aCallbackData, void *aUserData)
Vulkan debug messenger callback.
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.
const char * GetVulkanResultString(VkResult aResult)
Convert a VkResult code to a human-readable string.
Topology
Primitive topology types for rendering.
@ Warning
Potential issues that may need attention.
@ Info
General informational messages.
@ Debug
Detailed diagnostic information.