VulkanUtility.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462
  1. #include "pch.h"
  2. #include "VulkanUtility.h"
  3. #include "WebRTCMacros.h"
  4. #ifndef _WIN32
  5. #define EXTERNAL_MEMORY_HANDLE_SUPPORTED_TYPE VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR
  6. #else
  7. #define EXTERNAL_MEMORY_HANDLE_SUPPORTED_TYPE VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR
  8. #endif
  9. namespace unity
  10. {
  11. namespace webrtc
  12. {
  13. #ifdef _WIN32
  14. static PFN_vkGetMemoryWin32HandleKHR vkGetMemoryWin32HandleKHR = nullptr;
  15. #endif
  16. static PFN_vkGetMemoryFdKHR vkGetMemoryFdKHR = nullptr;
  17. static PFN_vkGetPhysicalDeviceProperties2KHR vkGetPhysicalDeviceProperties2KHR = nullptr;
  18. bool VulkanUtility::FindMemoryTypeInto(
  19. const VkPhysicalDevice physicalDevice,
  20. uint32_t typeFilter,
  21. VkMemoryPropertyFlags properties,
  22. uint32_t* memoryTypeIndex)
  23. {
  24. VkPhysicalDeviceMemoryProperties memProperties;
  25. vkGetPhysicalDeviceMemoryProperties(physicalDevice, &memProperties);
  26. for (uint32_t i = 0; i < memProperties.memoryTypeCount; ++i)
  27. {
  28. // properties define special features of the memory, like being able to map so we can write to it from the
  29. // CPU.
  30. if ((typeFilter & (1 << i)) && (memProperties.memoryTypes[i].propertyFlags & properties) == properties)
  31. {
  32. *memoryTypeIndex = i;
  33. return true;
  34. }
  35. }
  36. return false;
  37. }
  38. //---------------------------------------------------------------------------------------------------------------------
  39. // initialLayout must be either VK_IMAGE_LAYOUT_UNDEFINED or VK_IMAGE_LAYOUT_PREINITIALIZED
  40. // We use VK_IMAGE_LAYOUT_UNDEFINED here.
  41. // Returns 0 when failed
  42. VkDeviceSize VulkanUtility::CreateImage(
  43. const VkPhysicalDevice physicalDevice,
  44. const VkDevice device,
  45. const VkAllocationCallbacks* allocator,
  46. const uint32_t width,
  47. const uint32_t height,
  48. const VkImageTiling tiling,
  49. const VkImageUsageFlags usage,
  50. const VkMemoryPropertyFlags properties,
  51. const VkFormat format,
  52. VkImage* image,
  53. VkDeviceMemory* imageMemory,
  54. bool exportHandle)
  55. {
  56. VkImageCreateInfo imageInfo = {};
  57. imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
  58. imageInfo.imageType = VK_IMAGE_TYPE_2D;
  59. imageInfo.extent.width = static_cast<uint32_t>(width);
  60. imageInfo.extent.height = static_cast<uint32_t>(height);
  61. imageInfo.extent.depth = 1;
  62. imageInfo.mipLevels = 1;
  63. imageInfo.arrayLayers = 1;
  64. imageInfo.format = format;
  65. imageInfo.tiling = tiling;
  66. imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
  67. imageInfo.usage = usage;
  68. imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
  69. imageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
  70. imageInfo.flags = 0; // Optional
  71. if (vkCreateImage(device, &imageInfo, allocator, image) != VK_SUCCESS)
  72. {
  73. return 0;
  74. }
  75. VkMemoryRequirements memRequirements;
  76. vkGetImageMemoryRequirements(device, *image, &memRequirements);
  77. VkMemoryAllocateInfo allocInfo = {};
  78. allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
  79. allocInfo.allocationSize = memRequirements.size;
  80. if (!VulkanUtility::FindMemoryTypeInto(
  81. physicalDevice, memRequirements.memoryTypeBits, properties, &allocInfo.memoryTypeIndex))
  82. {
  83. return 0;
  84. }
  85. VkExportMemoryAllocateInfoKHR exportInfo = {};
  86. if (exportHandle)
  87. {
  88. exportInfo.sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_KHR;
  89. exportInfo.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR;
  90. allocInfo.pNext = &exportInfo;
  91. }
  92. if (vkAllocateMemory(device, &allocInfo, allocator, imageMemory) != VK_SUCCESS)
  93. {
  94. return 0;
  95. }
  96. VULKAN_CHECK_FAILVALUE(vkBindImageMemory(device, *image, *imageMemory, 0), 0)
  97. return memRequirements.size;
  98. }
  99. //---------------------------------------------------------------------------------------------------------------------
  100. VkResult VulkanUtility::CreateImage(
  101. const VkPhysicalDevice physicalDevice,
  102. const VkDevice device,
  103. const VkAllocationCallbacks* allocator,
  104. const uint32_t width,
  105. const uint32_t height,
  106. const VkImageTiling tiling,
  107. const VkImageUsageFlags usage,
  108. const VkMemoryPropertyFlags properties,
  109. const VkFormat format,
  110. UnityVulkanImage* unityVulkanImage,
  111. bool exportHandle)
  112. {
  113. VkImageCreateInfo imageInfo = {};
  114. imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
  115. imageInfo.imageType = VK_IMAGE_TYPE_2D;
  116. imageInfo.extent.width = static_cast<uint32_t>(width);
  117. imageInfo.extent.height = static_cast<uint32_t>(height);
  118. imageInfo.extent.depth = 1;
  119. imageInfo.mipLevels = 1;
  120. imageInfo.arrayLayers = 1;
  121. imageInfo.format = format;
  122. imageInfo.tiling = tiling;
  123. imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
  124. imageInfo.usage = usage;
  125. imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
  126. imageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
  127. imageInfo.flags = 0; // Optional
  128. VkResult result = vkCreateImage(device, &imageInfo, allocator, &unityVulkanImage->image);
  129. if (result != VK_SUCCESS)
  130. {
  131. return result;
  132. }
  133. VkMemoryRequirements memRequirements;
  134. vkGetImageMemoryRequirements(device, unityVulkanImage->image, &memRequirements);
  135. VkMemoryAllocateInfo allocInfo = {};
  136. allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
  137. allocInfo.allocationSize = memRequirements.size;
  138. bool success = VulkanUtility::FindMemoryTypeInto(
  139. physicalDevice, memRequirements.memoryTypeBits, properties, &allocInfo.memoryTypeIndex);
  140. RTC_CHECK(success);
  141. VkExportMemoryAllocateInfoKHR exportInfo = {};
  142. if (exportHandle)
  143. {
  144. exportInfo.sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_KHR;
  145. exportInfo.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR;
  146. allocInfo.pNext = &exportInfo;
  147. }
  148. result = vkAllocateMemory(device, &allocInfo, allocator, &unityVulkanImage->memory.memory);
  149. if (result != VK_SUCCESS)
  150. {
  151. return result;
  152. }
  153. const VkDeviceSize memoryOffset = 0;
  154. result = vkBindImageMemory(device, unityVulkanImage->image, unityVulkanImage->memory.memory, memoryOffset);
  155. if (result != VK_SUCCESS)
  156. {
  157. return result;
  158. }
  159. unityVulkanImage->memory.offset = memoryOffset;
  160. unityVulkanImage->memory.size = memRequirements.size;
  161. unityVulkanImage->memory.flags = properties;
  162. unityVulkanImage->memory.memoryTypeIndex = allocInfo.memoryTypeIndex;
  163. unityVulkanImage->layout = imageInfo.initialLayout;
  164. unityVulkanImage->usage = imageInfo.usage;
  165. unityVulkanImage->format = imageInfo.format;
  166. unityVulkanImage->extent = imageInfo.extent;
  167. unityVulkanImage->tiling = imageInfo.tiling;
  168. unityVulkanImage->type = imageInfo.imageType;
  169. unityVulkanImage->samples = imageInfo.samples;
  170. unityVulkanImage->layers = static_cast<int>(imageInfo.arrayLayers);
  171. unityVulkanImage->mipCount = static_cast<int>(imageInfo.mipLevels);
  172. return VK_SUCCESS;
  173. }
  174. //---------------------------------------------------------------------------------------------------------------------
  175. // returns VK_NULL_HANDLE when failed
  176. VkImageView VulkanUtility::CreateImageView(
  177. const VkDevice device, const VkAllocationCallbacks* allocator, const VkImage image, const VkFormat format)
  178. {
  179. VkImageViewCreateInfo viewInfo = {};
  180. viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
  181. viewInfo.image = image;
  182. viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
  183. viewInfo.format = format;
  184. viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
  185. viewInfo.subresourceRange.baseMipLevel = 0;
  186. viewInfo.subresourceRange.levelCount = 1;
  187. viewInfo.subresourceRange.baseArrayLayer = 0;
  188. viewInfo.subresourceRange.layerCount = 1;
  189. viewInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
  190. viewInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
  191. viewInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
  192. viewInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
  193. VkImageView imageView = nullptr;
  194. if (vkCreateImageView(device, &viewInfo, allocator, &imageView) != VK_SUCCESS)
  195. {
  196. RTC_LOG(LS_INFO) << "Failed vkCreateImageView";
  197. return nullptr;
  198. }
  199. return imageView;
  200. }
  201. //---------------------------------------------------------------------------------------------------------------------
  202. // Requires VK_KHR_get_physical_device_properties2 extension
  203. bool VulkanUtility::GetPhysicalDeviceUUIDInto(
  204. VkInstance instance, VkPhysicalDevice phyDevice, std::array<uint8_t, VK_UUID_SIZE>* deviceUUID)
  205. {
  206. VkPhysicalDeviceIDPropertiesKHR deviceIDProps = {};
  207. deviceIDProps.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES_KHR;
  208. VkPhysicalDeviceProperties2KHR props = {};
  209. props.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHR;
  210. props.pNext = &deviceIDProps;
  211. vkGetPhysicalDeviceProperties2KHR(phyDevice, &props);
  212. std::memcpy(deviceUUID->data(), deviceIDProps.deviceUUID, VK_UUID_SIZE);
  213. return true;
  214. }
  215. bool VulkanUtility::LoadDeviceFunctions(const VkDevice device)
  216. {
  217. #ifndef _WIN32
  218. vkGetMemoryFdKHR = (PFN_vkGetMemoryFdKHR)vkGetDeviceProcAddr(device, "vkGetMemoryFdKHR");
  219. if (!vkGetMemoryFdKHR)
  220. {
  221. RTC_LOG(LS_INFO) << "Failed to retrieve vkGetMemoryFdKHR";
  222. return false;
  223. }
  224. #else
  225. vkGetMemoryWin32HandleKHR =
  226. (PFN_vkGetMemoryWin32HandleKHR)vkGetDeviceProcAddr(device, "vkGetMemoryWin32HandleKHR");
  227. if (!vkGetMemoryWin32HandleKHR)
  228. {
  229. RTC_LOG(LS_INFO) << "Failed to retrieve vkGetMemoryWin32HandleKHR";
  230. return false;
  231. }
  232. #endif
  233. return true;
  234. }
  235. bool VulkanUtility::LoadInstanceFunctions(const VkInstance instance)
  236. {
  237. vkGetPhysicalDeviceProperties2KHR =
  238. (PFN_vkGetPhysicalDeviceProperties2KHR)vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceProperties2KHR");
  239. if (vkGetPhysicalDeviceProperties2KHR == nullptr)
  240. {
  241. RTC_LOG(LS_INFO) << "Failed to retrieve vkGetPhysicalDeviceProperties2KHR";
  242. return false;
  243. }
  244. return true;
  245. }
  246. #ifndef _WIN32
  247. void* VulkanUtility::GetExportHandle(const VkDevice device, const VkDeviceMemory memory)
  248. {
  249. int fd = -1;
  250. VkMemoryGetFdInfoKHR fdInfo = {};
  251. fdInfo.sType = VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR;
  252. fdInfo.memory = memory;
  253. fdInfo.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR;
  254. VkResult result = vkGetMemoryFdKHR(device, &fdInfo, &fd);
  255. if (result != VK_SUCCESS)
  256. {
  257. RTC_LOG(LS_ERROR) << "vkGetMemoryFdKHR error" << result;
  258. return nullptr;
  259. }
  260. return (void*)(uintptr_t)fd;
  261. }
  262. #else
  263. void* VulkanUtility::GetExportHandle(const VkDevice device, const VkDeviceMemory memory)
  264. {
  265. HANDLE handle = nullptr;
  266. VkMemoryGetWin32HandleInfoKHR handleInfo = {};
  267. handleInfo.sType = VK_STRUCTURE_TYPE_MEMORY_GET_WIN32_HANDLE_INFO_KHR;
  268. handleInfo.memory = memory;
  269. handleInfo.handleType = EXTERNAL_MEMORY_HANDLE_SUPPORTED_TYPE;
  270. VkResult result = vkGetMemoryWin32HandleKHR(device, &handleInfo, &handle);
  271. if (result != VK_SUCCESS)
  272. {
  273. RTC_LOG(LS_ERROR) << "vkGetMemoryWin32HandleKHR error" << result;
  274. return nullptr;
  275. }
  276. return reinterpret_cast<void*>(handle);
  277. }
  278. #endif
  279. VkResult VulkanUtility::DoImageLayoutTransition(
  280. const VkCommandBuffer commandBuffer,
  281. const VkImage image,
  282. const VkFormat format,
  283. const VkImageLayout oldLayout,
  284. const VkPipelineStageFlags oldStage,
  285. const VkImageLayout newLayout,
  286. const VkPipelineStageFlags newStage)
  287. {
  288. VkImageMemoryBarrier barrier = {};
  289. barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
  290. barrier.oldLayout = oldLayout;
  291. barrier.newLayout = newLayout;
  292. barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; // for transferring queue family ownership
  293. barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
  294. barrier.image = image;
  295. barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
  296. barrier.subresourceRange.baseMipLevel = 0;
  297. barrier.subresourceRange.levelCount = 1; // No mip map
  298. barrier.subresourceRange.baseArrayLayer = 0;
  299. barrier.subresourceRange.layerCount = 1;
  300. switch (oldLayout)
  301. {
  302. case VK_IMAGE_LAYOUT_UNDEFINED:
  303. // undefined (or does not matter). Only valid as initial layout
  304. // No flags required.
  305. barrier.srcAccessMask = 0;
  306. break;
  307. case VK_IMAGE_LAYOUT_PREINITIALIZED:
  308. // Image is preinitialized. Only valid as initial layout for linear images, preserves memory contents
  309. // Make sure host writes have been finished
  310. barrier.srcAccessMask = VK_ACCESS_HOST_WRITE_BIT;
  311. break;
  312. case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
  313. // Image is a color attachment
  314. // Make sure any writes to the color buffer have been finished
  315. barrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
  316. break;
  317. case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL:
  318. // Image is a depth/stencil attachment
  319. // Make sure any writes to the depth/stencil buffer have been finished
  320. barrier.srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
  321. break;
  322. case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL:
  323. // Image is a transfer source
  324. // Make sure any reads from the image have been finished
  325. barrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
  326. break;
  327. case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
  328. // Image is a transfer destination
  329. // Make sure any writes to the image have been finished
  330. barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
  331. break;
  332. case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
  333. // Image is read by a shader
  334. // Make sure any shader reads from the image have been finished
  335. barrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT;
  336. break;
  337. default:
  338. // Other source layouts aren't handled (yet)
  339. break;
  340. }
  341. switch (newLayout)
  342. {
  343. case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
  344. // Image will be used as a transfer destination
  345. // Make sure any writes to the image have been finished
  346. barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
  347. break;
  348. case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL:
  349. // Image will be used as a transfer source
  350. // Make sure any reads from the image have been finished
  351. barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
  352. break;
  353. case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
  354. // Image will be used as a color attachment
  355. // Make sure any writes to the color buffer have been finished
  356. barrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
  357. break;
  358. case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL:
  359. // Image layout will be used as a depth/stencil attachment
  360. // Make sure any writes to depth/stencil buffer have been finished
  361. barrier.dstAccessMask = barrier.dstAccessMask | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
  362. break;
  363. case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
  364. // Image will be read in a shader (sampler, input attachment)
  365. // Make sure any writes to the image have been finished
  366. if (barrier.srcAccessMask == 0)
  367. {
  368. barrier.srcAccessMask = VK_ACCESS_HOST_WRITE_BIT | VK_ACCESS_TRANSFER_WRITE_BIT;
  369. }
  370. barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
  371. break;
  372. default:
  373. // Other source layouts aren't handled (yet)
  374. break;
  375. }
  376. vkCmdPipelineBarrier(commandBuffer, oldStage, newStage, 0, 0, nullptr, 0, nullptr, 1, &barrier);
  377. return VK_SUCCESS;
  378. }
  379. VkResult VulkanUtility::CopyImage(
  380. const VkCommandBuffer commandBuffer,
  381. const VkImage srcImage,
  382. const VkImage dstImage,
  383. const uint32_t width,
  384. const uint32_t height)
  385. {
  386. // Start copy
  387. VkImageCopy copyRegion {};
  388. copyRegion.srcSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 };
  389. copyRegion.srcOffset = { 0, 0, 0 };
  390. copyRegion.dstSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 };
  391. copyRegion.dstOffset = { 0, 0, 0 };
  392. copyRegion.extent = { width, height, 1 };
  393. vkCmdCopyImage(
  394. commandBuffer,
  395. srcImage,
  396. VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
  397. dstImage,
  398. VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
  399. 1,
  400. &copyRegion);
  401. return VK_SUCCESS;
  402. }
  403. } // end namespace webrtc
  404. } // end namespace unity