#pragma once #include "vertex.hpp" #include #include #include #define VULKAN_HPP_NO_CONSTRUCTORS #define VULKAN_HPP_NO_EXCEPTIONS #include #ifdef GZ_UTIL_STRING_CONCEPTS static_assert(false, "gz-util/util/string_conversion.hpp is included before vulkan_util.hpp!"); #endif template concept VkToString = requires(const T& t) { { vk::to_string(t) }; }; template inline std::string toString(const T& t) { return vk::to_string(t); } namespace gz::vlk { /** * @name Convenience structs * @details * Structures and functionas making usiing the vulkan api more convenient * @{ */ /** * @brief Struct containing all physical device features structs * @details * Make sure to call vkGetPhysicalDeviceFeatures2 with the f member, not this struct itself * @todo Redo with vulkan.hpp and vk::StructureChain */ struct PhysicalDeviceFeatures { /** * @brief Initialize the structs with sType and pNext chain f -> f11 -> f12 -> f13 */ PhysicalDeviceFeatures(); VkPhysicalDeviceFeatures2 f {}; VkPhysicalDeviceVulkan11Features f11{}; VkPhysicalDeviceVulkan12Features f12{}; VkPhysicalDeviceVulkan13Features f13{}; /** * @brief Check if all features enabled in requiredFeatures are enabled in this */ bool requiredFeaturesAvailable(const PhysicalDeviceFeatures& requiredFeatures) const; }; enum PipelineT { PL_3D, PL_2D }; struct Pipeline { vk::Pipeline pipeline; vk::PipelineLayout layout; void operator=(const Pipeline& other) = delete; }; /** * @brief Map holding pipelines */ class PipelineContainer { public: using iterator = std::unordered_map::iterator; Pipeline& operator[](const PipelineT& key) { return pipelines[key]; } /** * @brief Destroy the pipeline+layout and then remove the handles from the underlying map */ void erase(const PipelineT& key, const vk::Device& device, const vk::AllocationCallbacks* pAllocator=nullptr); /** * @brief Destroy the pipeline+layout and then remove the handles from the underlying map */ iterator erase(const iterator& it, const vk::Device& device, const vk::AllocationCallbacks* pAllocator=nullptr); /** * @brief Destroy all pipelines#layouts and then remove the handles from the underlying map */ void destroy(const vk::Device& device, const vk::AllocationCallbacks* pAllocator=nullptr); iterator begin() { return pipelines.begin(); } iterator end() { return pipelines.end(); } size_t size() const { return pipelines.size(); } private: std::unordered_map pipelines; }; struct SwapChainSupport { vk::SurfaceCapabilities2KHR capabilities; std::vector formats; std::vector presentModes; }; template concept SupportedIndexType = std::same_as or std::same_as; template struct VerticesAndIndices { std::vector vertices; std::vector indices; constexpr vk::IndexType getIndexType() const { if (std::same_as) { return vk::IndexType::eUint16; } else if (std::same_as) { return vk::IndexType::eUint32; } } }; struct QueueFamilyIndices { std::optional graphicsFamily; std::optional presentFamily; std::optional transferFamily; bool hasNecessaryValues() { return graphicsFamily.has_value() && presentFamily.has_value(); } bool hasAllValues() { return graphicsFamily.has_value() && presentFamily.has_value() && transferFamily.has_value(); } std::string toString() const { std::string s = "[ "; s += "graphicsFamily: "; if (graphicsFamily.has_value()) { s += std::to_string(graphicsFamily.value()); } else { s += "not set"; } s += ", presentFamily: "; if (presentFamily.has_value()) { s += std::to_string(presentFamily.value()); } else { s += "not set"; } s += ", transferFamily: "; if (transferFamily.has_value()) { s += std::to_string(transferFamily.value()); } else { s += "not set"; } return s + " ]"; } }; /** * @brief Get a vk::DependencyInfo struct for a single image memory barrier */ vk::DependencyInfo getDepInfo(const vk::ImageMemoryBarrier2& barrier); /** * @brief Fill bufMeqReq and memReq * @details * Fill the structs and call vkGetBufferMemoryRequirements2() */ /* void getBufferMemoryRequirements(const vk::Device& device, const vk::Buffer& buffer, vk::BufferMemoryRequirementsInfo2& bufMemReq, vk::MemoryRequirements2& memReq); */ /** * @brief Fill imMemReq and memReq * @details * Fill the structs and call vkGetImageMemoryRequirements2() */ /* void getImageMemoryRequirements(const vk::Device& device, const vk::Image& image, vk::ImageMemoryRequirementsInfo2& imMemReq, vk::MemoryRequirements2& memReq); */ /// @} /** * @brief Used for debugging * @see VulkanInstance::debugLog * @details * Handles like vk::Device are pointers to the actual handle. * Register the handle to a vulkan object with this struct and call updateHandles(). * The handles set will then contain the actual address of the handle, as printed by the validation layers. * That means you can check a handle returned by a validation layer * with this struct and see if this handle belongs to object that created this struct. * @warning * Every pointer you submit to this must stay valid! * Use this struct only when debugging! */ struct ObjectUsingVulkan { ObjectUsingVulkan(std::string&& name, std::vector&& ptrsToHandles, std::vector&& vectorWithPtrsToHandles); std::string objectName; std::vector ptrToHandle; std::vector*> vectorWithPtrToHandle; std::set handles; /** * @brief Update the handles map with the current handle (aka segfault generator) */ void updateHandles(); }; /** * @brief Check if all required extensions are available */ template bool areExtensionsAvailable(const RE& requiredExtensions, const AE& availableExtensions) requires std::same_as, const char*&> and std::same_as, vk::ExtensionProperties&> { bool extensionAvailable; for (const auto& requiredExtension : requiredExtensions) { extensionAvailable = false; for (const auto& extension : availableExtensions) { if (strcmp(requiredExtension, extension.extensionName) == 0) { extensionAvailable = true; break; } } if (!extensionAvailable) { return false; } } return true; } /** * @file * @brief Various utility structs and functions, as well as toString() overload for vk objects */ } // namespace gz::vlk