From c4f65d65993e4ee2acd6e58862d004c021e7098a Mon Sep 17 00:00:00 2001 From: Ben Kyd Date: Sat, 4 Nov 2023 18:58:58 +0000 Subject: [PATCH] device suitability is in a better place now --- CMakeLists.txt | 1 + src/graphics.hpp | 18 +- src/graphics/enumeratescheme.hpp | 150 +++++++++ src/graphics/errorhandling.hpp | 203 ++++++++++++ src/graphics/vulkanextensionloader.hpp | 425 +++++++++++++++++++++++++ src/graphics/vulkanintrospection.hpp | 274 ++++++++++++++++ src/inferno.cpp | 197 ++++++------ src/window.cpp | 164 ++++++---- src/window.hpp | 23 +- 9 files changed, 1298 insertions(+), 157 deletions(-) create mode 100644 src/graphics/enumeratescheme.hpp create mode 100644 src/graphics/errorhandling.hpp create mode 100644 src/graphics/vulkanextensionloader.hpp create mode 100644 src/graphics/vulkanintrospection.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 9af64d8..0836f67 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -66,6 +66,7 @@ else() target_link_libraries(inferno PRIVATE ${GLFW3_LIBRARIES} Vulkan::Vulkan + libvulkan.so OpenMP::OpenMP_CXX ) endif() diff --git a/src/graphics.hpp b/src/graphics.hpp index d8cc5a6..15fa623 100644 --- a/src/graphics.hpp +++ b/src/graphics.hpp @@ -3,13 +3,25 @@ // easy include for graphics shit // Include GLFW and ImGUI +#ifdef _WIN32 +#define VK_USE_PLATFORM_WIN32_KHR +#define GLFW_EXPOSE_NATIVE_WIN32 +#include +#else +#define VK_USE_PLATFORM_XLIB_KHR +#define GLFW_EXPOSE_NATIVE_X11 +#include +#endif + #define GLFW_INCLUDE_VULKAN #include +#include +#include #include "imgui/imgui.h" -#include "imgui/imgui_internal.h" -#include "imgui/imgui_impl_vulkan.h" #include "imgui/imgui_impl_glfw.h" +#include "imgui/imgui_impl_vulkan.h" +#include "imgui/imgui_internal.h" // glm #define GLM_FORCE_SWIZZLE @@ -19,7 +31,7 @@ #include namespace inferno { namespace graphics::rays { -class Ray; + class Ray; } using RayField = std::vector; } diff --git a/src/graphics/enumeratescheme.hpp b/src/graphics/enumeratescheme.hpp new file mode 100644 index 0000000..a1a975b --- /dev/null +++ b/src/graphics/enumeratescheme.hpp @@ -0,0 +1,150 @@ +// Scheme for the various vkGet* and vkEnumerate* commands +// +// Following the DRY principle, this implements getting a vector of enumerants +// from the similar enumeration commands that return VK_INCOMPELTE. + +#pragma once + +#include +#include +#include + +#include + +#include "errorhandling.hpp" + +// the enumeration scheme +// takes function VkResult cmd( uint32_t count, Element* pArray ) and Vulkan command name (for debugging purposes) +// returns vector which contains the enumerants, or throws +template< typename Element, typename Cmd > +std::vector enumerateScheme( Cmd cmd, const char* cmdName ){ + std::vector enumerants; + + VkResult errorCode; + uint32_t enumerantsCount; + + // repeat until complete array is returned, or error + do{ + errorCode = cmd( &enumerantsCount, nullptr ); RESULT_HANDLER( errorCode, cmdName ); // get current array size + + enumerants.resize( enumerantsCount ); + errorCode = cmd( &enumerantsCount, enumerants.data() ); // get current array up to enumerantsCount + } while( errorCode == VK_INCOMPLETE ); + + RESULT_HANDLER( errorCode, cmdName ); + + enumerants.resize( enumerantsCount ); // shrink in case of enumerantsCount1 > enumerantsCount2 + enumerants.shrink_to_fit(); // unlikely the vector will grow from this point on anyway + + return enumerants; +} + + +// Adapters for specific Vulkan commands +/////////////////////////////////////////////// + +template< typename Element, typename... Ts, typename = std::enable_if_t::value> > +std::vector enumerate( Ts... ); + +// Tag will be VkInstance if to disambiguate commands that also work on device +template< typename Tag, typename Element, typename... Ts, typename = std::enable_if_t::value> > +std::vector enumerate( Ts... ); + +// for vkEnumerateInstanceLayerProperties -- auto v = enumerate(); +template<> +std::vector enumerate(){ + return enumerateScheme( vkEnumerateInstanceLayerProperties, "vkEnumerateInstanceLayerProperties" ); +} + +// for vkEnumerateDeviceLayerProperties -- auto v = enumerate( pd ); +template<> +std::vector enumerate( VkPhysicalDevice physicalDevice ){ + using namespace std::placeholders; + const auto cmd = vkEnumerateDeviceLayerProperties; + const auto adapterCmd = std::bind( cmd, physicalDevice, _1, _2 ); + + return enumerateScheme( adapterCmd, "vkEnumerateDeviceLayerProperties" ); +} + +// for vkEnumerateInstanceExtensionProperties -- auto v = enumerate( "ln" ); +template<> +std::vector enumerate( const char* pLayerName ){ + using namespace std::placeholders; + const auto cmd = vkEnumerateInstanceExtensionProperties; + const auto adapterCmd = std::bind( cmd, pLayerName, _1, _2 ); + + return enumerateScheme( adapterCmd, "vkEnumerateInstanceExtensionProperties" ); +} + +// for vkEnumerateInstanceExtensionProperties with nullptr layer -- auto v = enumerate(); +template<> +std::vector enumerate(){ + using namespace std::placeholders; + const auto cmd = vkEnumerateInstanceExtensionProperties; + const auto adapterCmd = std::bind( cmd, nullptr, _1, _2 ); + + return enumerateScheme( adapterCmd, "vkEnumerateInstanceExtensionProperties" ); +} + +// for vkEnumerateDeviceExtensionProperties -- auto v = enumerate( pd, "ln" ); +template<> +std::vector enumerate( VkPhysicalDevice physicalDevice, const char* pLayerName ){ + using namespace std::placeholders; + const auto cmd = vkEnumerateDeviceExtensionProperties; + const auto adapterCmd = std::bind( cmd, physicalDevice, pLayerName, _1, _2 ); + + return enumerateScheme( adapterCmd, "vkEnumerateDeviceExtensionProperties" ); +} + +// for vkEnumerateInstanceExtensionProperties with nullptr layer -- auto v = enumerate( pd ); +template<> +std::vector enumerate( VkPhysicalDevice physicalDevice ){ + using namespace std::placeholders; + const auto cmd = vkEnumerateDeviceExtensionProperties; + const auto adapterCmd = std::bind( cmd, physicalDevice, nullptr, _1, _2 ); + + return enumerateScheme( adapterCmd, "vkEnumerateDeviceExtensionProperties" ); +} + +// for vkEnumeratePhysicalDevices -- auto v = enumerate( i ); +template<> +std::vector enumerate( VkInstance instance ){ + using namespace std::placeholders; + const auto cmd = vkEnumeratePhysicalDevices; + const auto adapterCmd = std::bind( cmd, instance, _1, _2 ); + + return enumerateScheme( adapterCmd, "vkEnumeratePhysicalDevices" ); +} + +// for vkGetPhysicalDeviceSurfaceFormatsKHR -- auto v = enumerate( pd, s ); +template<> +std::vector enumerate( VkPhysicalDevice physicalDevice, VkSurfaceKHR surface ){ + using namespace std::placeholders; + const auto cmd = vkGetPhysicalDeviceSurfaceFormatsKHR; + const auto adapterCmd = std::bind( cmd, physicalDevice, surface, _1, _2 ); + + return enumerateScheme( adapterCmd, "vkGetPhysicalDeviceSurfaceFormatsKHR" ); +} + +// for vkGetPhysicalDeviceSurfacePresentModesKHR -- auto v = enumerate( pd, s ); +template<> +std::vector enumerate( VkPhysicalDevice physicalDevice, VkSurfaceKHR surface ){ + using namespace std::placeholders; + const auto cmd = vkGetPhysicalDeviceSurfacePresentModesKHR; + const auto adapterCmd = std::bind( cmd, physicalDevice, surface, _1, _2 ); + + return enumerateScheme( adapterCmd, "vkGetPhysicalDeviceSurfacePresentModesKHR" ); +} + +// for vkGetSwapchainImagesKHR -- auto v = enumerate( d, s ); +template<> +std::vector enumerate( VkDevice device, VkSwapchainKHR swapchain ){ + using namespace std::placeholders; + const auto cmd = vkGetSwapchainImagesKHR; + const auto adapterCmd = std::bind( cmd, device, swapchain, _1, _2 ); + + return enumerateScheme( adapterCmd, "vkGetSwapchainImagesKHR" ); +} + +// ... others to be added as needed + diff --git a/src/graphics/errorhandling.hpp b/src/graphics/errorhandling.hpp new file mode 100644 index 0000000..fed8719 --- /dev/null +++ b/src/graphics/errorhandling.hpp @@ -0,0 +1,203 @@ +// Reusable error handling primitives for Vulkan + +#pragma once + +#include +#include +#include + +#include + +#include "vulkanintrospection.hpp" + +struct VulkanResultException{ + const char* file; + unsigned line; + const char* func; + const char* source; + VkResult result; + + VulkanResultException( const char* file, unsigned line, const char* func, const char* source, VkResult result ) + : file( file ), line( line ), func( func ), source( source ), result( result ){} +}; + +#define RESULT_HANDLER( errorCode, source ) if( errorCode ) throw VulkanResultException( __FILE__, __LINE__, __func__, source, errorCode ) +#define RESULT_HANDLER_EX( cond, errorCode, source ) if( cond ) throw VulkanResultException( __FILE__, __LINE__, __func__, source, errorCode ) + +#define RUNTIME_ASSERT( cond, source ) if( !(cond) ) throw source " failed"; + +// just use cout for logging now +std::ostream& logger = std::cout; + +enum class Highlight{ off, on }; +void genericDebugCallback( std::string flags, Highlight highlight, std::string msgCode, std::string object, const char* message ); + +VKAPI_ATTR VkBool32 VKAPI_CALL genericDebugReportCallback( + VkDebugReportFlagsEXT msgFlags, + VkDebugReportObjectTypeEXT objType, + uint64_t srcObject, + size_t /*location*/, + int32_t msgCode, + const char* pLayerPrefix, + const char* pMsg, + void* /*pUserData*/ +); + +VKAPI_ATTR VkBool32 VKAPI_CALL genericDebugUtilsCallback( + VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, + VkDebugUtilsMessageTypeFlagsEXT messageTypes, + const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, + void* /*pUserData*/ +); + +enum class DebugObjectType{ debugReport, debugUtils } tag; +struct DebugObjectVariant{ + DebugObjectType tag; + union{ + VkDebugReportCallbackEXT debugReportCallback; + VkDebugUtilsMessengerEXT debugUtilsMessenger; + }; +}; + +DebugObjectVariant initDebug( const VkInstance instance, const DebugObjectType debugExtension, const VkDebugUtilsMessageSeverityFlagsEXT debugSeverity, const VkDebugUtilsMessageTypeFlagsEXT debugType ); +void killDebug( VkInstance instance, DebugObjectVariant debug ); + +VkDebugReportFlagsEXT translateFlags( const VkDebugUtilsMessageSeverityFlagsEXT debugSeverity, const VkDebugUtilsMessageTypeFlagsEXT debugType ); + +// Implementation +////////////////////////////////// + +void genericDebugCallback( std::string flags, Highlight highlight, std::string msgCode, std::string object, const char* message ){ + using std::endl; + using std::string; + + const string report = flags + ": " + object + ": " + msgCode + ", \"" + message + '"'; + + if( highlight != Highlight::off ){ + const string border( 80, '!' ); + + logger << border << endl; + logger << report << endl; + logger << border << endl << endl; + } + else{ + logger << report << endl; + } +} + +VKAPI_ATTR VkBool32 VKAPI_CALL genericDebugReportCallback( + VkDebugReportFlagsEXT flags, + VkDebugReportObjectTypeEXT objectType, + uint64_t object, + size_t /*location*/, + int32_t messageCode, + const char* pLayerPrefix, + const char* pMessage, + void* /*pUserData*/ +){ + using std::to_string; + using std::string; + + Highlight highlight; + if( (flags & VK_DEBUG_REPORT_ERROR_BIT_EXT) || (flags & VK_DEBUG_REPORT_WARNING_BIT_EXT) || (flags & VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT) ){ + highlight = Highlight::on; + } + else highlight = Highlight::off; + + + genericDebugCallback( dbrflags_to_string( flags ), highlight, string(pLayerPrefix) + ", " + to_string( messageCode ), to_string( objectType ) + "(" + to_string_hex( object ) + ")", pMessage ); + + return VK_FALSE; // no abort on misbehaving command +} + +VKAPI_ATTR VkBool32 VKAPI_CALL genericDebugUtilsCallback( + VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, + VkDebugUtilsMessageTypeFlagsEXT messageTypes, + const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, + void* /*pUserData*/ +){ + using std::to_string; + using std::string; + + Highlight highlight; + if( (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) || (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT)){ + highlight = Highlight::on; + } + else highlight = Highlight::off; + + string objects; + bool first = true; + for( uint32_t i = 0; i < pCallbackData->objectCount; ++i ){ + const auto& obj = pCallbackData->pObjects[i]; + + if( first ) first = false; + else objects += ", "; + objects += to_string( obj.objectType ) + "(" + to_string_hex( obj.objectHandle ) + ")"; + } + objects = "[" + objects + "]"; + + genericDebugCallback( dbutype_to_string( messageTypes ) + "+" + to_string( messageSeverity ), highlight, string(pCallbackData->pMessageIdName) + "(" + to_string( pCallbackData->messageIdNumber ) + ")", objects, pCallbackData->pMessage ); + + return VK_FALSE; // no abort on misbehaving command +} + +VkDebugReportFlagsEXT translateFlags( const VkDebugUtilsMessageSeverityFlagsEXT debugSeverity, const VkDebugUtilsMessageTypeFlagsEXT debugType ){ + VkDebugReportFlagsEXT flags = 0; + if( (debugType & VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT) || (debugType & VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT) ){ + if( debugSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT ) flags |= VK_DEBUG_REPORT_ERROR_BIT_EXT; + if( debugSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT ) flags |= VK_DEBUG_REPORT_WARNING_BIT_EXT; + if( (debugSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT) && (debugType & VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT) ) flags |= VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT; + if( debugSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT ) flags |= VK_DEBUG_REPORT_INFORMATION_BIT_EXT; + if( debugSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT ) flags |= VK_DEBUG_REPORT_DEBUG_BIT_EXT; + } + + return flags; +} + +DebugObjectVariant initDebug( const VkInstance instance, const DebugObjectType debugExtension, const VkDebugUtilsMessageSeverityFlagsEXT debugSeverity, const VkDebugUtilsMessageTypeFlagsEXT debugType ){ + DebugObjectVariant debug; + debug.tag = debugExtension; + + if( debugExtension == DebugObjectType::debugUtils ){ + const VkDebugUtilsMessengerCreateInfoEXT dmci = { + VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT, + nullptr, // pNext + 0, // flags + debugSeverity, + debugType, + ::genericDebugUtilsCallback, + nullptr // pUserData + }; + + const VkResult errorCode = vkCreateDebugUtilsMessengerEXT( instance, &dmci, nullptr, &debug.debugUtilsMessenger ); RESULT_HANDLER( errorCode, "vkCreateDebugUtilsMessengerEXT" ); + } + else if( debugExtension == DebugObjectType::debugReport ){ + const VkDebugReportCallbackCreateInfoEXT debugCreateInfo{ + VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT, + nullptr, // pNext + translateFlags( debugSeverity, debugType ), + ::genericDebugReportCallback, + nullptr // pUserData + }; + + const VkResult errorCode = vkCreateDebugReportCallbackEXT( instance, &debugCreateInfo, nullptr, &debug.debugReportCallback ); RESULT_HANDLER( errorCode, "vkCreateDebugReportCallbackEXT" ); + } + else{ + throw "initDebug: unknown debug extension"; + } + + return debug; +} + +void killDebug( const VkInstance instance, const DebugObjectVariant debug ){ + if( debug.tag == DebugObjectType::debugUtils ){ + vkDestroyDebugUtilsMessengerEXT( instance, debug.debugUtilsMessenger, nullptr ); + } + else if( debug.tag == DebugObjectType::debugReport ){ + vkDestroyDebugReportCallbackEXT( instance, debug.debugReportCallback, nullptr ); + } + else{ + throw "initDebug: unknown debug extension"; + } +} + diff --git a/src/graphics/vulkanextensionloader.hpp b/src/graphics/vulkanextensionloader.hpp new file mode 100644 index 0000000..047d609 --- /dev/null +++ b/src/graphics/vulkanextensionloader.hpp @@ -0,0 +1,425 @@ +#pragma once + +#include + +#include + +#include + +#include + +void loadInstanceExtensionsCommands( VkInstance instance, const std::vector& instanceExtensions ); +void unloadInstanceExtensionsCommands( VkInstance instance ); + +void loadDeviceExtensionsCommands( VkDevice device, const std::vector& instanceExtensions ); +void unloadDeviceExtensionsCommands( VkDevice device ); + +void loadPDProps2Commands( VkInstance instance ); +void unloadPDProps2Commands( VkInstance instance ); + +void loadDebugReportCommands( VkInstance instance ); +void unloadDebugReportCommands( VkInstance instance ); + +void loadDebugUtilsCommands( VkInstance instance ); +void unloadDebugUtilsCommands( VkInstance instance ); + +void loadExternalMemoryCapsCommands( VkInstance instance ); +void unloadExternalMemoryCapsCommands( VkInstance instance ); + + +void loadExternalMemoryCommands( VkDevice device ); +void unloadExternalMemoryCommands( VkDevice device ); + +#ifdef VK_USE_PLATFORM_WIN32_KHR +void loadExternalMemoryWin32Commands( VkDevice device ); +void unloadExternalMemoryWin32Commands( VkDevice device ); +#endif + +void loadDedicatedAllocationCommands( VkDevice device ); +void unloadDedicatedAllocationCommands( VkDevice device ); + +//////////////////////////////////////////////////////// + +std::unordered_map< VkInstance, std::vector > instanceExtensionsMap; +std::unordered_map< VkPhysicalDevice, VkInstance > physicalDeviceInstanceMap; + +void populatePhysicalDeviceInstaceMap( const VkInstance instance ){ + const std::vector physicalDevices = enumerate( instance ); + for( const auto pd : physicalDevices ) physicalDeviceInstanceMap[pd] = instance; +} + +void loadInstanceExtensionsCommands( const VkInstance instance, const std::vector& instanceExtensions ){ + using std::strcmp; + + instanceExtensionsMap[instance] = instanceExtensions; + + for( const auto e : instanceExtensions ){ + if( strcmp( e, VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME ) == 0 ) loadPDProps2Commands( instance ); + if( strcmp( e, VK_EXT_DEBUG_REPORT_EXTENSION_NAME ) == 0 ) loadDebugReportCommands( instance ); + if( strcmp( e, VK_EXT_DEBUG_UTILS_EXTENSION_NAME ) == 0 ) loadDebugUtilsCommands( instance ); + if( strcmp( e, VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME ) == 0 ) loadExternalMemoryCapsCommands( instance ); + // ... + } +} + +void unloadInstanceExtensionsCommands( const VkInstance instance ){ + using std::strcmp; + + for( const auto e : instanceExtensionsMap.at( instance ) ){ + if( strcmp( e, VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME ) == 0 ) unloadPDProps2Commands( instance ); + if( strcmp( e, VK_EXT_DEBUG_REPORT_EXTENSION_NAME ) == 0 ) unloadDebugReportCommands( instance ); + if( strcmp( e, VK_EXT_DEBUG_UTILS_EXTENSION_NAME ) == 0 ) unloadDebugUtilsCommands( instance ); + if( strcmp( e, VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME ) == 0 ) unloadExternalMemoryCapsCommands( instance ); + // ... + } + + instanceExtensionsMap.erase( instance ); +} + +std::unordered_map< VkDevice, std::vector > deviceExtensionsMap; + +void loadDeviceExtensionsCommands( const VkDevice device, const std::vector& deviceExtensions ){ + using std::strcmp; + + deviceExtensionsMap[device] = deviceExtensions; + + for( const auto e : deviceExtensions ){ + if( strcmp( e, VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME ) == 0 ) loadExternalMemoryCommands( device ); +#ifdef VK_USE_PLATFORM_WIN32_KHR + if( strcmp( e, VK_KHR_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME ) == 0 ) loadExternalMemoryWin32Commands( device ); +#endif + if( strcmp( e, VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME ) == 0 ) loadDedicatedAllocationCommands( device ); + // ... + } +} + +void unloadDeviceExtensionsCommands( const VkDevice device ){ + using std::strcmp; + + for( const auto e : deviceExtensionsMap.at( device ) ){ + if( strcmp( e, VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME ) == 0 ) unloadExternalMemoryCommands( device ); +#ifdef VK_USE_PLATFORM_WIN32_KHR + if( strcmp( e, VK_KHR_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME ) == 0 ) unloadExternalMemoryWin32Commands( device ); +#endif + if( strcmp( e, VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME ) == 0 ) unloadDedicatedAllocationCommands( device ); + // ... + } + + deviceExtensionsMap.erase( device ); +} + + +// VK_KHR_get_physical_device_properties2 +/////////////////////////////////////////// + +std::unordered_map< VkInstance, PFN_vkGetPhysicalDeviceFeatures2KHR > GetPhysicalDeviceFeatures2KHRDispatchTable; +std::unordered_map< VkInstance, PFN_vkGetPhysicalDeviceProperties2KHR > GetPhysicalDeviceProperties2KHRDispatchTable; +std::unordered_map< VkInstance, PFN_vkGetPhysicalDeviceFormatProperties2KHR > GetPhysicalDeviceFormatProperties2KHRDispatchTable; +std::unordered_map< VkInstance, PFN_vkGetPhysicalDeviceImageFormatProperties2KHR > GetPhysicalDeviceImageFormatProperties2KHRDispatchTable; +std::unordered_map< VkInstance, PFN_vkGetPhysicalDeviceQueueFamilyProperties2KHR > GetPhysicalDeviceQueueFamilyProperties2KHRDispatchTable; +std::unordered_map< VkInstance, PFN_vkGetPhysicalDeviceMemoryProperties2KHR > GetPhysicalDeviceMemoryProperties2KHRDispatchTable; +std::unordered_map< VkInstance, PFN_vkGetPhysicalDeviceSparseImageFormatProperties2KHR > GetPhysicalDeviceSparseImageFormatProperties2KHRDispatchTable; + +void loadPDProps2Commands( VkInstance instance ){ + populatePhysicalDeviceInstaceMap( instance ); + + PFN_vkVoidFunction temp_fp; + + temp_fp = vkGetInstanceProcAddr( instance, "vkGetPhysicalDeviceFeatures2KHR" ); + if( !temp_fp ) throw "Failed to load vkGetPhysicalDeviceFeatures2KHR"; // check shouldn't be necessary (based on spec) + GetPhysicalDeviceFeatures2KHRDispatchTable[instance] = reinterpret_cast( temp_fp ); + + temp_fp = vkGetInstanceProcAddr( instance, "vkGetPhysicalDeviceProperties2KHR" ); + if( !temp_fp ) throw "Failed to load vkGetPhysicalDeviceProperties2KHR"; // check shouldn't be necessary (based on spec) + GetPhysicalDeviceProperties2KHRDispatchTable[instance] = reinterpret_cast( temp_fp ); + + temp_fp = vkGetInstanceProcAddr( instance, "vkGetPhysicalDeviceFormatProperties2KHR" ); + if( !temp_fp ) throw "Failed to load vkGetPhysicalDeviceFormatProperties2KHR"; // check shouldn't be necessary (based on spec) + GetPhysicalDeviceFormatProperties2KHRDispatchTable[instance] = reinterpret_cast( temp_fp ); + + temp_fp = vkGetInstanceProcAddr( instance, "vkGetPhysicalDeviceImageFormatProperties2KHR" ); + if( !temp_fp ) throw "Failed to load vkGetPhysicalDeviceImageFormatProperties2KHR"; // check shouldn't be necessary (based on spec) + GetPhysicalDeviceImageFormatProperties2KHRDispatchTable[instance] = reinterpret_cast( temp_fp ); + + temp_fp = vkGetInstanceProcAddr( instance, "vkGetPhysicalDeviceQueueFamilyProperties2KHR" ); + if( !temp_fp ) throw "Failed to load vkGetPhysicalDeviceQueueFamilyProperties2KHR"; // check shouldn't be necessary (based on spec) + GetPhysicalDeviceQueueFamilyProperties2KHRDispatchTable[instance] = reinterpret_cast( temp_fp ); + + temp_fp = vkGetInstanceProcAddr( instance, "vkGetPhysicalDeviceMemoryProperties2KHR" ); + if( !temp_fp ) throw "Failed to load vkGetPhysicalDeviceMemoryProperties2KHR"; // check shouldn't be necessary (based on spec) + GetPhysicalDeviceMemoryProperties2KHRDispatchTable[instance] = reinterpret_cast( temp_fp ); + + temp_fp = vkGetInstanceProcAddr( instance, "vkGetPhysicalDeviceSparseImageFormatProperties2KHR" ); + if( !temp_fp ) throw "Failed to load vkGetPhysicalDeviceSparseImageFormatProperties2KHR"; // check shouldn't be necessary (based on spec) + GetPhysicalDeviceSparseImageFormatProperties2KHRDispatchTable[instance] = reinterpret_cast( temp_fp ); +} + +void unloadPDProps2Commands( VkInstance instance ){ + GetPhysicalDeviceFeatures2KHRDispatchTable.erase( instance ); + GetPhysicalDeviceProperties2KHRDispatchTable.erase( instance ); + GetPhysicalDeviceFormatProperties2KHRDispatchTable.erase( instance ); + GetPhysicalDeviceImageFormatProperties2KHRDispatchTable.erase( instance ); + GetPhysicalDeviceQueueFamilyProperties2KHRDispatchTable.erase( instance ); + GetPhysicalDeviceMemoryProperties2KHRDispatchTable.erase( instance ); + GetPhysicalDeviceSparseImageFormatProperties2KHRDispatchTable.erase( instance ); +} + +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceFeatures2KHR( VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures2* pFeatures ){ + const VkInstance instance = physicalDeviceInstanceMap.at( physicalDevice ); + auto dispatched_cmd = GetPhysicalDeviceFeatures2KHRDispatchTable.at( instance ); + return dispatched_cmd( physicalDevice, pFeatures ); +} + +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceProperties2KHR( VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties2* pProperties ){ + const VkInstance instance = physicalDeviceInstanceMap.at( physicalDevice ); + auto dispatched_cmd = GetPhysicalDeviceProperties2KHRDispatchTable.at( instance ); + return dispatched_cmd( physicalDevice, pProperties ); +} + +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceFormatProperties2KHR( VkPhysicalDevice physicalDevice, VkFormat format, VkFormatProperties2* pFormatProperties ){ + const VkInstance instance = physicalDeviceInstanceMap.at( physicalDevice ); + auto dispatched_cmd = GetPhysicalDeviceFormatProperties2KHRDispatchTable.at( instance ); + return dispatched_cmd( physicalDevice, format, pFormatProperties ); +} + +VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceImageFormatProperties2KHR( VkPhysicalDevice physicalDevice, const VkPhysicalDeviceImageFormatInfo2* pImageFormatInfo, VkImageFormatProperties2* pImageFormatProperties ){ + const VkInstance instance = physicalDeviceInstanceMap.at( physicalDevice ); + auto dispatched_cmd = GetPhysicalDeviceImageFormatProperties2KHRDispatchTable.at( instance ); + return dispatched_cmd( physicalDevice, pImageFormatInfo, pImageFormatProperties ); +} + +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceQueueFamilyProperties2KHR( VkPhysicalDevice physicalDevice, uint32_t* pQueueFamilyPropertyCount, VkQueueFamilyProperties2* pQueueFamilyProperties ){ + const VkInstance instance = physicalDeviceInstanceMap.at( physicalDevice ); + auto dispatched_cmd = GetPhysicalDeviceQueueFamilyProperties2KHRDispatchTable.at( instance ); + return dispatched_cmd( physicalDevice, pQueueFamilyPropertyCount, pQueueFamilyProperties ); +} + +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceMemoryProperties2KHR( VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties2* pMemoryProperties ){ + const VkInstance instance = physicalDeviceInstanceMap.at( physicalDevice ); + auto dispatched_cmd = GetPhysicalDeviceMemoryProperties2KHRDispatchTable.at( instance ); + return dispatched_cmd( physicalDevice, pMemoryProperties ); +} + +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceSparseImageFormatProperties2KHR( VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSparseImageFormatInfo2* pFormatInfo, uint32_t* pPropertyCount, VkSparseImageFormatProperties2* pProperties ){ + const VkInstance instance = physicalDeviceInstanceMap.at( physicalDevice ); + auto dispatched_cmd = GetPhysicalDeviceSparseImageFormatProperties2KHRDispatchTable.at( instance ); + return dispatched_cmd( physicalDevice, pFormatInfo, pPropertyCount, pProperties ); +} + +// VK_EXT_debug_report +////////////////////////////////// + +std::unordered_map< VkInstance, PFN_vkCreateDebugReportCallbackEXT > CreateDebugReportCallbackEXTDispatchTable; +std::unordered_map< VkInstance, PFN_vkDestroyDebugReportCallbackEXT > DestroyDebugReportCallbackEXTDispatchTable; +std::unordered_map< VkInstance, PFN_vkDebugReportMessageEXT > DebugReportMessageEXTDispatchTable; + +void loadDebugReportCommands( VkInstance instance ){ + PFN_vkVoidFunction temp_fp; + + temp_fp = vkGetInstanceProcAddr( instance, "vkCreateDebugReportCallbackEXT" ); + if( !temp_fp ) throw "Failed to load vkCreateDebugReportCallbackEXT"; // check shouldn't be necessary (based on spec) + CreateDebugReportCallbackEXTDispatchTable[instance] = reinterpret_cast( temp_fp ); + + temp_fp = vkGetInstanceProcAddr( instance, "vkDestroyDebugReportCallbackEXT" ); + if( !temp_fp ) throw "Failed to load vkDestroyDebugReportCallbackEXT"; // check shouldn't be necessary (based on spec) + DestroyDebugReportCallbackEXTDispatchTable[instance] = reinterpret_cast( temp_fp ); + + temp_fp = vkGetInstanceProcAddr( instance, "vkDebugReportMessageEXT" ); + if( !temp_fp ) throw "Failed to load vkDebugReportMessageEXT"; // check shouldn't be necessary (based on spec) + DebugReportMessageEXTDispatchTable[instance] = reinterpret_cast( temp_fp ); +} + +void unloadDebugReportCommands( VkInstance instance ){ + CreateDebugReportCallbackEXTDispatchTable.erase( instance ); + DestroyDebugReportCallbackEXTDispatchTable.erase( instance ); + DebugReportMessageEXTDispatchTable.erase( instance ); +} + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateDebugReportCallbackEXT( + VkInstance instance, + const VkDebugReportCallbackCreateInfoEXT* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkDebugReportCallbackEXT* pCallback +){ + auto dispatched_cmd = CreateDebugReportCallbackEXTDispatchTable.at( instance ); + return dispatched_cmd( instance, pCreateInfo, pAllocator, pCallback ); +} + +VKAPI_ATTR void VKAPI_CALL vkDestroyDebugReportCallbackEXT( + VkInstance instance, + VkDebugReportCallbackEXT callback, + const VkAllocationCallbacks* pAllocator +){ + auto dispatched_cmd = DestroyDebugReportCallbackEXTDispatchTable.at( instance ); + return dispatched_cmd( instance, callback, pAllocator ); +} + +VKAPI_ATTR void VKAPI_CALL vkDebugReportMessageEXT( + VkInstance instance, + VkDebugReportFlagsEXT flags, + VkDebugReportObjectTypeEXT objectType, + uint64_t object, + size_t location, + int32_t messageCode, + const char* pLayerPrefix, + const char* pMessage +){ + auto dispatched_cmd = DebugReportMessageEXTDispatchTable.at( instance ); + return dispatched_cmd( instance, flags, objectType, object, location, messageCode, pLayerPrefix, pMessage ); +} + +// VK_EXT_debug_utils +////////////////////////////////// + +std::unordered_map< VkInstance, PFN_vkCreateDebugUtilsMessengerEXT > CreateDebugUtilsMessengerEXTDispatchTable; +std::unordered_map< VkInstance, PFN_vkDestroyDebugUtilsMessengerEXT > DestroyDebugUtilsMessengerEXTDispatchTable; +std::unordered_map< VkInstance, PFN_vkSubmitDebugUtilsMessageEXT > SubmitDebugUtilsMessageEXTDispatchTable; + +void loadDebugUtilsCommands( VkInstance instance ){ + PFN_vkVoidFunction temp_fp; + + temp_fp = vkGetInstanceProcAddr( instance, "vkCreateDebugUtilsMessengerEXT" ); + if( !temp_fp ) throw "Failed to load vkCreateDebugUtilsMessengerEXT"; // check shouldn't be necessary (based on spec) + CreateDebugUtilsMessengerEXTDispatchTable[instance] = reinterpret_cast( temp_fp ); + + temp_fp = vkGetInstanceProcAddr( instance, "vkDestroyDebugUtilsMessengerEXT" ); + if( !temp_fp ) throw "Failed to load vkDestroyDebugUtilsMessengerEXT"; // check shouldn't be necessary (based on spec) + DestroyDebugUtilsMessengerEXTDispatchTable[instance] = reinterpret_cast( temp_fp ); + + temp_fp = vkGetInstanceProcAddr( instance, "vkSubmitDebugUtilsMessageEXT" ); + if( !temp_fp ) throw "Failed to load vkSubmitDebugUtilsMessageEXT"; // check shouldn't be necessary (based on spec) + SubmitDebugUtilsMessageEXTDispatchTable[instance] = reinterpret_cast( temp_fp ); +} + +void unloadDebugUtilsCommands( VkInstance instance ){ + CreateDebugUtilsMessengerEXTDispatchTable.erase( instance ); + DestroyDebugUtilsMessengerEXTDispatchTable.erase( instance ); + SubmitDebugUtilsMessageEXTDispatchTable.erase( instance ); +} + +VKAPI_ATTR VkResult VKAPI_CALL vkCreateDebugUtilsMessengerEXT( + VkInstance instance, + const VkDebugUtilsMessengerCreateInfoEXT* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkDebugUtilsMessengerEXT* pMessenger +){ + auto dispatched_cmd = CreateDebugUtilsMessengerEXTDispatchTable.at( instance ); + return dispatched_cmd( instance, pCreateInfo, pAllocator, pMessenger ); +} + +VKAPI_ATTR void VKAPI_CALL vkDestroyDebugUtilsMessengerEXT( + VkInstance instance, + VkDebugUtilsMessengerEXT messenger, + const VkAllocationCallbacks* pAllocator +){ + auto dispatched_cmd = DestroyDebugUtilsMessengerEXTDispatchTable.at( instance ); + return dispatched_cmd( instance, messenger, pAllocator ); +} + +VKAPI_ATTR void VKAPI_CALL vkSubmitDebugUtilsMessageEXT( + VkInstance instance, + VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, + VkDebugUtilsMessageTypeFlagsEXT messageTypes, + const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData +){ + auto dispatched_cmd = SubmitDebugUtilsMessageEXTDispatchTable.at( instance ); + return dispatched_cmd( instance, messageSeverity, messageTypes, pCallbackData ); +} + +// VK_KHR_external_memory_capabilities +/////////////////////////////////////////// + +std::unordered_map< VkInstance, PFN_vkGetPhysicalDeviceExternalBufferPropertiesKHR > GetPhysicalDeviceExternalBufferPropertiesKHRDispatchTable; + +void loadExternalMemoryCapsCommands( VkInstance instance ){ + populatePhysicalDeviceInstaceMap( instance ); + + PFN_vkVoidFunction temp_fp; + + temp_fp = vkGetInstanceProcAddr( instance, "vkGetPhysicalDeviceExternalBufferPropertiesKHR" ); + if( !temp_fp ) throw "Failed to load vkGetPhysicalDeviceExternalBufferPropertiesKHR"; // check shouldn't be necessary (based on spec) + GetPhysicalDeviceExternalBufferPropertiesKHRDispatchTable[instance] = reinterpret_cast( temp_fp ); +} + +void unloadExternalMemoryCapsCommands( VkInstance instance ){ + GetPhysicalDeviceExternalBufferPropertiesKHRDispatchTable.erase( instance ); +} + +VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceExternalBufferPropertiesKHR( + VkPhysicalDevice physicalDevice, + const VkPhysicalDeviceExternalBufferInfo* pExternalBufferInfo, + VkExternalBufferProperties* pExternalBufferProperties +){ + const VkInstance instance = physicalDeviceInstanceMap.at( physicalDevice ); + auto dispatched_cmd = GetPhysicalDeviceExternalBufferPropertiesKHRDispatchTable.at( instance ); + return dispatched_cmd( physicalDevice, pExternalBufferInfo, pExternalBufferProperties ); +} + + +// VK_KHR_external_memory +/////////////////////////////////////////// + +void loadExternalMemoryCommands( VkDevice ){ + // no commands +} + +void unloadExternalMemoryCommands( VkDevice ){ + // no commands +} + + +#ifdef VK_USE_PLATFORM_WIN32_KHR +// VK_KHR_external_memory_win32 +/////////////////////////////////////////// + +std::unordered_map< VkDevice, PFN_vkGetMemoryWin32HandleKHR > GetMemoryWin32HandleKHRDispatchTable; +std::unordered_map< VkDevice, PFN_vkGetMemoryWin32HandlePropertiesKHR > GetMemoryWin32HandlePropertiesKHRDispatchTable; + +void loadExternalMemoryWin32Commands( VkDevice device ){ + PFN_vkVoidFunction temp_fp; + + temp_fp = vkGetDeviceProcAddr( device, "vkGetMemoryWin32HandleKHR" ); + if( !temp_fp ) throw "Failed to load vkGetMemoryWin32HandleKHR"; // check shouldn't be necessary (based on spec) + GetMemoryWin32HandleKHRDispatchTable[device] = reinterpret_cast( temp_fp ); + + temp_fp = vkGetDeviceProcAddr( device, "vkGetMemoryWin32HandlePropertiesKHR" ); + if( !temp_fp ) throw "Failed to load vkGetMemoryWin32HandlePropertiesKHR"; // check shouldn't be necessary (based on spec) + GetMemoryWin32HandlePropertiesKHRDispatchTable[device] = reinterpret_cast( temp_fp ); +} + +void unloadExternalMemoryWin32Commands( VkDevice device ){ + GetMemoryWin32HandleKHRDispatchTable.erase( device ); + GetMemoryWin32HandlePropertiesKHRDispatchTable.erase( device ); +} + +VKAPI_ATTR VkResult VKAPI_CALL vkGetMemoryWin32HandleKHR( + VkDevice device, + const VkMemoryGetWin32HandleInfoKHR* pGetWin32HandleInfo, + HANDLE* pHandle +){ + auto dispatched_cmd = GetMemoryWin32HandleKHRDispatchTable.at( device ); + return dispatched_cmd( device, pGetWin32HandleInfo, pHandle ); +} + +VKAPI_ATTR VkResult VKAPI_CALL vkGetMemoryWin32HandlePropertiesKHR( + VkDevice device, + VkExternalMemoryHandleTypeFlagBits handleType, + HANDLE handle, + VkMemoryWin32HandlePropertiesKHR* pMemoryWin32HandleProperties +){ + auto dispatched_cmd = GetMemoryWin32HandlePropertiesKHRDispatchTable.at( device ); + return dispatched_cmd( device, handleType, handle, pMemoryWin32HandleProperties ); +} +#endif + +// VK_KHR_dedicated_allocation +/////////////////////////////////////////// + +void loadDedicatedAllocationCommands( VkDevice ){ + // no commands +} + +void unloadDedicatedAllocationCommands( VkDevice ){ + // no commands +} + diff --git a/src/graphics/vulkanintrospection.hpp b/src/graphics/vulkanintrospection.hpp new file mode 100644 index 0000000..8c70aa3 --- /dev/null +++ b/src/graphics/vulkanintrospection.hpp @@ -0,0 +1,274 @@ +// Introspection for Vulkan enums -- mostly to_string + +#pragma once + +#include +#include + +#include + +template +inline uint64_t handleToUint64(const PHANDLE_T *h) { return reinterpret_cast(h); } +inline uint64_t handleToUint64(const uint64_t h) { return h; } + +const char* to_string( const VkResult r ){ + switch( r ){ + case VK_SUCCESS: return "VK_SUCCESS"; + case VK_NOT_READY: return "VK_NOT_READY"; + case VK_TIMEOUT: return "VK_TIMEOUT"; + case VK_EVENT_SET: return "VK_EVENT_SET"; + case VK_EVENT_RESET: return "VK_EVENT_RESET"; + case VK_INCOMPLETE: return "VK_INCOMPLETE"; + case VK_ERROR_OUT_OF_HOST_MEMORY: return "VK_ERROR_OUT_OF_HOST_MEMORY"; + case VK_ERROR_OUT_OF_DEVICE_MEMORY: return "VK_ERROR_OUT_OF_DEVICE_MEMORY"; + case VK_ERROR_INITIALIZATION_FAILED: return "VK_ERROR_INITIALIZATION_FAILED"; + case VK_ERROR_DEVICE_LOST: return "VK_ERROR_DEVICE_LOST"; + case VK_ERROR_MEMORY_MAP_FAILED: return "VK_ERROR_MEMORY_MAP_FAILED"; + case VK_ERROR_LAYER_NOT_PRESENT: return "VK_ERROR_LAYER_NOT_PRESENT"; + case VK_ERROR_EXTENSION_NOT_PRESENT: return "VK_ERROR_EXTENSION_NOT_PRESENT"; + case VK_ERROR_FEATURE_NOT_PRESENT: return "VK_ERROR_FEATURE_NOT_PRESENT"; + case VK_ERROR_INCOMPATIBLE_DRIVER: return "VK_ERROR_INCOMPATIBLE_DRIVER"; + case VK_ERROR_TOO_MANY_OBJECTS: return "VK_ERROR_TOO_MANY_OBJECTS"; + case VK_ERROR_FORMAT_NOT_SUPPORTED: return "VK_ERROR_FORMAT_NOT_SUPPORTED"; + case VK_ERROR_FRAGMENTED_POOL: return "VK_ERROR_FRAGMENTED_POOL"; + case VK_ERROR_UNKNOWN: return "VK_ERROR_UNKNOWN"; + case VK_ERROR_OUT_OF_POOL_MEMORY: return "VK_ERROR_OUT_OF_POOL_MEMORY"; + case VK_ERROR_INVALID_EXTERNAL_HANDLE: return "VK_ERROR_INVALID_EXTERNAL_HANDLE"; + case VK_ERROR_FRAGMENTATION: return "VK_ERROR_FRAGMENTATION"; + case VK_ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS: return "VK_ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS"; + case VK_ERROR_SURFACE_LOST_KHR: return "VK_ERROR_SURFACE_LOST_KHR"; + case VK_ERROR_NATIVE_WINDOW_IN_USE_KHR: return "VK_ERROR_NATIVE_WINDOW_IN_USE_KHR"; + case VK_SUBOPTIMAL_KHR: return "VK_SUBOPTIMAL_KHR"; + case VK_ERROR_OUT_OF_DATE_KHR: return "VK_ERROR_OUT_OF_DATE_KHR"; + case VK_ERROR_INCOMPATIBLE_DISPLAY_KHR: return "VK_ERROR_INCOMPATIBLE_DISPLAY_KHR"; + case VK_ERROR_VALIDATION_FAILED_EXT: return "VK_ERROR_VALIDATION_FAILED_EXT"; + case VK_ERROR_INVALID_SHADER_NV: return "VK_ERROR_INVALID_SHADER_NV"; + case VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT: return "VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT"; + case VK_ERROR_NOT_PERMITTED_EXT: return "VK_ERROR_NOT_PERMITTED_EXT"; + case VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT: return "VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT"; + case VK_THREAD_IDLE_KHR: return "VK_THREAD_IDLE_KHR"; + case VK_THREAD_DONE_KHR: return "VK_THREAD_DONE_KHR"; + case VK_OPERATION_DEFERRED_KHR: return "VK_OPERATION_DEFERRED_KHR"; + case VK_OPERATION_NOT_DEFERRED_KHR: return "VK_OPERATION_NOT_DEFERRED_KHR"; + case VK_PIPELINE_COMPILE_REQUIRED_EXT: return "VK_PIPELINE_COMPILE_REQUIRED_EXT"; + default: return "unrecognized VkResult code"; + } +} + +std::string to_string( const VkDebugReportObjectTypeEXT o ){ + switch( o ){ + case VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT: return "unknown"; + case VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT: return "Instance"; + case VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT: return "PhysicalDevice"; + case VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT: return "Device"; + case VK_DEBUG_REPORT_OBJECT_TYPE_QUEUE_EXT: return "Queue"; + case VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT: return "Semaphore"; + case VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT: return "CommandBuffer"; + case VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT: return "Fence"; + case VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT: return "DeviceMemory"; + case VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT: return "Buffer"; + case VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT: return "Image"; + case VK_DEBUG_REPORT_OBJECT_TYPE_EVENT_EXT: return "Event"; + case VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT: return "QueryPool"; + case VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_VIEW_EXT: return "BufferView"; + case VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_VIEW_EXT: return "ImageView"; + case VK_DEBUG_REPORT_OBJECT_TYPE_SHADER_MODULE_EXT: return "ShaderModule"; + case VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_CACHE_EXT: return "PipelineCache"; + case VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_LAYOUT_EXT: return "PipelineLayout"; + case VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT: return "RenderPass"; + case VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT: return "Pipeline"; + case VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT_EXT: return "DescriptorSetLayout"; + case VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_EXT: return "Sampler"; + case VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT: return "DescriptorPool"; + case VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT: return "DescriptorSet"; + case VK_DEBUG_REPORT_OBJECT_TYPE_FRAMEBUFFER_EXT: return "Framebuffer"; + case VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_POOL_EXT: return "Command pool"; + case VK_DEBUG_REPORT_OBJECT_TYPE_SURFACE_KHR_EXT: return "SurfaceKHR"; + case VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT: return "SwapchainKHR"; + case VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_CALLBACK_EXT_EXT: return "DebugReportCallbackEXT"; + case VK_DEBUG_REPORT_OBJECT_TYPE_DISPLAY_KHR_EXT: return "DisplayKHR"; + case VK_DEBUG_REPORT_OBJECT_TYPE_DISPLAY_MODE_KHR_EXT: return "DisplayModeKHR"; + case VK_DEBUG_REPORT_OBJECT_TYPE_VALIDATION_CACHE_EXT_EXT: return "ValidationCacheEXT"; + case VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION_EXT: return "SamplerYcbcrConversion"; + case VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_EXT: return "DescriptorUpdateTemplate"; + case VK_DEBUG_REPORT_OBJECT_TYPE_ACCELERATION_STRUCTURE_KHR_EXT: return "AccelerationStructureKHR"; + case VK_DEBUG_REPORT_OBJECT_TYPE_ACCELERATION_STRUCTURE_NV_EXT: return "AccelerationStructureNV"; + default: return "unrecognized type"; + } +} + +std::string to_string( const VkObjectType o ){ + switch( o ){ + case VK_OBJECT_TYPE_UNKNOWN: return "unknown"; + case VK_OBJECT_TYPE_INSTANCE: return "Instance"; + case VK_OBJECT_TYPE_PHYSICAL_DEVICE: return "PhysicalDevice"; + case VK_OBJECT_TYPE_DEVICE: return "Device"; + case VK_OBJECT_TYPE_QUEUE: return "Queue"; + case VK_OBJECT_TYPE_SEMAPHORE: return "Semaphore"; + case VK_OBJECT_TYPE_COMMAND_BUFFER: return "CommandBuffer"; + case VK_OBJECT_TYPE_FENCE: return "Fence"; + case VK_OBJECT_TYPE_DEVICE_MEMORY: return "DeviceMemory"; + case VK_OBJECT_TYPE_BUFFER: return "Buffer"; + case VK_OBJECT_TYPE_IMAGE: return "Image"; + case VK_OBJECT_TYPE_EVENT: return "Event"; + case VK_OBJECT_TYPE_QUERY_POOL: return "QueryPool"; + case VK_OBJECT_TYPE_BUFFER_VIEW: return "BufferView"; + case VK_OBJECT_TYPE_IMAGE_VIEW: return "ImageView"; + case VK_OBJECT_TYPE_SHADER_MODULE: return "ShaderModule"; + case VK_OBJECT_TYPE_PIPELINE_CACHE: return "PipelineCache"; + case VK_OBJECT_TYPE_PIPELINE_LAYOUT: return "PipelineLayout"; + case VK_OBJECT_TYPE_RENDER_PASS: return "RenderPass"; + case VK_OBJECT_TYPE_PIPELINE: return "Pipeline"; + case VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT: return "DescriptorSetLayout"; + case VK_OBJECT_TYPE_SAMPLER: return "Sampler"; + case VK_OBJECT_TYPE_DESCRIPTOR_POOL: return "DescriptorPool"; + case VK_OBJECT_TYPE_DESCRIPTOR_SET: return "DescriptorSet"; + case VK_OBJECT_TYPE_FRAMEBUFFER: return "Framebuffer"; + case VK_OBJECT_TYPE_COMMAND_POOL: return "Command pool"; + case VK_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION: return "SamplerYcbcrConversion"; + case VK_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE: return "DescriptorUpdateTemplateKHR"; + case VK_OBJECT_TYPE_SURFACE_KHR: return "SurfaceKHR"; + case VK_OBJECT_TYPE_SWAPCHAIN_KHR: return "SwapchainKHR"; + case VK_OBJECT_TYPE_DISPLAY_KHR: return "DisplayKHR"; + case VK_OBJECT_TYPE_DISPLAY_MODE_KHR: return "DisplayModeKHR"; + case VK_OBJECT_TYPE_DEBUG_REPORT_CALLBACK_EXT: return "DebugReportCallbackEXT"; +#ifdef VK_ENABLE_BETA_EXTENSIONS + case VK_OBJECT_TYPE_VIDEO_SESSION_KHR: return "VideoSessionKHR"; + case VK_OBJECT_TYPE_VIDEO_SESSION_PARAMETERS_KHR: return "VideoSessionParametersKHR"; +#endif + case VK_OBJECT_TYPE_DEBUG_UTILS_MESSENGER_EXT: return "DebugUtilsMessengerEXT"; + case VK_OBJECT_TYPE_ACCELERATION_STRUCTURE_KHR: return "AccelerationStructureKHR"; + case VK_OBJECT_TYPE_VALIDATION_CACHE_EXT: return "ValidationCacheEXT"; + case VK_OBJECT_TYPE_ACCELERATION_STRUCTURE_NV: return "AccelerationStructureNV"; + case VK_OBJECT_TYPE_PERFORMANCE_CONFIGURATION_INTEL: return "PerformanceConfigurationINTEL"; + case VK_OBJECT_TYPE_DEFERRED_OPERATION_KHR: return "DeferredOperationKHR"; + case VK_OBJECT_TYPE_INDIRECT_COMMANDS_LAYOUT_NV: return "IndirectCommandsLayoutNV"; + case VK_OBJECT_TYPE_PRIVATE_DATA_SLOT_EXT: return "PrivateDataSlotEXT"; + default: return "unrecognized type"; + } +} + +std::string dbrflags_to_string( VkDebugReportFlagsEXT msgFlags ){ + std::string res; + bool first = true; + + if( msgFlags & VK_DEBUG_REPORT_ERROR_BIT_EXT ){ + if( !first ) res += " | "; + res += "ERROR"; + first = false; + } + + if( msgFlags & VK_DEBUG_REPORT_WARNING_BIT_EXT ){ + if( !first ) res += " | "; + res += "WARNING"; + first = false; + } + + if( msgFlags & VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT ){ + if( !first ) res += " | "; + res += "PERFORMANCE"; + first = false; + } + + if( msgFlags & VK_DEBUG_REPORT_INFORMATION_BIT_EXT ){ + if( !first ) res += " | "; + res += "Info"; + first = false; + } + + if( msgFlags & VK_DEBUG_REPORT_DEBUG_BIT_EXT ){ + if( !first ) res += " | "; + res += "Debug"; + first = false; + } + + VkDebugReportFlagsEXT known = VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT | VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT | VK_DEBUG_REPORT_INFORMATION_BIT_EXT | VK_DEBUG_REPORT_DEBUG_BIT_EXT; + if( msgFlags & ~known ){ + if( !first ) res += " | "; + res += "UNRECOGNIZED_FLAG"; + first = false; + } + + return res; +} + +std::string dbuseverity_to_string( const VkDebugUtilsMessageSeverityFlagsEXT debugSeverity ){ + std::string res; + bool first = true; + + if( debugSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT ){ + if( !first ) res += " | "; + res += "ERROR"; + first = false; + } + + if( debugSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT ){ + if( !first ) res += " | "; + res += "WARNING"; + first = false; + } + + if( debugSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT ){ + if( !first ) res += " | "; + res += "Info"; + first = false; + } + + if( debugSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT ){ + if( !first ) res += " | "; + res += "Verbose"; + first = false; + } + + VkDebugUtilsMessageSeverityFlagsEXT known = VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT; + if( debugSeverity & ~known ){ + if( !first ) res += " | "; + res += "UNRECOGNIZED_FLAG"; + first = false; + } + + return res; +} + +std::string to_string( const VkDebugUtilsMessageSeverityFlagBitsEXT debugSeverity ){ + return dbuseverity_to_string( debugSeverity ); +} + +std::string dbutype_to_string( const VkDebugUtilsMessageTypeFlagsEXT debugType ){ + std::string res; + bool first = true; + + if( debugType & VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT ){ + if( !first ) res += " | "; + res += "GENERAL"; + first = false; + } + + if( debugType & VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT ){ + if( !first ) res += " | "; + res += "VALIDATION"; + first = false; + } + + if( debugType & VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT ){ + if( !first ) res += " | "; + res += "PERFORMANCE"; + first = false; + } + + VkDebugUtilsMessageSeverityFlagsEXT known = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT; + if( debugType & ~known ){ + if( !first ) res += " | "; + res += "UNRECOGNIZED_FLAG"; + first = false; + } + + return res; +} + +std::string to_string_hex( const uint64_t n ){ + std::stringstream ss; + ss << std::hex << std::noshowbase << std::uppercase << n; + return "0x" + ss.str(); +} + diff --git a/src/inferno.cpp b/src/inferno.cpp index 880ff57..fc44448 100644 --- a/src/inferno.cpp +++ b/src/inferno.cpp @@ -1,7 +1,7 @@ #include "inferno.hpp" -#include #include +#include // #include "gui/layout.hpp" // #include "renderer/renderer.hpp" // #include "scene/scene.hpp" @@ -21,6 +21,7 @@ #include #include #include +#include namespace inferno { @@ -83,13 +84,14 @@ InfernoApp* inferno_create() InfernoApp* app = new InfernoApp; // app->Input = new InfernoInput; // app->Scene = scene::scene_create(); - // app->MainTimer = inferno_timer_create(); - // + app->MainTimer = inferno_timer_create(); + // graphics::camera_set_position(app->Scene->Camera, { 0.0f, 1.0f, 3.1f }); - // + // // Create window graphics::window_create("Inferno v" INFERNO_VERSION, 1280, 720); - // + + // // setup the scene // scene::Material* basicMaterial = new scene::Material("basic"); // graphics::Shader* basicShader = graphics::shader_create(); @@ -225,106 +227,105 @@ bool inferno_pre(InfernoApp* app) void inferno_end(InfernoApp* app) { - } int inferno_run(InfernoApp* app) { while (true) { - // inferno_timer_start(app->MainTimer); - // if (!inferno_pre(app)) - // break; - // - // if (glm::length(app->Input->MouseDelta) > 0.0f) - // graphics::camera_mouse_move(app->Scene->Camera, app->Input->MouseDelta); - // if (app->Input->MovementDelta != 0b00000000) - // graphics::camera_move(app->Scene->Camera, app->Input->MovementDelta); - // - // // Menu Bar - // static bool showPreview = true; - // static bool showRenderSettings = true; - // static bool showDemoWindow = false; - // if (ImGui::BeginMenuBar()) { - // if (ImGui::BeginMenu("Menu")) { - // ImGui::EndMenu(); - // } - // if (ImGui::BeginMenu("View")) { - // ImGui::Checkbox("Show Preview", &showPreview); - // ImGui::SameLine(); - // inferno_gui_help_marker("Show the preview window"); - // ImGui::Checkbox("Show Settings", &showRenderSettings); - // ImGui::SameLine(); - // inferno_gui_help_marker("Show the Inferno HART settings window"); - // ImGui::Checkbox("Show Demo", &showDemoWindow); - // - // ImGui::EndMenu(); - // } - // ImGui::EndMenuBar(); - // } - // - // if (showRenderSettings && ImGui::Begin("Inferno HART")) { - // if (ImGui::TreeNode("Camera")) { - // graphics::Camera* camera = scene::scene_get_camera(app->Scene); - // graphics::camera_draw_ui(camera); - // ImGui::TreePop(); - // } - // if (ImGui::TreeNode("Preview Render")) { - // ImGui::Checkbox("Show Preview", &showPreview); - // graphics::preview_draw_ui(app->PreviewRenderer); - // if (ImGui::TreeNode("Debug Overlay")) { - // graphics::debug_draw_ui(); - // ImGui::TreePop(); - // } - // ImGui::TreePop(); - // } - // if (ImGui::TreeNode("RayTraced Render")) { - // graphics::rayr_draw_ui(app->RayRenderer); - // ImGui::TreePop(); - // } - // ImGui::End(); - // } - // - // if (showPreview && ImGui::Begin("Preview", nullptr, ImGuiWindowFlags_NoScrollbar)) { - // if (ImGui::IsWindowHovered()) { - // inferno_move_input(app, inferno_timer_get_time(app->MainTimer)); - // } else { - // inferno_stop_move_input(app); - // } - // - // graphics::camera_raster_set_viewport(scene::scene_get_camera(app->Scene), - // { ImGui::GetWindowSize().x, ImGui::GetWindowSize().y }); - // graphics::preview_set_viewport(app->PreviewRenderer, app->Scene->Camera); - // - // graphics::preview_draw(app->PreviewRenderer, app->Scene); - // graphics::debug_draw_to_target(app->Scene); - // - // ImTextureID texture = (ImTextureID)graphics::preview_get_rendered_texture(app->PreviewRenderer); - // ImGui::Image( - // texture, - // { ImGui::GetWindowSize().x, ImGui::GetWindowSize().y }, - // ImVec2(0, 1), ImVec2(1, 0)); - // - // ImGui::End(); - // } - // - // if (ImGui::Begin("Render")) { - // graphics::rayr_draw(app->RayRenderer); - // - // ImTextureID texture = (ImTextureID)graphics::rayr_get_rendered_texture(app->RayRenderer); - // ImGui::Image( - // texture, - // { ImGui::GetWindowSize().x, ImGui::GetWindowSize().y }, - // ImVec2(0, 1), ImVec2(1, 0)); - // ImGui::End(); - // } - // - // if (showDemoWindow) { - // ImGui::ShowDemoWindow(); - // } - // + // inferno_timer_start(app->MainTimer); + // if (!inferno_pre(app)) + // break; + // + // if (glm::length(app->Input->MouseDelta) > 0.0f) + // graphics::camera_mouse_move(app->Scene->Camera, app->Input->MouseDelta); + // if (app->Input->MovementDelta != 0b00000000) + // graphics::camera_move(app->Scene->Camera, app->Input->MovementDelta); + // + // // Menu Bar + // static bool showPreview = true; + // static bool showRenderSettings = true; + // static bool showDemoWindow = false; + // if (ImGui::BeginMenuBar()) { + // if (ImGui::BeginMenu("Menu")) { + // ImGui::EndMenu(); + // } + // if (ImGui::BeginMenu("View")) { + // ImGui::Checkbox("Show Preview", &showPreview); + // ImGui::SameLine(); + // inferno_gui_help_marker("Show the preview window"); + // ImGui::Checkbox("Show Settings", &showRenderSettings); + // ImGui::SameLine(); + // inferno_gui_help_marker("Show the Inferno HART settings window"); + // ImGui::Checkbox("Show Demo", &showDemoWindow); + // + // ImGui::EndMenu(); + // } + // ImGui::EndMenuBar(); + // } + // + // if (showRenderSettings && ImGui::Begin("Inferno HART")) { + // if (ImGui::TreeNode("Camera")) { + // graphics::Camera* camera = scene::scene_get_camera(app->Scene); + // graphics::camera_draw_ui(camera); + // ImGui::TreePop(); + // } + // if (ImGui::TreeNode("Preview Render")) { + // ImGui::Checkbox("Show Preview", &showPreview); + // graphics::preview_draw_ui(app->PreviewRenderer); + // if (ImGui::TreeNode("Debug Overlay")) { + // graphics::debug_draw_ui(); + // ImGui::TreePop(); + // } + // ImGui::TreePop(); + // } + // if (ImGui::TreeNode("RayTraced Render")) { + // graphics::rayr_draw_ui(app->RayRenderer); + // ImGui::TreePop(); + // } + // ImGui::End(); + // } + // + // if (showPreview && ImGui::Begin("Preview", nullptr, ImGuiWindowFlags_NoScrollbar)) { + // if (ImGui::IsWindowHovered()) { + // inferno_move_input(app, inferno_timer_get_time(app->MainTimer)); + // } else { + // inferno_stop_move_input(app); + // } + // + // graphics::camera_raster_set_viewport(scene::scene_get_camera(app->Scene), + // { ImGui::GetWindowSize().x, ImGui::GetWindowSize().y }); + // graphics::preview_set_viewport(app->PreviewRenderer, app->Scene->Camera); + // + // graphics::preview_draw(app->PreviewRenderer, app->Scene); + // graphics::debug_draw_to_target(app->Scene); + // + // ImTextureID texture = (ImTextureID)graphics::preview_get_rendered_texture(app->PreviewRenderer); + // ImGui::Image( + // texture, + // { ImGui::GetWindowSize().x, ImGui::GetWindowSize().y }, + // ImVec2(0, 1), ImVec2(1, 0)); + // + // ImGui::End(); + // } + // + // if (ImGui::Begin("Render")) { + // graphics::rayr_draw(app->RayRenderer); + // + // ImTextureID texture = (ImTextureID)graphics::rayr_get_rendered_texture(app->RayRenderer); + // ImGui::Image( + // texture, + // { ImGui::GetWindowSize().x, ImGui::GetWindowSize().y }, + // ImVec2(0, 1), ImVec2(1, 0)); + // ImGui::End(); + // } + // + // if (showDemoWindow) { + // ImGui::ShowDemoWindow(); + // } + // graphics::window_render(); inferno_end(app); - // inferno_timer_end(app->MainTimer); + // inferno_timer_end(app->MainTimer); } // return 1; diff --git a/src/window.cpp b/src/window.cpp index 88f6d7c..fbc2ff6 100644 --- a/src/window.cpp +++ b/src/window.cpp @@ -2,13 +2,15 @@ #include "gui/style.hpp" -#include #include +#include #include "yolo/yolo.hpp" #include +#include #include +#include namespace inferno::graphics { @@ -17,9 +19,6 @@ static KeyCallback UserKeyCallback = nullptr; static int Width, Height; static GLFWwindow* Window; -static VkInstance VulkanInstance; -static VkPhysicalDevice VulkanPhysicalDevice = VK_NULL_HANDLE; - void glfwKeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods) { @@ -33,40 +32,6 @@ void glfwErrorCallback(int error, const char* description) yolo::error("[GLFW {}] {}", error, description); } -struct QueueFamilyIndices { - std::optional graphicsFamily; - - bool isComplete() { - return graphicsFamily.has_value(); - } -}; - -QueueFamilyIndices findQueueFamilies(VkPhysicalDevice device) -{ - QueueFamilyIndices indices; - - uint32_t queueFamilyCount = 0; - vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, nullptr); - - std::vector queueFamilies(queueFamilyCount); - vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, queueFamilies.data()); - - int i = 0; - for (const auto& queueFamily : queueFamilies) { - if (queueFamily.queueFlags & VK_QUEUE_GRAPHICS_BIT) { - indices.graphicsFamily = i; - } - - if (indices.isComplete()) { - break; - } - - i++; - } - - return indices; -} - void setupGLFW(std::string title) { glfwSetErrorCallback(glfwErrorCallback); @@ -84,6 +49,11 @@ void setupGLFW(std::string title) if (Window == NULL) throw std::runtime_error("Could not create window"); + if (!glfwVulkanSupported()) { + yolo::error("Vulkan not supported"); + exit(1); + } + // Vulkan Init VkApplicationInfo appInfo {}; appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; @@ -99,10 +69,13 @@ void setupGLFW(std::string title) uint32_t glfwExtCount = 0; const char** exts = glfwGetRequiredInstanceExtensions(&ext); + // add VK_KHR_xcb_surface to the list of extensions + // TODO: This is a massive fuck off hack - SOLVE IT!!!! + exts[glfwExtCount++] = "VK_KHR_xcb_surface"; instInfo.enabledExtensionCount = glfwExtCount; instInfo.ppEnabledExtensionNames = exts; instInfo.enabledLayerCount = 0; - yolo::info("GLFW requested {} extensions: {}", glfwExtCount, exts); + yolo::info("GLFW requested {} extensions: {}", glfwExtCount, exts[0]); if (vkCreateInstance(&instInfo, nullptr, &VulkanInstance) != VK_SUCCESS) { yolo::error("Could not create Vulkan instance"); @@ -120,14 +93,45 @@ void setupGLFW(std::string title) std::vector devices(deviceCount); vkEnumeratePhysicalDevices(VulkanInstance, &deviceCount, devices.data()); + // TODO: We need to do device suitability in a much better way + const std::vector deviceExtensions { + VK_KHR_SWAPCHAIN_EXTENSION_NAME, + }; + for (const auto& device : devices) { - VkPhysicalDeviceProperties deviceProperties; - vkGetPhysicalDeviceProperties(device, &deviceProperties); - VkPhysicalDeviceFeatures deviceFeatures; - vkGetPhysicalDeviceFeatures(device, &deviceFeatures); - yolo::info("Found Vulkan device: {}", deviceProperties.deviceName); - if (deviceProperties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU - && deviceFeatures.geometryShader) { + const auto& checkDevExtensions = [&]() -> bool { + uint32_t extensionCount; + vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionCount, nullptr); + + std::vector availableExtensions(extensionCount); + vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionCount, availableExtensions.data()); + + std::set requiredExtensions(deviceExtensions.begin(), deviceExtensions.end()); + + for (const auto& extension : availableExtensions) { + requiredExtensions.erase(extension.extensionName); + } + + return requiredExtensions.empty(); + }; + + const auto& isDeviceSuitable + = [&]() -> bool { + VkPhysicalDeviceProperties deviceProperties; + vkGetPhysicalDeviceProperties(device, &deviceProperties); + VkPhysicalDeviceFeatures deviceFeatures; + vkGetPhysicalDeviceFeatures(device, &deviceFeatures); + yolo::info("Found Vulkan device: {}", deviceProperties.deviceName); + + bool features = deviceProperties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU && deviceFeatures.geometryShader; + + QueueFamilyIndices indices = window_get_queue_families(device); + bool extensions = checkDevExtensions(); + + return indices.isComplete() && extensions && features; + }; + + if (isDeviceSuitable()) { VulkanPhysicalDevice = device; break; } @@ -139,19 +143,25 @@ void setupGLFW(std::string title) } // Logical Device - QueueFamilyIndices indices = findQueueFamilies(VulkanPhysicalDevice); - VkDeviceQueueCreateInfo queueCreateInfo {}; - queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; - queueCreateInfo.queueFamilyIndex = indices.graphicsFamily.value(); - queueCreateInfo.queueCount = 1; + QueueFamilyIndices indices = window_get_queue_families(VulkanPhysicalDevice); + std::vector queueCreateInfos; + std::set uniqueQueueFamilies = { indices.graphicsFamily.value(), indices.presentFamily.value() }; + float queuePriority = 1.0f; - queueCreateInfo.pQueuePriorities = &queuePriority; + for (uint32_t queueFamily : uniqueQueueFamilies) { + VkDeviceQueueCreateInfo queueCreateInfo {}; + queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; + queueCreateInfo.queueFamilyIndex = queueFamily; + queueCreateInfo.queueCount = 1; + queueCreateInfo.pQueuePriorities = &queuePriority; + queueCreateInfos.push_back(queueCreateInfo); + } VkPhysicalDeviceFeatures deviceFeatures {}; VkDeviceCreateInfo createInfo {}; createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; - createInfo.pQueueCreateInfos = &queueCreateInfo; - createInfo.queueCreateInfoCount = 1; + createInfo.queueCreateInfoCount = static_cast(queueCreateInfos.size()); + createInfo.pQueueCreateInfos = queueCreateInfos.data(); createInfo.pEnabledFeatures = &deviceFeatures; createInfo.enabledExtensionCount = 0; createInfo.enabledLayerCount = 0; @@ -161,9 +171,18 @@ void setupGLFW(std::string title) exit(1); } + vkGetDeviceQueue(VulkanDevice, indices.graphicsFamily.value(), 0, &VulkanPresentQueue); + VkPhysicalDeviceProperties deviceProperties; vkGetPhysicalDeviceProperties(VulkanPhysicalDevice, &deviceProperties); yolo::info("Vulkan running on ", deviceProperties.deviceName); + + // "Surface" creation + VkResult result = glfwCreateWindowSurface(VulkanInstance, Window, nullptr, &VulkanSurface); + if (result != VK_SUCCESS) { + yolo::error("Could not create Vulkan surface (code: {})", result); + exit(1); + } } void setupImGui() @@ -246,6 +265,8 @@ void window_create(std::string title, int width, int height) void window_cleanup() { + vkDestroySurfaceKHR(VulkanInstance, VulkanSurface, nullptr); + vkDestroyInstance(VulkanInstance, nullptr); vkDestroyDevice(VulkanDevice, nullptr); shutdownGLFW(); } @@ -268,6 +289,41 @@ glm::vec2 window_get_size() { return { Width, Height }; } void window_get_pos(int& x, int& y) { glfwGetWindowPos(Window, &x, &y); } +// VULKAN SPECIFIC +QueueFamilyIndices window_get_queue_families(VkPhysicalDevice device) +{ + QueueFamilyIndices indices; + + uint32_t queueFamilyCount = 0; + vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, nullptr); + + std::vector queueFamilies(queueFamilyCount); + vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, queueFamilies.data()); + + int i = 0; + for (const auto& queueFamily : queueFamilies) { + if (queueFamily.queueFlags & VK_QUEUE_GRAPHICS_BIT) { + indices.graphicsFamily = i; + } + + VkBool32 presentSupport = false; + vkGetPhysicalDeviceSurfaceSupportKHR(device, i, VulkanSurface, &presentSupport); + + if (presentSupport) { + indices.presentFamily = i; + } + + if (indices.isComplete()) { + break; + } + + i++; + } + + return indices; +} +// END VULKAN SPECIFIC + GLFWwindow* window_get_glfw_window() { return Window; } void window_set_mode(WINDOW_MODE mode) diff --git a/src/window.hpp b/src/window.hpp index 4773b6b..43325df 100644 --- a/src/window.hpp +++ b/src/window.hpp @@ -1,9 +1,10 @@ #pragma once -#include - #include "graphics.hpp" +#include +#include + #define WINDOW_FLAGS ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoNavFocus | ImGuiWindowFlags_MenuBar | ImGuiWindowFlags_NoBackground | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoCollapse namespace inferno::graphics { @@ -11,13 +12,27 @@ namespace inferno::graphics { typedef void (*KeyCallback)(int key, int scan, int action, int mod); typedef void (*MouseCallback)(double x, double y); +static VkInstance VulkanInstance; +static VkPhysicalDevice VulkanPhysicalDevice = VK_NULL_HANDLE; static VkDevice VulkanDevice; +static VkQueue VulkanPresentQueue; +static VkSurfaceKHR VulkanSurface; enum WINDOW_MODE { WIN_MODE_DEFAULT, WIN_MODE_FPS, }; +struct QueueFamilyIndices { + std::optional graphicsFamily; + std::optional presentFamily; + + bool isComplete() + { + return graphicsFamily.has_value() && presentFamily.has_value(); + } +}; + void window_create(std::string title, int width, int height); void window_cleanup(); @@ -28,6 +43,10 @@ void window_set_pos(int x, int y); glm::vec2 window_get_size(); void window_get_pos(int& x, int& y); +// VULKAN SPECIFIC +QueueFamilyIndices window_get_queue_families(VkPhysicalDevice device); +// END VULKAN SPECIFIC + GLFWwindow* window_get_glfw_window(); void window_set_mode(WINDOW_MODE mode);