vulkan_image_linux.cc 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  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 <tuple>
  6. #include "base/containers/cxx20_erase.h"
  7. #include "base/logging.h"
  8. #include "gpu/vulkan/vulkan_device_queue.h"
  9. #include "gpu/vulkan/vulkan_function_pointers.h"
  10. namespace gpu {
  11. // static
  12. std::unique_ptr<VulkanImage> VulkanImage::CreateWithExternalMemoryAndModifiers(
  13. VulkanDeviceQueue* device_queue,
  14. const gfx::Size& size,
  15. VkFormat format,
  16. std::vector<uint64_t> modifiers,
  17. VkImageUsageFlags usage,
  18. VkImageCreateFlags flags) {
  19. auto image = std::make_unique<VulkanImage>(base::PassKey<VulkanImage>());
  20. if (!image->InitializeWithExternalMemoryAndModifiers(
  21. device_queue, size, format, std::move(modifiers), usage, flags)) {
  22. return nullptr;
  23. }
  24. return image;
  25. }
  26. bool VulkanImage::InitializeFromGpuMemoryBufferHandle(
  27. VulkanDeviceQueue* device_queue,
  28. gfx::GpuMemoryBufferHandle gmb_handle,
  29. const gfx::Size& size,
  30. VkFormat format,
  31. VkImageUsageFlags usage,
  32. VkImageCreateFlags flags,
  33. VkImageTiling image_tiling,
  34. uint32_t queue_family_index) {
  35. if (gmb_handle.type != gfx::GpuMemoryBufferType::NATIVE_PIXMAP) {
  36. DLOG(ERROR) << "GpuMemoryBuffer is not supported. type:" << gmb_handle.type;
  37. return false;
  38. }
  39. queue_family_index_ = queue_family_index;
  40. auto& native_pixmap_handle = gmb_handle.native_pixmap_handle;
  41. // 2 plane images are ok, they just need ycbcr set up.
  42. DCHECK_LT(native_pixmap_handle.planes.size(), 3u);
  43. if (native_pixmap_handle.planes.size() == 2) {
  44. ycbcr_info_ = VulkanYCbCrInfo(
  45. /*image_format=*/format,
  46. /*external_format=*/0,
  47. /*suggested_ycbcr_model=*/native_pixmap_handle.planes.size(),
  48. /*suggested_ycbcr_range=*/1,
  49. /*suggested_xchroma_offset=*/0,
  50. /*suggested_ychroma_offset=*/0,
  51. // The same flags that VaapiVideoDecoderUses to create the texture.
  52. /*format_features=*/VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT |
  53. VK_FORMAT_FEATURE_TRANSFER_DST_BIT |
  54. VK_FORMAT_FEATURE_TRANSFER_SRC_BIT |
  55. VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT |
  56. VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT |
  57. VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT);
  58. }
  59. auto& scoped_fd = native_pixmap_handle.planes[0].fd;
  60. if (!scoped_fd.is_valid()) {
  61. DLOG(ERROR) << "GpuMemoryBufferHandle doesn't have a valid fd.";
  62. return false;
  63. }
  64. bool using_modifier =
  65. native_pixmap_handle.modifier != gfx::NativePixmapHandle::kNoModifier &&
  66. gfx::HasExtension(device_queue->enabled_extensions(),
  67. VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_EXTENSION_NAME);
  68. VkExternalMemoryImageCreateInfoKHR external_image_create_info = {
  69. .sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO_KHR,
  70. .handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
  71. };
  72. VkImageDrmFormatModifierListCreateInfoEXT modifier_info = {
  73. .sType = VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_LIST_CREATE_INFO_EXT,
  74. .drmFormatModifierCount = 1,
  75. .pDrmFormatModifiers = &native_pixmap_handle.modifier,
  76. };
  77. if (using_modifier) {
  78. DCHECK_EQ(image_tiling, VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT);
  79. external_image_create_info.pNext = &modifier_info;
  80. }
  81. int memory_fd = scoped_fd.release();
  82. VkImportMemoryFdInfoKHR import_memory_fd_info = {
  83. .sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR,
  84. .handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
  85. .fd = memory_fd,
  86. };
  87. VkMemoryRequirements* requirements = nullptr;
  88. bool result = Initialize(device_queue, size, format, usage, flags,
  89. image_tiling, &external_image_create_info,
  90. &import_memory_fd_info, requirements);
  91. // If Initialize successfully, the fd in scoped_fd should be owned by vulkan,
  92. // otherwise take the ownership of the fd back.
  93. if (!result) {
  94. scoped_fd.reset(memory_fd);
  95. }
  96. return result;
  97. }
  98. bool VulkanImage::InitializeWithExternalMemoryAndModifiers(
  99. VulkanDeviceQueue* device_queue,
  100. const gfx::Size& size,
  101. VkFormat format,
  102. std::vector<uint64_t> modifiers,
  103. VkImageUsageFlags usage,
  104. VkImageCreateFlags flags) {
  105. DCHECK(gfx::HasExtension(device_queue->enabled_extensions(),
  106. VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_EXTENSION_NAME));
  107. DCHECK(!modifiers.empty());
  108. VkPhysicalDevice physical_device = device_queue->GetVulkanPhysicalDevice();
  109. // Query all supported format modifiers.
  110. VkDrmFormatModifierPropertiesListEXT modifier_props_list = {
  111. .sType = VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_EXT,
  112. };
  113. VkFormatProperties2 format_props = {
  114. .sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2,
  115. .pNext = &modifier_props_list,
  116. };
  117. vkGetPhysicalDeviceFormatProperties2(physical_device, format, &format_props);
  118. std::vector<VkDrmFormatModifierPropertiesEXT> props_vector;
  119. props_vector.resize(modifier_props_list.drmFormatModifierCount);
  120. modifier_props_list.pDrmFormatModifierProperties = props_vector.data();
  121. vkGetPhysicalDeviceFormatProperties2(physical_device, format, &format_props);
  122. // Call GetImageFormatProperties with every modifier and filter the list
  123. // down to those that we know work.
  124. base::EraseIf(props_vector, [&](const VkDrmFormatModifierPropertiesEXT& p) {
  125. VkPhysicalDeviceImageDrmFormatModifierInfoEXT mod_info = {
  126. .sType =
  127. VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_DRM_FORMAT_MODIFIER_INFO_EXT,
  128. .drmFormatModifier = p.drmFormatModifier,
  129. .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
  130. };
  131. VkPhysicalDeviceImageFormatInfo2 format_info = {
  132. .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2,
  133. .pNext = &mod_info,
  134. .format = format,
  135. .type = VK_IMAGE_TYPE_2D,
  136. .tiling = VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT,
  137. .usage = usage,
  138. .flags = flags,
  139. };
  140. VkImageFormatProperties2 format_props = {
  141. .sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2,
  142. };
  143. auto result = vkGetPhysicalDeviceImageFormatProperties2(
  144. physical_device, &format_info, &format_props);
  145. return result != VK_SUCCESS;
  146. });
  147. if (props_vector.empty())
  148. return false;
  149. // Find compatible modifiers.
  150. base::EraseIf(modifiers, [&props_vector](uint64_t modifier) {
  151. for (const auto& modifier_props : props_vector) {
  152. if (modifier == modifier_props.drmFormatModifier)
  153. return false;
  154. }
  155. return true;
  156. });
  157. if (modifiers.empty())
  158. return false;
  159. VkImageDrmFormatModifierListCreateInfoEXT modifier_list = {
  160. .sType = VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_LIST_CREATE_INFO_EXT,
  161. .drmFormatModifierCount = static_cast<uint32_t>(modifiers.size()),
  162. .pDrmFormatModifiers = modifiers.data(),
  163. };
  164. if (!InitializeWithExternalMemory(device_queue, size, format, usage, flags,
  165. VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT,
  166. &modifier_list,
  167. /*memory_allocation_info_next=*/nullptr)) {
  168. return false;
  169. }
  170. // Vulkan implementation will select a modifier from |modifiers|, so we need
  171. // to query it from the VkImage.
  172. VkImageDrmFormatModifierPropertiesEXT image_modifier_props = {
  173. .sType = VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_PROPERTIES_EXT,
  174. };
  175. auto result = vkGetImageDrmFormatModifierPropertiesEXT(
  176. device_queue->GetVulkanDevice(), image_, &image_modifier_props);
  177. DCHECK_EQ(result, VK_SUCCESS);
  178. modifier_ = image_modifier_props.drmFormatModifier;
  179. for (auto props : props_vector) {
  180. if (props.drmFormatModifier == modifier_) {
  181. plane_count_ = props.drmFormatModifierPlaneCount;
  182. break;
  183. }
  184. }
  185. DCHECK_GE(plane_count_, 1u);
  186. DCHECK_LE(plane_count_, 3u);
  187. for (uint32_t i = 0; i < plane_count_; i++) {
  188. // Based on spec VK_IMAGE_ASPECT_MEMORY_PLANE_i_BIT_EXT should be used for
  189. // VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT tiling. But we have to use
  190. // VK_IMAGE_ASPECT_PLANE_i_BIT because mesa only handles
  191. // VK_IMAGE_ASPECT_PLANE_i_BIT.
  192. // TODO(penghuang): use VK_IMAGE_ASPECT_MEMORY_PLANE_i_BIT_EXT when the mesa
  193. // can handle VK_IMAGE_ASPECT_MEMORY_PLANE_i_BIT_EXT.
  194. const VkImageSubresource image_subresource = {
  195. .aspectMask =
  196. static_cast<VkImageAspectFlags>(VK_IMAGE_ASPECT_PLANE_0_BIT << i),
  197. .mipLevel = 0,
  198. .arrayLayer = 0,
  199. };
  200. vkGetImageSubresourceLayout(device_queue->GetVulkanDevice(), image_,
  201. &image_subresource, &layouts_[i]);
  202. }
  203. return true;
  204. }
  205. } // namespace gpu