123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462 |
- #include "pch.h"
- #include "VulkanUtility.h"
- #include "WebRTCMacros.h"
- #ifndef _WIN32
- #define EXTERNAL_MEMORY_HANDLE_SUPPORTED_TYPE VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR
- #else
- #define EXTERNAL_MEMORY_HANDLE_SUPPORTED_TYPE VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR
- #endif
- namespace unity
- {
- namespace webrtc
- {
- #ifdef _WIN32
- static PFN_vkGetMemoryWin32HandleKHR vkGetMemoryWin32HandleKHR = nullptr;
- #endif
- static PFN_vkGetMemoryFdKHR vkGetMemoryFdKHR = nullptr;
- static PFN_vkGetPhysicalDeviceProperties2KHR vkGetPhysicalDeviceProperties2KHR = nullptr;
- bool VulkanUtility::FindMemoryTypeInto(
- const VkPhysicalDevice physicalDevice,
- uint32_t typeFilter,
- VkMemoryPropertyFlags properties,
- uint32_t* memoryTypeIndex)
- {
- VkPhysicalDeviceMemoryProperties memProperties;
- vkGetPhysicalDeviceMemoryProperties(physicalDevice, &memProperties);
- for (uint32_t i = 0; i < memProperties.memoryTypeCount; ++i)
- {
- // properties define special features of the memory, like being able to map so we can write to it from the
- // CPU.
- if ((typeFilter & (1 << i)) && (memProperties.memoryTypes[i].propertyFlags & properties) == properties)
- {
- *memoryTypeIndex = i;
- return true;
- }
- }
- return false;
- }
- //---------------------------------------------------------------------------------------------------------------------
- // initialLayout must be either VK_IMAGE_LAYOUT_UNDEFINED or VK_IMAGE_LAYOUT_PREINITIALIZED
- // We use VK_IMAGE_LAYOUT_UNDEFINED here.
- // Returns 0 when failed
- VkDeviceSize VulkanUtility::CreateImage(
- const VkPhysicalDevice physicalDevice,
- const VkDevice device,
- const VkAllocationCallbacks* allocator,
- const uint32_t width,
- const uint32_t height,
- const VkImageTiling tiling,
- const VkImageUsageFlags usage,
- const VkMemoryPropertyFlags properties,
- const VkFormat format,
- VkImage* image,
- VkDeviceMemory* imageMemory,
- bool exportHandle)
- {
- VkImageCreateInfo imageInfo = {};
- imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
- imageInfo.imageType = VK_IMAGE_TYPE_2D;
- imageInfo.extent.width = static_cast<uint32_t>(width);
- imageInfo.extent.height = static_cast<uint32_t>(height);
- imageInfo.extent.depth = 1;
- imageInfo.mipLevels = 1;
- imageInfo.arrayLayers = 1;
- imageInfo.format = format;
- imageInfo.tiling = tiling;
- imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
- imageInfo.usage = usage;
- imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
- imageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
- imageInfo.flags = 0; // Optional
- if (vkCreateImage(device, &imageInfo, allocator, image) != VK_SUCCESS)
- {
- return 0;
- }
- VkMemoryRequirements memRequirements;
- vkGetImageMemoryRequirements(device, *image, &memRequirements);
- VkMemoryAllocateInfo allocInfo = {};
- allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
- allocInfo.allocationSize = memRequirements.size;
- if (!VulkanUtility::FindMemoryTypeInto(
- physicalDevice, memRequirements.memoryTypeBits, properties, &allocInfo.memoryTypeIndex))
- {
- return 0;
- }
- VkExportMemoryAllocateInfoKHR exportInfo = {};
- if (exportHandle)
- {
- exportInfo.sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_KHR;
- exportInfo.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR;
- allocInfo.pNext = &exportInfo;
- }
- if (vkAllocateMemory(device, &allocInfo, allocator, imageMemory) != VK_SUCCESS)
- {
- return 0;
- }
- VULKAN_CHECK_FAILVALUE(vkBindImageMemory(device, *image, *imageMemory, 0), 0)
- return memRequirements.size;
- }
- //---------------------------------------------------------------------------------------------------------------------
- VkResult VulkanUtility::CreateImage(
- const VkPhysicalDevice physicalDevice,
- const VkDevice device,
- const VkAllocationCallbacks* allocator,
- const uint32_t width,
- const uint32_t height,
- const VkImageTiling tiling,
- const VkImageUsageFlags usage,
- const VkMemoryPropertyFlags properties,
- const VkFormat format,
- UnityVulkanImage* unityVulkanImage,
- bool exportHandle)
- {
- VkImageCreateInfo imageInfo = {};
- imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
- imageInfo.imageType = VK_IMAGE_TYPE_2D;
- imageInfo.extent.width = static_cast<uint32_t>(width);
- imageInfo.extent.height = static_cast<uint32_t>(height);
- imageInfo.extent.depth = 1;
- imageInfo.mipLevels = 1;
- imageInfo.arrayLayers = 1;
- imageInfo.format = format;
- imageInfo.tiling = tiling;
- imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
- imageInfo.usage = usage;
- imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
- imageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
- imageInfo.flags = 0; // Optional
- VkResult result = vkCreateImage(device, &imageInfo, allocator, &unityVulkanImage->image);
- if (result != VK_SUCCESS)
- {
- return result;
- }
- VkMemoryRequirements memRequirements;
- vkGetImageMemoryRequirements(device, unityVulkanImage->image, &memRequirements);
- VkMemoryAllocateInfo allocInfo = {};
- allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
- allocInfo.allocationSize = memRequirements.size;
- bool success = VulkanUtility::FindMemoryTypeInto(
- physicalDevice, memRequirements.memoryTypeBits, properties, &allocInfo.memoryTypeIndex);
- RTC_CHECK(success);
- VkExportMemoryAllocateInfoKHR exportInfo = {};
- if (exportHandle)
- {
- exportInfo.sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_KHR;
- exportInfo.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR;
- allocInfo.pNext = &exportInfo;
- }
- result = vkAllocateMemory(device, &allocInfo, allocator, &unityVulkanImage->memory.memory);
- if (result != VK_SUCCESS)
- {
- return result;
- }
- const VkDeviceSize memoryOffset = 0;
- result = vkBindImageMemory(device, unityVulkanImage->image, unityVulkanImage->memory.memory, memoryOffset);
- if (result != VK_SUCCESS)
- {
- return result;
- }
- unityVulkanImage->memory.offset = memoryOffset;
- unityVulkanImage->memory.size = memRequirements.size;
- unityVulkanImage->memory.flags = properties;
- unityVulkanImage->memory.memoryTypeIndex = allocInfo.memoryTypeIndex;
- unityVulkanImage->layout = imageInfo.initialLayout;
- unityVulkanImage->usage = imageInfo.usage;
- unityVulkanImage->format = imageInfo.format;
- unityVulkanImage->extent = imageInfo.extent;
- unityVulkanImage->tiling = imageInfo.tiling;
- unityVulkanImage->type = imageInfo.imageType;
- unityVulkanImage->samples = imageInfo.samples;
- unityVulkanImage->layers = static_cast<int>(imageInfo.arrayLayers);
- unityVulkanImage->mipCount = static_cast<int>(imageInfo.mipLevels);
- return VK_SUCCESS;
- }
- //---------------------------------------------------------------------------------------------------------------------
- // returns VK_NULL_HANDLE when failed
- VkImageView VulkanUtility::CreateImageView(
- const VkDevice device, const VkAllocationCallbacks* allocator, const VkImage image, const VkFormat format)
- {
- VkImageViewCreateInfo viewInfo = {};
- viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
- viewInfo.image = image;
- viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
- viewInfo.format = format;
- viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
- viewInfo.subresourceRange.baseMipLevel = 0;
- viewInfo.subresourceRange.levelCount = 1;
- viewInfo.subresourceRange.baseArrayLayer = 0;
- viewInfo.subresourceRange.layerCount = 1;
- viewInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
- viewInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
- viewInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
- viewInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
- VkImageView imageView = nullptr;
- if (vkCreateImageView(device, &viewInfo, allocator, &imageView) != VK_SUCCESS)
- {
- RTC_LOG(LS_INFO) << "Failed vkCreateImageView";
- return nullptr;
- }
- return imageView;
- }
- //---------------------------------------------------------------------------------------------------------------------
- // Requires VK_KHR_get_physical_device_properties2 extension
- bool VulkanUtility::GetPhysicalDeviceUUIDInto(
- VkInstance instance, VkPhysicalDevice phyDevice, std::array<uint8_t, VK_UUID_SIZE>* deviceUUID)
- {
- VkPhysicalDeviceIDPropertiesKHR deviceIDProps = {};
- deviceIDProps.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES_KHR;
- VkPhysicalDeviceProperties2KHR props = {};
- props.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHR;
- props.pNext = &deviceIDProps;
- vkGetPhysicalDeviceProperties2KHR(phyDevice, &props);
- std::memcpy(deviceUUID->data(), deviceIDProps.deviceUUID, VK_UUID_SIZE);
- return true;
- }
- bool VulkanUtility::LoadDeviceFunctions(const VkDevice device)
- {
- #ifndef _WIN32
- vkGetMemoryFdKHR = (PFN_vkGetMemoryFdKHR)vkGetDeviceProcAddr(device, "vkGetMemoryFdKHR");
- if (!vkGetMemoryFdKHR)
- {
- RTC_LOG(LS_INFO) << "Failed to retrieve vkGetMemoryFdKHR";
- return false;
- }
- #else
- vkGetMemoryWin32HandleKHR =
- (PFN_vkGetMemoryWin32HandleKHR)vkGetDeviceProcAddr(device, "vkGetMemoryWin32HandleKHR");
- if (!vkGetMemoryWin32HandleKHR)
- {
- RTC_LOG(LS_INFO) << "Failed to retrieve vkGetMemoryWin32HandleKHR";
- return false;
- }
- #endif
- return true;
- }
- bool VulkanUtility::LoadInstanceFunctions(const VkInstance instance)
- {
- vkGetPhysicalDeviceProperties2KHR =
- (PFN_vkGetPhysicalDeviceProperties2KHR)vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceProperties2KHR");
- if (vkGetPhysicalDeviceProperties2KHR == nullptr)
- {
- RTC_LOG(LS_INFO) << "Failed to retrieve vkGetPhysicalDeviceProperties2KHR";
- return false;
- }
- return true;
- }
- #ifndef _WIN32
- void* VulkanUtility::GetExportHandle(const VkDevice device, const VkDeviceMemory memory)
- {
- int fd = -1;
- VkMemoryGetFdInfoKHR fdInfo = {};
- fdInfo.sType = VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR;
- fdInfo.memory = memory;
- fdInfo.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR;
- VkResult result = vkGetMemoryFdKHR(device, &fdInfo, &fd);
- if (result != VK_SUCCESS)
- {
- RTC_LOG(LS_ERROR) << "vkGetMemoryFdKHR error" << result;
- return nullptr;
- }
- return (void*)(uintptr_t)fd;
- }
- #else
- void* VulkanUtility::GetExportHandle(const VkDevice device, const VkDeviceMemory memory)
- {
- HANDLE handle = nullptr;
- VkMemoryGetWin32HandleInfoKHR handleInfo = {};
- handleInfo.sType = VK_STRUCTURE_TYPE_MEMORY_GET_WIN32_HANDLE_INFO_KHR;
- handleInfo.memory = memory;
- handleInfo.handleType = EXTERNAL_MEMORY_HANDLE_SUPPORTED_TYPE;
- VkResult result = vkGetMemoryWin32HandleKHR(device, &handleInfo, &handle);
- if (result != VK_SUCCESS)
- {
- RTC_LOG(LS_ERROR) << "vkGetMemoryWin32HandleKHR error" << result;
- return nullptr;
- }
- return reinterpret_cast<void*>(handle);
- }
- #endif
- VkResult VulkanUtility::DoImageLayoutTransition(
- const VkCommandBuffer commandBuffer,
- const VkImage image,
- const VkFormat format,
- const VkImageLayout oldLayout,
- const VkPipelineStageFlags oldStage,
- const VkImageLayout newLayout,
- const VkPipelineStageFlags newStage)
- {
- VkImageMemoryBarrier barrier = {};
- barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
- barrier.oldLayout = oldLayout;
- barrier.newLayout = newLayout;
- barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; // for transferring queue family ownership
- barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
- barrier.image = image;
- barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
- barrier.subresourceRange.baseMipLevel = 0;
- barrier.subresourceRange.levelCount = 1; // No mip map
- barrier.subresourceRange.baseArrayLayer = 0;
- barrier.subresourceRange.layerCount = 1;
- switch (oldLayout)
- {
- case VK_IMAGE_LAYOUT_UNDEFINED:
- // undefined (or does not matter). Only valid as initial layout
- // No flags required.
- barrier.srcAccessMask = 0;
- break;
- case VK_IMAGE_LAYOUT_PREINITIALIZED:
- // Image is preinitialized. Only valid as initial layout for linear images, preserves memory contents
- // Make sure host writes have been finished
- barrier.srcAccessMask = VK_ACCESS_HOST_WRITE_BIT;
- break;
- case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
- // Image is a color attachment
- // Make sure any writes to the color buffer have been finished
- barrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
- break;
- case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL:
- // Image is a depth/stencil attachment
- // Make sure any writes to the depth/stencil buffer have been finished
- barrier.srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
- break;
- case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL:
- // Image is a transfer source
- // Make sure any reads from the image have been finished
- barrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
- break;
- case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
- // Image is a transfer destination
- // Make sure any writes to the image have been finished
- barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
- break;
- case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
- // Image is read by a shader
- // Make sure any shader reads from the image have been finished
- barrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT;
- break;
- default:
- // Other source layouts aren't handled (yet)
- break;
- }
- switch (newLayout)
- {
- case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
- // Image will be used as a transfer destination
- // Make sure any writes to the image have been finished
- barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
- break;
- case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL:
- // Image will be used as a transfer source
- // Make sure any reads from the image have been finished
- barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
- break;
- case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
- // Image will be used as a color attachment
- // Make sure any writes to the color buffer have been finished
- barrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
- break;
- case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL:
- // Image layout will be used as a depth/stencil attachment
- // Make sure any writes to depth/stencil buffer have been finished
- barrier.dstAccessMask = barrier.dstAccessMask | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
- break;
- case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
- // Image will be read in a shader (sampler, input attachment)
- // Make sure any writes to the image have been finished
- if (barrier.srcAccessMask == 0)
- {
- barrier.srcAccessMask = VK_ACCESS_HOST_WRITE_BIT | VK_ACCESS_TRANSFER_WRITE_BIT;
- }
- barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
- break;
- default:
- // Other source layouts aren't handled (yet)
- break;
- }
- vkCmdPipelineBarrier(commandBuffer, oldStage, newStage, 0, 0, nullptr, 0, nullptr, 1, &barrier);
- return VK_SUCCESS;
- }
- VkResult VulkanUtility::CopyImage(
- const VkCommandBuffer commandBuffer,
- const VkImage srcImage,
- const VkImage dstImage,
- const uint32_t width,
- const uint32_t height)
- {
- // Start copy
- VkImageCopy copyRegion {};
- copyRegion.srcSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 };
- copyRegion.srcOffset = { 0, 0, 0 };
- copyRegion.dstSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 };
- copyRegion.dstOffset = { 0, 0, 0 };
- copyRegion.extent = { width, height, 1 };
- vkCmdCopyImage(
- commandBuffer,
- srcImage,
- VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
- dstImage,
- VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
- 1,
- ©Region);
- return VK_SUCCESS;
- }
- } // end namespace webrtc
- } // end namespace unity
|