vulkan_image.cc 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385
  1. // Copyright 2020 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "gpu/vulkan/vulkan_image.h"
  5. #include <vulkan/vulkan.h>
  6. #include <algorithm>
  7. #include "base/logging.h"
  8. #include "build/build_config.h"
  9. #include "build/chromeos_buildflags.h"
  10. #include "gpu/vulkan/vulkan_device_queue.h"
  11. #include "gpu/vulkan/vulkan_function_pointers.h"
  12. #include "third_party/abseil-cpp/absl/types/optional.h"
  13. namespace gpu {
  14. namespace {
  15. absl::optional<uint32_t> FindMemoryTypeIndex(
  16. VkPhysicalDevice physical_device,
  17. const VkMemoryRequirements* requirements,
  18. VkMemoryPropertyFlags flags) {
  19. VkPhysicalDeviceMemoryProperties properties;
  20. vkGetPhysicalDeviceMemoryProperties(physical_device, &properties);
  21. constexpr uint32_t kMaxIndex = 31;
  22. for (uint32_t i = 0; i <= kMaxIndex; i++) {
  23. if (((1u << i) & requirements->memoryTypeBits) == 0)
  24. continue;
  25. if ((properties.memoryTypes[i].propertyFlags & flags) != flags)
  26. continue;
  27. return i;
  28. }
  29. NOTREACHED();
  30. return absl::nullopt;
  31. }
  32. } // namespace
  33. // static
  34. std::unique_ptr<VulkanImage> VulkanImage::Create(
  35. VulkanDeviceQueue* device_queue,
  36. const gfx::Size& size,
  37. VkFormat format,
  38. VkImageUsageFlags usage,
  39. VkImageCreateFlags flags,
  40. VkImageTiling image_tiling,
  41. void* vk_image_create_info_next,
  42. void* vk_memory_allocation_info_next) {
  43. auto image = std::make_unique<VulkanImage>(base::PassKey<VulkanImage>());
  44. if (!image->Initialize(device_queue, size, format, usage, flags, image_tiling,
  45. vk_image_create_info_next,
  46. vk_memory_allocation_info_next,
  47. nullptr /* requirements */)) {
  48. return nullptr;
  49. }
  50. return image;
  51. }
  52. // static
  53. std::unique_ptr<VulkanImage> VulkanImage::CreateWithExternalMemory(
  54. VulkanDeviceQueue* device_queue,
  55. const gfx::Size& size,
  56. VkFormat format,
  57. VkImageUsageFlags usage,
  58. VkImageCreateFlags flags,
  59. VkImageTiling image_tiling,
  60. void* image_create_info_next,
  61. void* memory_allocation_info_next) {
  62. auto image = std::make_unique<VulkanImage>(base::PassKey<VulkanImage>());
  63. if (!image->InitializeWithExternalMemory(
  64. device_queue, size, format, usage, flags, image_tiling,
  65. image_create_info_next, memory_allocation_info_next)) {
  66. return nullptr;
  67. }
  68. return image;
  69. }
  70. // static
  71. std::unique_ptr<VulkanImage> VulkanImage::CreateFromGpuMemoryBufferHandle(
  72. VulkanDeviceQueue* device_queue,
  73. gfx::GpuMemoryBufferHandle gmb_handle,
  74. const gfx::Size& size,
  75. VkFormat format,
  76. VkImageUsageFlags usage,
  77. VkImageCreateFlags flags,
  78. VkImageTiling image_tiling,
  79. uint32_t queue_family_index) {
  80. auto image = std::make_unique<VulkanImage>(base::PassKey<VulkanImage>());
  81. if (!image->InitializeFromGpuMemoryBufferHandle(
  82. device_queue, std::move(gmb_handle), size, format, usage, flags,
  83. image_tiling, queue_family_index)) {
  84. return nullptr;
  85. }
  86. return image;
  87. }
  88. // static
  89. std::unique_ptr<VulkanImage> VulkanImage::Create(
  90. VulkanDeviceQueue* device_queue,
  91. VkImage vk_image,
  92. VkDeviceMemory vk_device_memory,
  93. const gfx::Size& size,
  94. VkFormat format,
  95. VkImageTiling image_tiling,
  96. VkDeviceSize device_size,
  97. uint32_t memory_type_index,
  98. absl::optional<VulkanYCbCrInfo>& ycbcr_info,
  99. VkImageUsageFlags usage,
  100. VkImageCreateFlags flags) {
  101. auto image = std::make_unique<VulkanImage>(base::PassKey<VulkanImage>());
  102. image->device_queue_ = device_queue;
  103. image->image_ = vk_image;
  104. image->device_memory_ = vk_device_memory;
  105. image->create_info_.extent = {static_cast<uint32_t>(size.width()),
  106. static_cast<uint32_t>(size.height()), 1};
  107. image->create_info_.format = format;
  108. image->create_info_.tiling = image_tiling;
  109. image->device_size_ = device_size;
  110. image->memory_type_index_ = memory_type_index;
  111. image->ycbcr_info_ = ycbcr_info;
  112. image->create_info_.usage = usage;
  113. image->create_info_.flags = flags;
  114. return image;
  115. }
  116. VulkanImage::VulkanImage(base::PassKey<VulkanImage> pass_key) {}
  117. VulkanImage::~VulkanImage() {
  118. DCHECK(!device_queue_);
  119. DCHECK(image_ == VK_NULL_HANDLE);
  120. DCHECK(device_memory_ == VK_NULL_HANDLE);
  121. }
  122. void VulkanImage::Destroy() {
  123. if (!device_queue_)
  124. return;
  125. VkDevice vk_device = device_queue_->GetVulkanDevice();
  126. if (image_ != VK_NULL_HANDLE) {
  127. vkDestroyImage(vk_device, image_, nullptr /* pAllocator */);
  128. image_ = VK_NULL_HANDLE;
  129. }
  130. if (device_memory_ != VK_NULL_HANDLE) {
  131. vkFreeMemory(vk_device, device_memory_, nullptr /* pAllocator */);
  132. device_memory_ = VK_NULL_HANDLE;
  133. }
  134. device_queue_ = nullptr;
  135. }
  136. #if BUILDFLAG(IS_POSIX)
  137. base::ScopedFD VulkanImage::GetMemoryFd(
  138. VkExternalMemoryHandleTypeFlagBits handle_type) {
  139. VkMemoryGetFdInfoKHR get_fd_info = {
  140. .sType = VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR,
  141. .memory = device_memory_,
  142. .handleType = handle_type,
  143. };
  144. VkDevice device = device_queue_->GetVulkanDevice();
  145. int memory_fd = -1;
  146. vkGetMemoryFdKHR(device, &get_fd_info, &memory_fd);
  147. if (memory_fd < 0) {
  148. DLOG(ERROR) << "Unable to extract file descriptor out of external VkImage";
  149. return base::ScopedFD();
  150. }
  151. return base::ScopedFD(memory_fd);
  152. }
  153. #endif // BUILDFLAG(IS_POSIX)
  154. bool VulkanImage::Initialize(VulkanDeviceQueue* device_queue,
  155. const gfx::Size& size,
  156. VkFormat format,
  157. VkImageUsageFlags usage,
  158. VkImageCreateFlags flags,
  159. VkImageTiling image_tiling,
  160. void* vk_image_create_info_next,
  161. void* vk_memory_allocation_info_next,
  162. const VkMemoryRequirements* requirements) {
  163. DCHECK(!device_queue_);
  164. DCHECK(image_ == VK_NULL_HANDLE);
  165. DCHECK(device_memory_ == VK_NULL_HANDLE);
  166. device_queue_ = device_queue;
  167. create_info_ = {
  168. .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
  169. .pNext = vk_image_create_info_next,
  170. .flags = flags,
  171. .imageType = VK_IMAGE_TYPE_2D,
  172. .format = format,
  173. .extent = {static_cast<uint32_t>(size.width()),
  174. static_cast<uint32_t>(size.height()), 1},
  175. .mipLevels = 1,
  176. .arrayLayers = 1,
  177. .samples = VK_SAMPLE_COUNT_1_BIT,
  178. .tiling = image_tiling,
  179. .usage = usage,
  180. .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
  181. .queueFamilyIndexCount = 0,
  182. .pQueueFamilyIndices = nullptr,
  183. .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
  184. };
  185. VkDevice vk_device = device_queue->GetVulkanDevice();
  186. VkResult result = vkCreateImage(vk_device, &create_info_,
  187. nullptr /* pAllocator */, &image_);
  188. create_info_.pNext = nullptr;
  189. if (result != VK_SUCCESS) {
  190. DLOG(ERROR) << "vkCreateImage failed result:" << result;
  191. device_queue_ = nullptr;
  192. return false;
  193. }
  194. VkMemoryRequirements tmp_requirements;
  195. if (!requirements) {
  196. vkGetImageMemoryRequirements(vk_device, image_, &tmp_requirements);
  197. if (!tmp_requirements.memoryTypeBits) {
  198. DLOG(ERROR) << "vkGetImageMemoryRequirements failed";
  199. Destroy();
  200. return false;
  201. }
  202. requirements = &tmp_requirements;
  203. }
  204. device_size_ = requirements->size;
  205. // Some vulkan implementations require dedicated memory for sharing memory
  206. // object between vulkan instances.
  207. VkMemoryDedicatedAllocateInfoKHR dedicated_memory_info = {
  208. .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR,
  209. .pNext = vk_memory_allocation_info_next,
  210. .image = image_,
  211. };
  212. auto index =
  213. FindMemoryTypeIndex(device_queue->GetVulkanPhysicalDevice(), requirements,
  214. VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
  215. if (!index) {
  216. DLOG(ERROR) << "Cannot find validate memory type index.";
  217. Destroy();
  218. return false;
  219. }
  220. memory_type_index_ = index.value();
  221. VkMemoryAllocateInfo memory_allocate_info = {
  222. .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
  223. .pNext = &dedicated_memory_info,
  224. .allocationSize = device_size_,
  225. .memoryTypeIndex = memory_type_index_,
  226. };
  227. result = vkAllocateMemory(vk_device, &memory_allocate_info,
  228. nullptr /* pAllocator */, &device_memory_);
  229. if (result != VK_SUCCESS) {
  230. DLOG(ERROR) << "vkAllocateMemory failed result:" << result;
  231. Destroy();
  232. return false;
  233. }
  234. result = vkBindImageMemory(vk_device, image_, device_memory_,
  235. 0 /* memoryOffset */);
  236. if (result != VK_SUCCESS) {
  237. DLOG(ERROR) << "Failed to bind memory to external VkImage: " << result;
  238. Destroy();
  239. return false;
  240. }
  241. // Get subresource layout for images with VK_IMAGE_TILING_LINEAR.
  242. // For images with VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT, the layout is
  243. // initialized in InitializeWithExternalMemoryAndModifiers(). For
  244. // VK_IMAGE_TILING_OPTIMAL the layout is not usable and
  245. // vkGetImageSubresourceLayout() is illegal.
  246. if (image_tiling != VK_IMAGE_TILING_LINEAR)
  247. return true;
  248. const VkImageSubresource image_subresource = {
  249. .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
  250. .mipLevel = 0,
  251. .arrayLayer = 0,
  252. };
  253. vkGetImageSubresourceLayout(device_queue_->GetVulkanDevice(), image_,
  254. &image_subresource, &layouts_[0]);
  255. return true;
  256. }
  257. bool VulkanImage::InitializeWithExternalMemory(
  258. VulkanDeviceQueue* device_queue,
  259. const gfx::Size& size,
  260. VkFormat format,
  261. VkImageUsageFlags usage,
  262. VkImageCreateFlags flags,
  263. VkImageTiling image_tiling,
  264. void* image_create_info_next,
  265. void* memory_allocation_info_next) {
  266. #if BUILDFLAG(IS_FUCHSIA)
  267. constexpr auto kHandleType =
  268. VK_EXTERNAL_MEMORY_HANDLE_TYPE_ZIRCON_VMO_BIT_FUCHSIA;
  269. #elif BUILDFLAG(IS_WIN)
  270. constexpr auto kHandleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT;
  271. #else
  272. constexpr auto kHandleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;
  273. #endif
  274. VkPhysicalDeviceImageFormatInfo2 format_info_2 = {
  275. .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2,
  276. .format = format,
  277. .type = VK_IMAGE_TYPE_2D,
  278. .tiling = image_tiling,
  279. .usage = usage,
  280. .flags = flags,
  281. };
  282. VkPhysicalDeviceExternalImageFormatInfo external_info = {
  283. .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO,
  284. .handleType = kHandleType,
  285. };
  286. format_info_2.pNext = &external_info;
  287. // TODO(crbug.com/1052397): Revisit once build flag switch of lacros-chrome is
  288. // complete.
  289. #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
  290. VkPhysicalDeviceImageDrmFormatModifierInfoEXT modifier_info = {
  291. .sType =
  292. VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_DRM_FORMAT_MODIFIER_INFO_EXT,
  293. .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
  294. };
  295. // If image_tiling is VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT, a modifier_info
  296. // struct has to be appended.
  297. if (image_tiling == VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT)
  298. external_info.pNext = &modifier_info;
  299. #endif
  300. VkImageFormatProperties2 image_format_properties_2 = {
  301. .sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2,
  302. };
  303. VkExternalImageFormatProperties external_image_format_properties = {
  304. .sType = VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES,
  305. };
  306. image_format_properties_2.pNext = &external_image_format_properties;
  307. auto result = vkGetPhysicalDeviceImageFormatProperties2(
  308. device_queue->GetVulkanPhysicalDevice(), &format_info_2,
  309. &image_format_properties_2);
  310. if (result != VK_SUCCESS) {
  311. DLOG(ERROR) << "External memory is not supported."
  312. << " format:" << format << " image_tiling:" << image_tiling
  313. << " usage:" << usage << " flags:" << flags;
  314. return false;
  315. }
  316. const auto& external_format_properties =
  317. external_image_format_properties.externalMemoryProperties;
  318. if (!(external_format_properties.externalMemoryFeatures &
  319. VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT)) {
  320. DLOG(ERROR) << "External memroy cannot be exported."
  321. << " format:" << format << " image_tiling:" << image_tiling
  322. << " usage:" << usage << " flags:" << flags;
  323. return false;
  324. }
  325. handle_types_ = external_format_properties.compatibleHandleTypes;
  326. DCHECK(handle_types_ & kHandleType);
  327. VkExternalMemoryImageCreateInfoKHR external_image_create_info = {
  328. .sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO_KHR,
  329. .pNext = image_create_info_next,
  330. .handleTypes = handle_types_,
  331. };
  332. VkExportMemoryAllocateInfoKHR external_memory_allocate_info = {
  333. .sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_KHR,
  334. .pNext = memory_allocation_info_next,
  335. .handleTypes = handle_types_,
  336. };
  337. return Initialize(device_queue, size, format, usage, flags, image_tiling,
  338. &external_image_create_info, &external_memory_allocate_info,
  339. nullptr /* requirements */);
  340. }
  341. } // namespace gpu