.. _program_listing_file_Source_Azura_RenderSystem_Src_Vulkan_VkCore.cpp: Program Listing for File VkCore.cpp =================================== |exhale_lsh| :ref:`Return to documentation for file ` (``Source\Azura\RenderSystem\Src\Vulkan\VkCore.cpp``) .. |exhale_lsh| unicode:: U+021B0 .. UPWARDS ARROW WITH TIP LEFTWARDS .. code-block:: cpp #include "Vulkan/VkCore.h" #include "Generic/Constants.h" #include #include #include #include "Memory/MemoryFactory.h" #include "Memory/MonotonicAllocator.h" #include "Memory/StackMemoryBuffer.h" #include "Memory/HeapMemoryBuffer.h" #include "Vulkan/VkMacros.h" #include "Vulkan/VkTypeMapping.h" #include "Vulkan/VkScopedBuffer.h" #include "Vulkan/VkScopedSwapChain.h" #ifdef BUILD_DEBUG #include #endif using ContainerExtent = Azura::Containers::ContainerExtent; namespace Azura { namespace Vulkan { namespace { #ifdef BUILD_DEBUG const std::array VALIDATION_LAYERS = { "VK_LAYER_LUNARG_standard_validation" }; VKAPI_ATTR VkBool32 VKAPI_CALL DebugReportCallback( VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objType, uint64_t obj, size_t location, int32_t code, const char* layerPrefix, const char* msg, void* userData) { UNUSED(userData); UNUSED(layerPrefix); UNUSED(code); UNUSED(location); UNUSED(obj); UNUSED(objType); UNUSED(flags); std::cout << "[VkRenderer] Validation layer: " << msg << std::endl; return VK_FALSE; } #endif const std::array DEVICE_EXTENSIONS = {VK_KHR_SWAPCHAIN_EXTENSION_NAME}; bool CheckValidationLayerSupport() { #ifdef BUILD_DEBUG HEAP_ALLOCATOR(Temporary, Memory::MonotonicAllocator, 16384); U32 layerCount = 0; vkEnumerateInstanceLayerProperties(&layerCount, nullptr); Containers::Vector availableLayers(ContainerExtent{layerCount}, allocatorTemporary); vkEnumerateInstanceLayerProperties(&layerCount, availableLayers.Data()); for (const char* layer : VALIDATION_LAYERS) { bool layerFound = false; for (const auto& vkLayer : availableLayers) { if (strcmp(layer, &vkLayer.layerName[0]) == 0) { // NOLINT layerFound = true; break; } } if (!layerFound) { return false; } } #endif return true; } bool CheckDeviceExtensionSupport(VkPhysicalDevice device) { U32 extensionCount = 0; const U32 maxExtensionCount = 128; HEAP_ALLOCATOR(Extension, Memory::MonotonicAllocator, sizeof(VkExtensionProperties) * maxExtensionCount) vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionCount, nullptr); Containers::Vector availableExtensions(ContainerExtent{extensionCount, maxExtensionCount}, allocatorExtension); vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionCount, availableExtensions.Data()); for (const auto& requiredExtension : DEVICE_EXTENSIONS) { bool foundExtension = false; for (const auto& availableExtension : availableExtensions) { if (strcmp(&availableExtension.extensionName[0], requiredExtension) == 0) { foundExtension = true; break; } } if (!foundExtension) { return false; } } return true; } void LogDeviceFeatures(VkPhysicalDeviceFeatures features, const Log& log_VulkanRenderSystem) { UNUSED(features); UNUSED(log_VulkanRenderSystem); LOG_DBG(log_VulkanRenderSystem, LOG_LEVEL, "Robust Buffer Access: %d", features.robustBufferAccess); LOG_DBG(log_VulkanRenderSystem, LOG_LEVEL, "Full Draw Index Uint32: %d", features.fullDrawIndexUint32); LOG_DBG(log_VulkanRenderSystem, LOG_LEVEL, "Image Cube Array: %d", features.imageCubeArray); LOG_DBG(log_VulkanRenderSystem, LOG_LEVEL, "Independent Blend: %d", features.independentBlend); LOG_DBG(log_VulkanRenderSystem, LOG_LEVEL, "Geometry Shader: %d", features.geometryShader); LOG_DBG(log_VulkanRenderSystem, LOG_LEVEL, "Tessellation Shader: %d", features.tessellationShader); LOG_DBG(log_VulkanRenderSystem, LOG_LEVEL, "Sample Rate Shading: %d", features.sampleRateShading); LOG_DBG(log_VulkanRenderSystem, LOG_LEVEL, "Dual Src Blend: %d", features.dualSrcBlend); LOG_DBG(log_VulkanRenderSystem, LOG_LEVEL, "Logic Op: %d", features.logicOp); LOG_DBG(log_VulkanRenderSystem, LOG_LEVEL, "Multi Draw Indirect: %d", features.multiDrawIndirect); LOG_DBG(log_VulkanRenderSystem, LOG_LEVEL, "Draw Indirect First Instance: %d", features.drawIndirectFirstInstance); LOG_DBG(log_VulkanRenderSystem, LOG_LEVEL, "Depth Clamp: %d", features.depthClamp); LOG_DBG(log_VulkanRenderSystem, LOG_LEVEL, "Depth Bias Clamp: %d", features.depthBiasClamp); LOG_DBG(log_VulkanRenderSystem, LOG_LEVEL, "Fill Mode Non Solid: %d", features.fillModeNonSolid); LOG_DBG(log_VulkanRenderSystem, LOG_LEVEL, "Depth Bounds: %d", features.depthBounds); LOG_DBG(log_VulkanRenderSystem, LOG_LEVEL, "Wide Lines: %d", features.wideLines); LOG_DBG(log_VulkanRenderSystem, LOG_LEVEL, "Large Points: %d", features.largePoints); LOG_DBG(log_VulkanRenderSystem, LOG_LEVEL, "Alpha To One: %d", features.alphaToOne); LOG_DBG(log_VulkanRenderSystem, LOG_LEVEL, "Multi Viewport: %d", features.multiViewport); LOG_DBG(log_VulkanRenderSystem, LOG_LEVEL, "Sampler Anisotropy: %d", features.samplerAnisotropy); LOG_DBG(log_VulkanRenderSystem, LOG_LEVEL, "Texture Compression ETC 2: %d", features.textureCompressionETC2); LOG_DBG(log_VulkanRenderSystem, LOG_LEVEL, "Texture Compression ASTC LDR: %d", features.textureCompressionASTC_LDR); LOG_DBG(log_VulkanRenderSystem, LOG_LEVEL, "texture Compression BC: %d", features.textureCompressionBC); LOG_DBG(log_VulkanRenderSystem, LOG_LEVEL, "Occlusion Query Precise: %d", features.occlusionQueryPrecise); LOG_DBG(log_VulkanRenderSystem, LOG_LEVEL, "Pipeline Statistics Query: %d", features.pipelineStatisticsQuery); LOG_DBG(log_VulkanRenderSystem, LOG_LEVEL, "Vertex Pipeline Stores And Atomics: %d", features. vertexPipelineStoresAndAtomics); LOG_DBG(log_VulkanRenderSystem, LOG_LEVEL, "Fragment Stores And Atomics: %d", features.fragmentStoresAndAtomics); LOG_DBG(log_VulkanRenderSystem, LOG_LEVEL, "Shader Tessellation And Geometry Point Size: %d", features. shaderTessellationAndGeometryPointSize); LOG_DBG(log_VulkanRenderSystem, LOG_LEVEL, "Shader Image Gather Extended: %d", features.shaderImageGatherExtended); LOG_DBG(log_VulkanRenderSystem, LOG_LEVEL, "Shader Storage Image Extended Formats: %d", features. shaderStorageImageExtendedFormats); LOG_DBG(log_VulkanRenderSystem, LOG_LEVEL, "Shader Storage Image Multisample: %d", features. shaderStorageImageMultisample); LOG_DBG(log_VulkanRenderSystem, LOG_LEVEL, "Shader StorageImageRead Without Format: %d", features. shaderStorageImageReadWithoutFormat); LOG_DBG(log_VulkanRenderSystem, LOG_LEVEL, "Shader Storage ImageWrite Without Format: %d", features. shaderStorageImageWriteWithoutFormat); LOG_DBG(log_VulkanRenderSystem, LOG_LEVEL, "Shader Uniform Buffer Array Dynamic Indexing: %d", features. shaderUniformBufferArrayDynamicIndexing); LOG_DBG(log_VulkanRenderSystem, LOG_LEVEL, "Shader Sampled Image Array Dynamic Indexing: %d", features. shaderSampledImageArrayDynamicIndexing); LOG_DBG(log_VulkanRenderSystem, LOG_LEVEL, "Shader Storage Buffer Array Dynamic Indexing: %d", features. shaderStorageBufferArrayDynamicIndexing); LOG_DBG(log_VulkanRenderSystem, LOG_LEVEL, "Shader Storage Image Array Dynamic Indexing: %d", features. shaderStorageImageArrayDynamicIndexing); LOG_DBG(log_VulkanRenderSystem, LOG_LEVEL, "Shader Clip Distance: %d", features.shaderClipDistance); LOG_DBG(log_VulkanRenderSystem, LOG_LEVEL, "Shader Cull Distance: %d", features.shaderCullDistance); LOG_DBG(log_VulkanRenderSystem, LOG_LEVEL, "Shader Float64: %d", features.shaderFloat64); LOG_DBG(log_VulkanRenderSystem, LOG_LEVEL, "Shader Int64: %d", features.shaderInt64); LOG_DBG(log_VulkanRenderSystem, LOG_LEVEL, "Shader Int16: %d", features.shaderInt16); LOG_DBG(log_VulkanRenderSystem, LOG_LEVEL, "Shader Resource Residency: %d", features.shaderResourceResidency); LOG_DBG(log_VulkanRenderSystem, LOG_LEVEL, "ShaderResource Min Lod: %d", features.shaderResourceMinLod); LOG_DBG(log_VulkanRenderSystem, LOG_LEVEL, "Sparse Binding: %d", features.sparseBinding); LOG_DBG(log_VulkanRenderSystem, LOG_LEVEL, "Sparse Residency Buffer: %d", features.sparseResidencyBuffer); LOG_DBG(log_VulkanRenderSystem, LOG_LEVEL, "Sparse Residency Image2 D: %d", features.sparseResidencyImage2D); LOG_DBG(log_VulkanRenderSystem, LOG_LEVEL, "Sparse Residency Image3 D: %d", features.sparseResidencyImage3D); LOG_DBG(log_VulkanRenderSystem, LOG_LEVEL, "Sparse Residency2 Samples: %d", features.sparseResidency2Samples); LOG_DBG(log_VulkanRenderSystem, LOG_LEVEL, "Sparse Residency4 Samples: %d", features.sparseResidency4Samples); LOG_DBG(log_VulkanRenderSystem, LOG_LEVEL, "Sparse Residency8 Samples: %d", features.sparseResidency8Samples); LOG_DBG(log_VulkanRenderSystem, LOG_LEVEL, "Sparse Residency16 Samples: %d", features.sparseResidency16Samples); LOG_DBG(log_VulkanRenderSystem, LOG_LEVEL, "Sparse Residency Aliased: %d", features.sparseResidencyAliased); LOG_DBG(log_VulkanRenderSystem, LOG_LEVEL, "Variable Multisample Rate: %d", features.variableMultisampleRate); LOG_DBG(log_VulkanRenderSystem, LOG_LEVEL, "Inherited Queries: %d", features.inheritedQueries); } int GetDeviceScore(VkPhysicalDevice device, VkSurfaceKHR surface, const DeviceRequirements& requirements, const SwapChainDeviceSupport& swapChainSupport, const Log& log_VulkanRenderSystem) { int score = 0; VkPhysicalDeviceProperties deviceProperties; VkPhysicalDeviceFeatures deviceFeatures; vkGetPhysicalDeviceProperties(device, &deviceProperties); vkGetPhysicalDeviceFeatures(device, &deviceFeatures); LOG_DBG(log_VulkanRenderSystem, LOG_LEVEL, "Device Info: Device: %s", deviceProperties.deviceName); LOG_DBG(log_VulkanRenderSystem, LOG_LEVEL, "Device ID: %d", deviceProperties.deviceID); LOG_DBG(log_VulkanRenderSystem, LOG_LEVEL, "API Version: %d", deviceProperties.apiVersion); LOG_DBG(log_VulkanRenderSystem, LOG_LEVEL, "Driver Version: %d", deviceProperties.driverVersion); LOG_DBG(log_VulkanRenderSystem, LOG_LEVEL, "Device Type: %s", VkPhysicalDeviceTypeToString(deviceProperties.deviceType )); LOG_DBG(log_VulkanRenderSystem, LOG_LEVEL, "Vendor ID: %d", deviceProperties.vendorID); LOG_DBG(log_VulkanRenderSystem, LOG_LEVEL, "Device Features: Device: %s", deviceProperties.deviceName); LogDeviceFeatures(deviceFeatures, log_VulkanRenderSystem); const VkQueueIndices indices = VkCore::FindQueueFamiliesInDevice(device, surface, requirements, log_VulkanRenderSystem); const bool areExtensionsSupported = CheckDeviceExtensionSupport(device); if (!areExtensionsSupported) { return 0; } const bool isSwapChainSupported = swapChainSupport.IsSupported(); if (!isSwapChainSupported) { return 0; } if (!indices.IsComplete()) { return 0; } if (requirements.m_float64 && deviceFeatures.shaderFloat64 == 0u) { return 0; } if (requirements.m_int64 && deviceFeatures.shaderInt64 == 0u) { return 0; } if (requirements.m_discreteGPU && deviceProperties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU) { score += 1000; } return score; } } // namespace #ifdef BUILD_DEBUG VkResult VkCore::CreateDebugReportCallbackEXT(VkInstance instance, const VkDebugReportCallbackCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDebugReportCallbackEXT* pCallback) { // NOLINTNEXTLINE auto func = reinterpret_cast( vkGetInstanceProcAddr(instance, "vkCreateDebugReportCallbackEXT")); if (func != nullptr) { return func(instance, pCreateInfo, pAllocator, pCallback); } return VK_ERROR_EXTENSION_NOT_PRESENT; } void VkCore::DestroyDebugReportCallbackEXT(VkInstance instance, VkDebugReportCallbackEXT callback, const VkAllocationCallbacks* pAllocator) { // NOLINTNEXTLINE auto func = reinterpret_cast( vkGetInstanceProcAddr(instance, "vkDestroyDebugReportCallbackEXT")); if (func != nullptr) { func(instance, callback, pAllocator); } } VkDebugReportCallbackEXT VkCore::SetupDebug(VkInstance instance, const Log& log_VulkanRenderSystem) { // Attach callback since we have validation turned on VkDebugReportCallbackCreateInfoEXT createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT; createInfo.flags = VK_DEBUG_REPORT_WARNING_BIT_EXT | VK_DEBUG_REPORT_ERROR_BIT_EXT; createInfo.pfnCallback = DebugReportCallback; VkDebugReportCallbackEXT callback; VERIFY_VK_OP(log_VulkanRenderSystem, CreateDebugReportCallbackEXT(instance, &createInfo, nullptr, &callback), "Failed to create Debug Callback"); return callback; } #endif VkInstance VkCore::CreateInstance(const ApplicationInfo& applicationData, const Containers::Vector& vkExtensions, const Log& log_VulkanRenderSystem) { VkApplicationInfo appInfo = {}; appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; appInfo.pApplicationName = applicationData.m_name.c_str(); const U32 majorVer = std::get(applicationData.m_version); const U32 minorVer = std::get(applicationData.m_version); const U32 patchVer = std::get(applicationData.m_version); appInfo.applicationVersion = VK_MAKE_VERSION(majorVer, minorVer, patchVer); appInfo.pEngineName = "Azura"; appInfo.engineVersion = VK_MAKE_VERSION(RENDER_SYSTEM_MAJOR_SEMVER, RENDER_SYSTEM_MINOR_SEMVER, RENDER_SYSTEM_PATCH_SEMVER); appInfo.apiVersion = VK_API_VERSION_1_1; VkInstanceCreateInfo createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; createInfo.pApplicationInfo = &appInfo; createInfo.enabledExtensionCount = vkExtensions.GetSize(); createInfo.ppEnabledExtensionNames = vkExtensions.Data(); LOG_DBG(log_VulkanRenderSystem, LOG_LEVEL, "Instance Creation: Loading Device Extensions"); for (const auto& extension : vkExtensions) { // TODO(vasumahesh1):[PERF]: Check compiler optimization here UNUSED(extension); LOG_DBG(log_VulkanRenderSystem, LOG_LEVEL, "= Instance Extensions: %s", extension); } // Validation Layers Check VERIFY_TRUE(log_VulkanRenderSystem, CheckValidationLayerSupport(), "Validation layers requested, but not available on device"); #ifdef BUILD_DEBUG createInfo.enabledLayerCount = U32(VALIDATION_LAYERS.size()); createInfo.ppEnabledLayerNames = VALIDATION_LAYERS.data(); #else createInfo.enabledLayerCount = 0; createInfo.ppEnabledLayerNames = nullptr; #endif VkInstance result; VERIFY_VK_OP(log_VulkanRenderSystem, vkCreateInstance(&createInfo, nullptr, &result), "Failed to create VkInstance"); return result; } VkQueueIndices VkCore::FindQueueFamiliesInDevice(VkPhysicalDevice device, VkSurfaceKHR surface, const DeviceRequirements& requirements, const Log& log_VulkanRenderSystem) { VkQueueIndices result; result.m_isTransferQueueRequired = requirements.m_transferQueue; UNUSED(log_VulkanRenderSystem); const U32 maxQueueFamilies = 4; STACK_ALLOCATOR(QueueFamily, Memory::MonotonicAllocator, sizeof(VkQueueFamilyProperties) * maxQueueFamilies) U32 queueFamilyCount; vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, nullptr); Containers::Vector queueFamilies(ContainerExtent{queueFamilyCount, maxQueueFamilies}, allocatorQueueFamily); vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, queueFamilies.Data()); int idx = 0; for (const auto& queueFamily : queueFamilies) { if (queueFamily.queueCount > 0 && (queueFamily.queueFlags & VK_QUEUE_GRAPHICS_BIT) != 0) { LOG_DBG(log_VulkanRenderSystem, LOG_LEVEL, "Found Graphics Queue At: %d", idx); result.m_graphicsFamily = idx; } if (queueFamily.queueCount > 0 && !((queueFamily.queueFlags & VK_QUEUE_GRAPHICS_BIT) != 0) && (queueFamily.queueFlags & VK_QUEUE_TRANSFER_BIT) != 0) { LOG_DBG(log_VulkanRenderSystem, LOG_LEVEL, "Found Transfer Queue At (was Required): %d", idx); result.m_transferFamily = idx; } VkBool32 canPresent = 0u; vkGetPhysicalDeviceSurfaceSupportKHR(device, idx, surface, &canPresent); if (queueFamily.queueCount > 0 && canPresent != 0u) { LOG_DBG(log_VulkanRenderSystem, LOG_LEVEL, "Found Present Queue At: %d", idx); result.m_presentFamily = idx; } ++idx; } return result; } SwapChainDeviceSupport VkCore::QuerySwapChainSupport(VkPhysicalDevice device, VkSurfaceKHR surface, Memory::Allocator& allocator) { SwapChainDeviceSupport result(allocator); vkGetPhysicalDeviceSurfaceCapabilitiesKHR(device, surface, &result.m_capabilities); U32 formatCount = 0; vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &formatCount, nullptr); if (formatCount > 0) { result.m_formats.Resize(formatCount); vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &formatCount, result.m_formats.Data()); } U32 presentCount = 0; vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, &presentCount, nullptr); if (presentCount > 0) { result.m_presentModes.Resize(presentCount); vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, &presentCount, result.m_presentModes.Data()); } return result; } VkPhysicalDevice VkCore::SelectPhysicalDevice(VkInstance instance, VkSurfaceKHR surface, const DeviceRequirements& requirements, const Log& log_VulkanRenderSystem) { VkPhysicalDevice physicalDevice = VK_NULL_HANDLE; // Query for Available Devices U32 availableDeviceCount = 0; vkEnumeratePhysicalDevices(instance, &availableDeviceCount, nullptr); VERIFY_TRUE(log_VulkanRenderSystem, availableDeviceCount != 0, "No supported GPUs found with Vulkan"); const U32 maxDevices = 4; STACK_ALLOCATOR(Device, Memory::MonotonicAllocator, sizeof(VkPhysicalDevice) * maxDevices); STACK_ALLOCATOR(SwapChainSupport, Memory::MonotonicAllocator, 2048); Containers::Vector availableDevices(ContainerExtent{availableDeviceCount, maxDevices}, allocatorDevice); vkEnumeratePhysicalDevices(instance, &availableDeviceCount, availableDevices.Data()); std::multimap candidates; // Rate and Select the best GPU for (const auto& device : availableDevices) { const auto swapChainSupport = QuerySwapChainSupport(device, surface, allocatorSwapChainSupport); int tempScore = GetDeviceScore(device, surface, requirements, swapChainSupport, log_VulkanRenderSystem); candidates.insert(std::make_pair(tempScore, device)); } if (candidates.rbegin()->first > 0) { physicalDevice = candidates.rbegin()->second; } #ifdef BUILD_DEBUG VkPhysicalDeviceProperties deviceProperties; VkPhysicalDeviceFeatures deviceFeatures; vkGetPhysicalDeviceProperties(physicalDevice, &deviceProperties); vkGetPhysicalDeviceFeatures(physicalDevice, &deviceFeatures); LOG_DBG(log_VulkanRenderSystem, LOG_LEVEL, "[SELECTED DEVICE] Device Info: Device: %s", deviceProperties.deviceName); LOG_DBG(log_VulkanRenderSystem, LOG_LEVEL, "Device ID: %d", deviceProperties.deviceID); LOG_DBG(log_VulkanRenderSystem, LOG_LEVEL, "API Version: %d", deviceProperties.apiVersion); LOG_DBG(log_VulkanRenderSystem, LOG_LEVEL, "Driver Version: %d", deviceProperties.driverVersion); LOG_DBG(log_VulkanRenderSystem, LOG_LEVEL, "Device Type: %s", VkPhysicalDeviceTypeToString(deviceProperties.deviceType )); LOG_DBG(log_VulkanRenderSystem, LOG_LEVEL, "Vendor ID: %d", deviceProperties.vendorID); LOG_DBG(log_VulkanRenderSystem, LOG_LEVEL, "Device Features: Device: %s", deviceProperties.deviceName); LogDeviceFeatures(deviceFeatures, log_VulkanRenderSystem); #endif VERIFY_TRUE(log_VulkanRenderSystem, physicalDevice != VK_NULL_HANDLE, "No suitable GPU found for Vulkan"); return physicalDevice; } VkDevice VkCore::CreateLogicalDevice(VkPhysicalDevice physicalDevice, const VkQueueIndices& queueIndices, const DeviceRequirements& requirements, const Log& log_VulkanRenderSystem) { // Create Queue Infos const std::set uniqueQueueFamilies = { queueIndices.m_graphicsFamily, queueIndices.m_presentFamily, queueIndices.m_transferFamily }; const U32 maxQueueFamilies = 3; STACK_ALLOCATOR(QueueCreateInfo, Memory::MonotonicAllocator, sizeof(VkDeviceQueueCreateInfo) * maxQueueFamilies) // TODO(vasumahesh1): Simplify with Azura::Vector Containers::Vector queueCreateInfos(maxQueueFamilies, allocatorQueueCreateInfo); float queuePriority = 1.0f; for (const auto& queueIdx : uniqueQueueFamilies) { VkDeviceQueueCreateInfo queueCreateInfo = {}; queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; queueCreateInfo.queueFamilyIndex = queueIdx; queueCreateInfo.queueCount = 1; queueCreateInfo.pQueuePriorities = &queuePriority; queueCreateInfos.PushBack(queueCreateInfo); } VkPhysicalDeviceFeatures deviceFeatures = {}; deviceFeatures.shaderFloat64 = requirements.m_float64 ? VK_TRUE : VK_FALSE; deviceFeatures.shaderInt64 = requirements.m_int64 ? VK_TRUE : VK_FALSE; // Create the logical device VkDeviceCreateInfo createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; createInfo.pQueueCreateInfos = queueCreateInfos.Data(); createInfo.queueCreateInfoCount = queueCreateInfos.GetSize(); createInfo.pEnabledFeatures = &deviceFeatures; createInfo.enabledExtensionCount = U32(DEVICE_EXTENSIONS.size()); createInfo.ppEnabledExtensionNames = DEVICE_EXTENSIONS.data(); LOG_DBG(log_VulkanRenderSystem, LOG_LEVEL, "Device Creation: Loading Device Extensions"); for (const auto& extension : DEVICE_EXTENSIONS) { // TODO(vasumahesh1):[PERF]: Check compiler optimization here UNUSED(extension); LOG_DBG(log_VulkanRenderSystem, LOG_LEVEL, "= Device Extensions: %s", extension); } #ifdef BUILD_DEBUG LOG_DBG(log_VulkanRenderSystem, LOG_LEVEL, "Device Creation: Loading Device Validation Layers"); for (const auto& layer : VALIDATION_LAYERS) { LOG_DBG(log_VulkanRenderSystem, LOG_LEVEL, "= Validation Layer: %s", layer); } createInfo.enabledLayerCount = U32(VALIDATION_LAYERS.size()); createInfo.ppEnabledLayerNames = VALIDATION_LAYERS.data(); #else createInfo.enabledLayerCount = 0; createInfo.ppEnabledLayerNames = nullptr; #endif VkDevice device; VERIFY_VK_OP(log_VulkanRenderSystem, vkCreateDevice(physicalDevice, &createInfo, nullptr, &device), "Failed to create VkDevice"); LOG_DBG(log_VulkanRenderSystem, LOG_LEVEL, "Created VkDevice Successfully"); return device; } VkQueue VkCore::GetQueueFromDevice(VkDevice device, int queueIndex) { VkQueue queue; vkGetDeviceQueue(device, queueIndex, 0, &queue); return queue; } VkImage VkCore::CreateImage(VkDevice device, RawStorageFormat format, ImageType imageType, const Bounds2D& bounds, U32 depth, U32 layers, U32 mips, VkImageTiling tiling, VkImageUsageFlags imageUsage, const Log& log_VulkanRenderSystem) { const auto imageFormat = ToVkFormat(format); VERIFY_OPT(log_VulkanRenderSystem, imageFormat, "Unknown Format"); const auto vkImageType = ToVkImageType(imageType); VERIFY_OPT(log_VulkanRenderSystem, vkImageType, "Unknown Image Type"); assert(bounds.m_width > 0); assert(bounds.m_height > 0); assert(depth > 0); assert(layers > 0); assert(mips > 0); VkImageCreateInfo createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; createInfo.imageType = vkImageType.value(); // Note that vkCmdBlitImage (if supported) will also do format conversions if the swapchain color format would differ createInfo.format = imageFormat.value(); createInfo.extent.width = bounds.m_width; createInfo.extent.height = bounds.m_height; createInfo.extent.depth = depth; createInfo.arrayLayers = layers; createInfo.mipLevels = mips; createInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; createInfo.samples = VK_SAMPLE_COUNT_1_BIT; createInfo.tiling = tiling; createInfo.usage = imageUsage; createInfo.flags = 0; // TODO(vasumahesh1):[TEXTURE]: Add support for Cube Maps VkImage resultImage; VERIFY_VK_OP(log_VulkanRenderSystem, vkCreateImage(device, &createInfo, nullptr, &resultImage), "Failed to Create Image"); return resultImage; } VkImageView VkCore::CreateImageView(VkDevice device, VkImage sourceImage, VkImageViewType viewType, VkFormat viewFormat, VkImageAspectFlags aspectMask, const Log& log_VulkanRenderSystem, U32 baseMip, U32 levelCount, U32 baseArrayLayer, U32 layerCount) { VkImageViewCreateInfo createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; createInfo.image = sourceImage; createInfo.viewType = viewType; createInfo.format = viewFormat; // TODO(vasumahesh1):[TEXTURE]: Add Swizzle support // Default Swizzle createInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY; createInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY; createInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY; createInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY; // Which part of image to access createInfo.subresourceRange.aspectMask = aspectMask; createInfo.subresourceRange.baseMipLevel = baseMip; createInfo.subresourceRange.levelCount = levelCount; createInfo.subresourceRange.baseArrayLayer = baseArrayLayer; createInfo.subresourceRange.layerCount = layerCount; VkImageView imageView; VERIFY_VK_OP(log_VulkanRenderSystem, vkCreateImageView(device, &createInfo, nullptr, &imageView), "Failed to create image view"); return imageView; } // TODO(vasumahesh1):[PIPELINE]: Needs serious changes here VkRenderPass VkCore::CreateRenderPass(VkDevice device, const VkScopedSwapChain& swapChain, const Log& log_VulkanRenderSystem) { VkAttachmentDescription colorAttachment = {}; colorAttachment.format = swapChain.GetSurfaceFormat(); colorAttachment.samples = VK_SAMPLE_COUNT_1_BIT; colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; // Not using Stencil buffer colorAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; colorAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; colorAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; colorAttachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; VkAttachmentDescription depthAttachment = {}; depthAttachment.format = swapChain.GetDepthFormat(); depthAttachment.samples = VK_SAMPLE_COUNT_1_BIT; depthAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; depthAttachment.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; depthAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; depthAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; depthAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; depthAttachment.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; VkAttachmentReference colorAttachmentRef = {}; colorAttachmentRef.attachment = 0; colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; VkAttachmentReference depthAttachmentRef = {}; depthAttachmentRef.attachment = 1; depthAttachmentRef.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; VkSubpassDescription subpass = {}; subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; subpass.colorAttachmentCount = 1; subpass.pColorAttachments = &colorAttachmentRef; subpass.pDepthStencilAttachment = &depthAttachmentRef; std::array attachments = {colorAttachment, depthAttachment}; VkRenderPassCreateInfo renderPassInfo = {}; renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; renderPassInfo.attachmentCount = U32(attachments.size()); renderPassInfo.pAttachments = attachments.data(); renderPassInfo.subpassCount = 1; renderPassInfo.pSubpasses = &subpass; // Tell special subpass to wait for Image acquisition from semaphore VkSubpassDependency dependency = {}; dependency.srcSubpass = VK_SUBPASS_EXTERNAL; dependency.dstSubpass = 0; dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; dependency.srcAccessMask = 0; dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; renderPassInfo.dependencyCount = 1; renderPassInfo.pDependencies = &dependency; VkRenderPass renderPass; VERIFY_VK_OP(log_VulkanRenderSystem, vkCreateRenderPass(device, &renderPassInfo, nullptr, &renderPass), "Failed to create render pass"); return renderPass; } void VkCore::CreateUniformBufferBinding(Containers::Vector& bindings, const U32 binding, const U32 count, VkShaderStageFlags stageFlag) { VkDescriptorSetLayoutBinding uboLayoutBinding = {}; uboLayoutBinding.binding = binding; uboLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; uboLayoutBinding.descriptorCount = count; uboLayoutBinding.stageFlags = stageFlag; uboLayoutBinding.pImmutableSamplers = nullptr; bindings.PushBack(std::move(uboLayoutBinding)); } void VkCore::CreateSamplerBinding(Containers::Vector& bindings, U32 binding, U32 count, VkShaderStageFlags stageFlag) { VkDescriptorSetLayoutBinding uboLayoutBinding = {}; uboLayoutBinding.binding = binding; uboLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER; uboLayoutBinding.descriptorCount = count; uboLayoutBinding.stageFlags = stageFlag; uboLayoutBinding.pImmutableSamplers = nullptr; bindings.PushBack(std::move(uboLayoutBinding)); } void VkCore::CreateSampledImageBinding(Containers::Vector& bindings, U32 binding, U32 count, VkShaderStageFlags stageFlag) { VkDescriptorSetLayoutBinding uboLayoutBinding = {}; uboLayoutBinding.binding = binding; uboLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; uboLayoutBinding.descriptorCount = count; uboLayoutBinding.stageFlags = stageFlag; uboLayoutBinding.pImmutableSamplers = nullptr; bindings.PushBack(std::move(uboLayoutBinding)); } void VkCore::CreateCombinedImageSamplerBinding(Containers::Vector& bindings, U32 binding, U32 count, VkShaderStageFlags stageFlag) { VkDescriptorSetLayoutBinding uboLayoutBinding = {}; uboLayoutBinding.binding = binding; uboLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; uboLayoutBinding.descriptorCount = count; uboLayoutBinding.stageFlags = stageFlag; uboLayoutBinding.pImmutableSamplers = nullptr; bindings.PushBack(std::move(uboLayoutBinding)); } VkDescriptorSetLayout VkCore::CreateDescriptorSetLayout( VkDevice device, const Containers::Vector& bindings, const Log& log_VulkanRenderSystem) { VkDescriptorSetLayoutCreateInfo layoutInfo = {}; layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; layoutInfo.bindingCount = bindings.GetSize(); layoutInfo.pBindings = bindings.Data(); VkDescriptorSetLayout descriptorSet; VERIFY_VK_OP(log_VulkanRenderSystem, vkCreateDescriptorSetLayout(device, &layoutInfo, nullptr, &descriptorSet), "Failed to create descriptor set layout"); return descriptorSet; } VkPipelineLayout VkCore::CreatePipelineLayout(VkDevice device, const Containers::Vector& descriptorSets, const Log& log_VulkanRenderSystem) { VkPipelineLayoutCreateInfo pipelineLayoutInfo = {}; pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; // Descriptors Info pipelineLayoutInfo.pSetLayouts = descriptorSets.Data(); pipelineLayoutInfo.setLayoutCount = descriptorSets.GetSize(); VkPipelineLayout pipelineLayout; VERIFY_VK_OP(log_VulkanRenderSystem, vkCreatePipelineLayout(device, &pipelineLayoutInfo, nullptr, &pipelineLayout), "Failed to create pipeline layout"); return pipelineLayout; } VkShaderModule VkCore::CreateShaderModule(VkDevice device, const Containers::Vector& code, const Log& log_VulkanRenderSystem) { VkShaderModuleCreateInfo createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; createInfo.codeSize = code.GetSize(); // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) createInfo.pCode = reinterpret_cast(code.Data()); // byte code ptr conversion VkShaderModule shaderModule; VERIFY_VK_OP(log_VulkanRenderSystem, vkCreateShaderModule(device, &createInfo, nullptr, &shaderModule), "Failed to create shader module"); return shaderModule; } Containers::Vector VkCore::CreateFrameBuffers(VkDevice device, VkRenderPass renderPass, const VkScopedSwapChain& scopedSwapChain, Memory::Allocator& allocator, const Log& log_VulkanRenderSystem) { const auto& allImages = scopedSwapChain.GetAllImages(); const auto swapChainExtent = scopedSwapChain.GetExtent(); Containers::Vector frameBuffers(ContainerExtent{allImages.GetSize()}, allocator); for (U32 idx = 0; idx < allImages.GetSize(); ++idx) { const std::array attachments = {allImages[idx].View()}; VkFramebufferCreateInfo framebufferInfo = {}; framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; framebufferInfo.renderPass = renderPass; framebufferInfo.attachmentCount = U32(attachments.size()); framebufferInfo.pAttachments = attachments.data(); framebufferInfo.width = swapChainExtent.width; framebufferInfo.height = swapChainExtent.height; framebufferInfo.layers = 1; VERIFY_VK_OP(log_VulkanRenderSystem, vkCreateFramebuffer(device, &framebufferInfo, nullptr, &frameBuffers[idx]), "Failed to create framebuffer"); } return frameBuffers; } void VkCore::CreateFrameBuffers(VkDevice device, VkRenderPass renderPass, const VkScopedSwapChain& scopedSwapChain, Containers::Vector& frameBuffers, const Log& log_VulkanRenderSystem) { const auto& allImages = scopedSwapChain.GetAllImages(); const auto swapChainExtent = scopedSwapChain.GetExtent(); frameBuffers.Resize(allImages.GetSize()); VkImageView depthImageView = scopedSwapChain.GetDepthImage().View(); for (U32 idx = 0; idx < allImages.GetSize(); ++idx) { const std::array attachments = {allImages[idx].View(), depthImageView}; VkFramebufferCreateInfo framebufferInfo = {}; framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; framebufferInfo.renderPass = renderPass; framebufferInfo.attachmentCount = U32(attachments.size()); framebufferInfo.pAttachments = attachments.data(); framebufferInfo.width = swapChainExtent.width; framebufferInfo.height = swapChainExtent.height; framebufferInfo.layers = 1; VERIFY_VK_OP(log_VulkanRenderSystem, vkCreateFramebuffer(device, &framebufferInfo, nullptr, &frameBuffers[idx]), "Failed to create framebuffer"); } } VkCommandPool VkCore::CreateCommandPool(VkDevice device, int queueIndex, VkCommandPoolCreateFlags flags, const Log& log_VulkanRenderSystem) { VkCommandPoolCreateInfo poolInfo = {}; poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; poolInfo.queueFamilyIndex = queueIndex; poolInfo.flags = flags; VkCommandPool commandPool; VERIFY_VK_OP(log_VulkanRenderSystem, vkCreateCommandPool(device, &poolInfo, nullptr, &commandPool), "Failed to create command pool"); return commandPool; } U32 VkCore::FindMemoryType(U32 typeFilter, VkMemoryPropertyFlags properties, const VkPhysicalDeviceMemoryProperties& physicalDeviceMemoryProperties) { // TODO(vasumahesh1): Fix this warning for (U32 idx = 0; idx < physicalDeviceMemoryProperties.memoryTypeCount; ++idx) { if (((typeFilter & (1 << idx)) != 0u) // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-constant-array-index) && ((physicalDeviceMemoryProperties.memoryTypes[idx].propertyFlags & properties) == properties)) { return idx; } } throw std::runtime_error("Failed to find suitable memory type"); } VkDescriptorPoolSize VkCore::CreateDescriptorPoolSize(VkDescriptorType type, U32 descriptorCount) { VkDescriptorPoolSize poolSize; poolSize.type = type; poolSize.descriptorCount = descriptorCount; return poolSize; } VkDescriptorPool VkCore::CreateDescriptorPool(VkDevice device, const Containers::Vector& pools, U32 maxSets, const Log& log_VulkanRenderSystem) { VkDescriptorPoolCreateInfo poolInfo = {}; poolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; poolInfo.poolSizeCount = pools.GetSize(); poolInfo.pPoolSizes = pools.Data(); poolInfo.maxSets = maxSets; VkDescriptorPool descriptorPool; VERIFY_VK_OP(log_VulkanRenderSystem, vkCreateDescriptorPool(device, &poolInfo, nullptr, &descriptorPool), "Failed to create descriptor pool"); return descriptorPool; } VkDescriptorSet VkCore::CreateDescriptorSet(VkDevice device, VkDescriptorPool descriptorPool, const Containers::Vector& descriptorSets, const Log& log_VulkanRenderSystem) { VkDescriptorSetAllocateInfo allocInfo = {}; allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; allocInfo.descriptorPool = descriptorPool; allocInfo.descriptorSetCount = descriptorSets.GetSize(); allocInfo.pSetLayouts = descriptorSets.Data(); VkDescriptorSet descriptorSet; VERIFY_VK_OP(log_VulkanRenderSystem, vkAllocateDescriptorSets(device, &allocInfo, &descriptorSet), "Failed to allocate descriptor set"); return descriptorSet; } VkWriteDescriptorSet VkCore::CreateWriteDescriptorForUniformBuffer( VkDescriptorSet set, U32 layoutIndex, U32 binding, const Containers::Vector& bufferInfos) { VkWriteDescriptorSet descriptorWrite = {}; descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; descriptorWrite.dstSet = set; descriptorWrite.dstArrayElement = layoutIndex; descriptorWrite.dstBinding = binding; descriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; // Attach Buffer Info to WriteDescriptorSet descriptorWrite.descriptorCount = bufferInfos.GetSize(); descriptorWrite.pBufferInfo = bufferInfos.Data(); descriptorWrite.pImageInfo = nullptr; descriptorWrite.pTexelBufferView = nullptr; return descriptorWrite; } void VkCore::UpdateDescriptorSets(VkDevice device, const Containers::Vector& descriptorWrites) { vkUpdateDescriptorSets(device, U32(descriptorWrites.GetSize()), descriptorWrites.Data(), 0, nullptr); } VkCommandBuffer VkCore::CreateCommandBuffer(VkDevice device, VkCommandPool commandPool, VkCommandBufferLevel level, const Log& log_VulkanRenderSystem) { VkCommandBuffer commandBuffer; VkCommandBufferAllocateInfo allocInfo = {}; allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; allocInfo.commandPool = commandPool; allocInfo.level = level; allocInfo.commandBufferCount = 1; VERIFY_VK_OP(log_VulkanRenderSystem, vkAllocateCommandBuffers(device, &allocInfo, &commandBuffer), "Failed to allocate command buffers"); return commandBuffer; } Containers::Vector VkCore::CreateCommandBuffers( VkDevice device, U32 count, VkCommandPool commandPool, VkCommandBufferLevel level, Memory::Allocator& allocator, const Log& log_VulkanRenderSystem) { Containers::Vector commandBuffers(ContainerExtent{count}, allocator); CreateCommandBuffers(device, commandPool, level, commandBuffers, log_VulkanRenderSystem); return commandBuffers; } void VkCore::CreateCommandBuffers(VkDevice device, VkCommandPool commandPool, VkCommandBufferLevel level, Containers::Vector& commandBuffers, const Log& log_VulkanRenderSystem) { VkCommandBufferAllocateInfo allocInfo = {}; allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; allocInfo.commandPool = commandPool; allocInfo.level = level; allocInfo.commandBufferCount = commandBuffers.GetSize(); VERIFY_VK_OP(log_VulkanRenderSystem, vkAllocateCommandBuffers(device, &allocInfo, commandBuffers.Data()), "Failed to create command buffers"); } void VkCore::BeginCommandBuffer(VkCommandBuffer buffer, VkCommandBufferUsageFlags flags, const Log& log_VulkanRenderSystem) { VkCommandBufferBeginInfo beginInfo = {}; beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; beginInfo.flags = flags; beginInfo.pInheritanceInfo = nullptr; VERIFY_VK_OP(log_VulkanRenderSystem, vkBeginCommandBuffer(buffer, &beginInfo), "Failed to begin recording command buffer"); } void VkCore::BeginCommandBuffer(VkCommandBuffer buffer, VkCommandBufferUsageFlags flags, const VkCommandBufferInheritanceInfo& inheritanceInfo, const Log& log_VulkanRenderSystem) { VkCommandBufferBeginInfo beginInfo = {}; beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; beginInfo.flags = flags; beginInfo.pInheritanceInfo = &inheritanceInfo; VERIFY_VK_OP(log_VulkanRenderSystem, vkBeginCommandBuffer(buffer, &beginInfo), "Failed to begin recording command buffer"); } void VkCore::EndCommandBuffer(VkCommandBuffer buffer, const Log& log_VulkanRenderSystem) { VERIFY_VK_OP(log_VulkanRenderSystem, vkEndCommandBuffer(buffer), "Failed to end recording command buffer"); } VkSemaphore VkCore::CreateSemaphore(VkDevice device, const Log& log_VulkanRenderSystem) { VkSemaphoreCreateInfo semaphoreInfo = {}; semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; VkSemaphore semaphore; VERIFY_VK_OP(log_VulkanRenderSystem, vkCreateSemaphore(device, &semaphoreInfo, nullptr, &semaphore), "Failed to create semaphore"); return semaphore; } void VkCore::CreateSemaphores(VkDevice device, U32 count, Containers::Vector& semaphores, const Log& log_VulkanRenderSystem) { VkSemaphoreCreateInfo semaphoreInfo = {}; semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; for (U32 idx = 0; idx < count; ++idx) { VERIFY_VK_OP(log_VulkanRenderSystem, vkCreateSemaphore(device, &semaphoreInfo, nullptr, &semaphores[idx]), "Failed to create semaphore [multi-create]"); } } Containers::Vector VkCore::CreateSemaphores(VkDevice device, U32 count, Memory::Allocator& allocator, const Log& log_VulkanRenderSystem) { Containers::Vector semaphores(ContainerExtent{count}, allocator); CreateSemaphores(device, count, semaphores, log_VulkanRenderSystem); return semaphores; } VkFence VkCore::CreateFence(VkDevice device, VkFenceCreateFlags flags, const Log& log_VulkanRenderSystem) { VkFenceCreateInfo fenceInfo = {}; fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; fenceInfo.flags = flags; VkFence fence; VERIFY_VK_OP(log_VulkanRenderSystem, vkCreateFence(device, &fenceInfo, nullptr, &fence), "Failed to create fence"); return fence; } void VkCore::CreateFences(VkDevice device, U32 count, VkFenceCreateFlags flags, Containers::Vector& fences, const Log& log_VulkanRenderSystem) { VkFenceCreateInfo fenceInfo = {}; fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; fenceInfo.flags = flags; for (U32 idx = 0; idx < count; ++idx) { VERIFY_VK_OP(log_VulkanRenderSystem, vkCreateFence(device, &fenceInfo, nullptr, &fences[idx]), "Failed to create fences [multi-create]"); } } Containers::Vector VkCore::CreateFences(VkDevice device, U32 count, VkFenceCreateFlags flags, Memory::Allocator& allocator, const Log& log_VulkanRenderSystem) { Containers::Vector fences(ContainerExtent{count}, allocator); CreateFences(device, count, flags, fences, log_VulkanRenderSystem); return fences; } void VkCore::CopyBuffer(VkDevice device, VkQueue queue, const VkScopedBuffer& srcBuffer, const VkScopedBuffer& dstBuffer, const VkDeviceSize size, const VkCommandPool commandPool) { VkCommandBufferAllocateInfo allocInfo = {}; allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; allocInfo.commandPool = commandPool; allocInfo.commandBufferCount = 1; VkCommandBuffer commandBuffer; vkAllocateCommandBuffers(device, &allocInfo, &commandBuffer); VkCommandBufferBeginInfo beginInfo = {}; beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; vkBeginCommandBuffer(commandBuffer, &beginInfo); VkBufferCopy copyRegion = {}; copyRegion.srcOffset = 0; copyRegion.dstOffset = 0; copyRegion.size = size; vkCmdCopyBuffer(commandBuffer, srcBuffer.Real(), dstBuffer.Real(), 1, ©Region); vkEndCommandBuffer(commandBuffer); VkSubmitInfo submitInfo = {}; submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; submitInfo.commandBufferCount = 1; submitInfo.pCommandBuffers = &commandBuffer; vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE); vkQueueWaitIdle(queue); vkFreeCommandBuffers(device, commandPool, 1, &commandBuffer); } void VkCore::TransitionImageLayout( VkCommandBuffer cmdBuffer, VkImage image, VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask, VkImageLayout oldImageLayout, VkImageLayout newImageLayout, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, VkImageSubresourceRange imageSubresourceRange) { VkImageMemoryBarrier imageMemoryBarrier{}; imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; imageMemoryBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; imageMemoryBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; imageMemoryBarrier.srcAccessMask = srcAccessMask; imageMemoryBarrier.dstAccessMask = dstAccessMask; imageMemoryBarrier.oldLayout = oldImageLayout; imageMemoryBarrier.newLayout = newImageLayout; imageMemoryBarrier.image = image; imageMemoryBarrier.subresourceRange = imageSubresourceRange; vkCmdPipelineBarrier( cmdBuffer, srcStageMask, dstStageMask, 0, 0, nullptr, 0, nullptr, 1, &imageMemoryBarrier ); } void VkCore::ImageBlit(VkCommandBuffer cmdBuffer, VkImage srcImage, VkImage dstImage, VkImageAspectFlagBits srcAspect, VkImageAspectFlagBits dstAspect, const Bounds3D& blitRegion, const LayerSubresource& srcLayerResource, const LayerSubresource& dstLayerResource, U32 srcMipLevel, U32 dstMipLevel, VkFilter blitFilter) { VkOffset3D blitSize; blitSize.x = blitRegion.m_width; blitSize.y = blitRegion.m_height; blitSize.z = blitRegion.m_depth; VkImageBlit imageBlitRegion{}; imageBlitRegion.srcSubresource.aspectMask = srcAspect; imageBlitRegion.srcSubresource.layerCount = srcLayerResource.m_layerCount; imageBlitRegion.srcSubresource.baseArrayLayer = srcLayerResource.m_baseLayer; imageBlitRegion.srcSubresource.mipLevel = srcMipLevel; imageBlitRegion.srcOffsets[1] = blitSize; imageBlitRegion.dstSubresource.aspectMask = dstAspect; imageBlitRegion.dstSubresource.layerCount = dstLayerResource.m_layerCount; imageBlitRegion.dstSubresource.baseArrayLayer = dstLayerResource.m_baseLayer; imageBlitRegion.dstSubresource.mipLevel = dstMipLevel; imageBlitRegion.dstOffsets[1] = blitSize; vkCmdBlitImage( cmdBuffer, srcImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dstImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &imageBlitRegion, blitFilter ); } void VkCore::ImageBlit(VkCommandBuffer cmdBuffer, VkImage srcImage, VkImage dstImage, VkImageAspectFlagBits srcAspect, VkImageAspectFlagBits dstAspect, const Bounds3D& blitRegion) { return ImageBlit(cmdBuffer, srcImage, dstImage, srcAspect, dstAspect, blitRegion, LayerSubresource{1, 0}, LayerSubresource{1, 0}, 0, 0, VK_FILTER_NEAREST); } void VkCore::ImageCopy( VkCommandBuffer cmdBuffer, VkImage srcImage, VkImage dstImage, const Containers::Vector& copyRegions ) { vkCmdCopyImage( cmdBuffer, srcImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dstImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, copyRegions.GetSize(), copyRegions.Data()); } VkImageCopy VkCore::GetImageCopyRegion( VkImageAspectFlagBits srcAspect, VkImageAspectFlagBits dstAspect, const Bounds3D& copyRegion, const TextureSubresource& srcSubresource, const TextureSubresource& dstSubresource) { VkImageCopy imageCopyRegion = {}; imageCopyRegion.srcSubresource.aspectMask = srcAspect; imageCopyRegion.srcSubresource.layerCount = srcSubresource.m_layerInfo.m_layerCount; imageCopyRegion.srcSubresource.baseArrayLayer = srcSubresource.m_layerInfo.m_baseLayer; imageCopyRegion.srcSubresource.mipLevel = srcSubresource.m_mipLevel; imageCopyRegion.dstSubresource.aspectMask = dstAspect; imageCopyRegion.dstSubresource.layerCount = dstSubresource.m_layerInfo.m_layerCount; imageCopyRegion.dstSubresource.baseArrayLayer = dstSubresource.m_layerInfo.m_baseLayer; imageCopyRegion.dstSubresource.mipLevel = dstSubresource.m_mipLevel; imageCopyRegion.extent.width = copyRegion.m_width; imageCopyRegion.extent.height = copyRegion.m_height; imageCopyRegion.extent.depth = copyRegion.m_depth; return imageCopyRegion; } void VkCore::ImageCopy( VkCommandBuffer cmdBuffer, VkImage srcImage, VkImage dstImage, VkImageAspectFlagBits srcAspect, VkImageAspectFlagBits dstAspect, const Bounds3D& copyRegion, const TextureSubresource& srcSubresource, const TextureSubresource& dstSubresource ) { STACK_ALLOCATOR(Temporary, Memory::MonotonicAllocator, 1024); Containers::Vector imageCopyRegions(1, allocatorTemporary); imageCopyRegions.PushBack(GetImageCopyRegion(srcAspect, dstAspect, copyRegion, srcSubresource, dstSubresource)); ImageCopy(cmdBuffer, srcImage, dstImage, imageCopyRegions); } void VkCore::ImageCopy( VkCommandBuffer cmdBuffer, VkImage srcImage, VkImage dstImage, VkImageAspectFlagBits srcAspect, VkImageAspectFlagBits dstAspect, const Bounds3D& copyRegion ) { STACK_ALLOCATOR(Temporary, Memory::MonotonicAllocator, 1024); Containers::Vector imageCopyRegions(1, allocatorTemporary); imageCopyRegions.PushBack(GetImageCopyRegion(srcAspect, dstAspect, copyRegion, {}, {})); ImageCopy(cmdBuffer, srcImage, dstImage, imageCopyRegions); } void VkCore::FlushCommandBuffer(VkDevice device, VkCommandBuffer cmdBuffer, VkQueue queue, const Log& log_VulkanRenderSystem) { EndCommandBuffer(cmdBuffer, log_VulkanRenderSystem); VkSubmitInfo submitInfo = {}; submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; submitInfo.commandBufferCount = 1; submitInfo.pCommandBuffers = &cmdBuffer; VkFence fence = CreateFence(device, VK_FENCE_CREATE_SIGNALED_BIT, log_VulkanRenderSystem); vkResetFences(device, 1, &fence); // Submit to the queue VERIFY_VK_OP(log_VulkanRenderSystem, vkQueueSubmit(queue, 1, &submitInfo, fence), "Flush Command Buffer: Failed to submit to queue"); // Wait for the fence to signal that command buffer has finished executing VERIFY_VK_OP(log_VulkanRenderSystem, vkWaitForFences(device, 1, &fence, VK_TRUE, std::numeric_limits::max()) , "Wait Fence failed"); vkDestroyFence(device, fence, nullptr); } bool VkCore::QueryFormatFeatureSupport(VkPhysicalDevice physicalDevice, VkFormat format, std::function queryFunction) { VkFormatProperties formatProps; vkGetPhysicalDeviceFormatProperties(physicalDevice, format, &formatProps); return queryFunction(formatProps); } VkFormat VkCore::GetVkFormat(RawStorageFormat rawFormat, const Log& log_VulkanRenderSystem) { const auto format = ToVkFormat(rawFormat); VERIFY_OPT(log_VulkanRenderSystem, format, "Unknown Format"); return format.value(); } } // namespace Vulkan } // namespace Azura