123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233 |
- // Copyright 2020 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "gpu/vulkan/vulkan_image.h"
- #include <tuple>
- #include "base/containers/cxx20_erase.h"
- #include "base/logging.h"
- #include "gpu/vulkan/vulkan_device_queue.h"
- #include "gpu/vulkan/vulkan_function_pointers.h"
- namespace gpu {
- // static
- std::unique_ptr<VulkanImage> VulkanImage::CreateWithExternalMemoryAndModifiers(
- VulkanDeviceQueue* device_queue,
- const gfx::Size& size,
- VkFormat format,
- std::vector<uint64_t> modifiers,
- VkImageUsageFlags usage,
- VkImageCreateFlags flags) {
- auto image = std::make_unique<VulkanImage>(base::PassKey<VulkanImage>());
- if (!image->InitializeWithExternalMemoryAndModifiers(
- device_queue, size, format, std::move(modifiers), usage, flags)) {
- return nullptr;
- }
- return image;
- }
- bool VulkanImage::InitializeFromGpuMemoryBufferHandle(
- VulkanDeviceQueue* device_queue,
- gfx::GpuMemoryBufferHandle gmb_handle,
- const gfx::Size& size,
- VkFormat format,
- VkImageUsageFlags usage,
- VkImageCreateFlags flags,
- VkImageTiling image_tiling,
- uint32_t queue_family_index) {
- if (gmb_handle.type != gfx::GpuMemoryBufferType::NATIVE_PIXMAP) {
- DLOG(ERROR) << "GpuMemoryBuffer is not supported. type:" << gmb_handle.type;
- return false;
- }
- queue_family_index_ = queue_family_index;
- auto& native_pixmap_handle = gmb_handle.native_pixmap_handle;
- // 2 plane images are ok, they just need ycbcr set up.
- DCHECK_LT(native_pixmap_handle.planes.size(), 3u);
- if (native_pixmap_handle.planes.size() == 2) {
- ycbcr_info_ = VulkanYCbCrInfo(
- /*image_format=*/format,
- /*external_format=*/0,
- /*suggested_ycbcr_model=*/native_pixmap_handle.planes.size(),
- /*suggested_ycbcr_range=*/1,
- /*suggested_xchroma_offset=*/0,
- /*suggested_ychroma_offset=*/0,
- // The same flags that VaapiVideoDecoderUses to create the texture.
- /*format_features=*/VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT |
- VK_FORMAT_FEATURE_TRANSFER_DST_BIT |
- VK_FORMAT_FEATURE_TRANSFER_SRC_BIT |
- VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT |
- VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT |
- VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT);
- }
- auto& scoped_fd = native_pixmap_handle.planes[0].fd;
- if (!scoped_fd.is_valid()) {
- DLOG(ERROR) << "GpuMemoryBufferHandle doesn't have a valid fd.";
- return false;
- }
- bool using_modifier =
- native_pixmap_handle.modifier != gfx::NativePixmapHandle::kNoModifier &&
- gfx::HasExtension(device_queue->enabled_extensions(),
- VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_EXTENSION_NAME);
- VkExternalMemoryImageCreateInfoKHR external_image_create_info = {
- .sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO_KHR,
- .handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
- };
- VkImageDrmFormatModifierListCreateInfoEXT modifier_info = {
- .sType = VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_LIST_CREATE_INFO_EXT,
- .drmFormatModifierCount = 1,
- .pDrmFormatModifiers = &native_pixmap_handle.modifier,
- };
- if (using_modifier) {
- DCHECK_EQ(image_tiling, VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT);
- external_image_create_info.pNext = &modifier_info;
- }
- int memory_fd = scoped_fd.release();
- VkImportMemoryFdInfoKHR import_memory_fd_info = {
- .sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR,
- .handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
- .fd = memory_fd,
- };
- VkMemoryRequirements* requirements = nullptr;
- bool result = Initialize(device_queue, size, format, usage, flags,
- image_tiling, &external_image_create_info,
- &import_memory_fd_info, requirements);
- // If Initialize successfully, the fd in scoped_fd should be owned by vulkan,
- // otherwise take the ownership of the fd back.
- if (!result) {
- scoped_fd.reset(memory_fd);
- }
- return result;
- }
- bool VulkanImage::InitializeWithExternalMemoryAndModifiers(
- VulkanDeviceQueue* device_queue,
- const gfx::Size& size,
- VkFormat format,
- std::vector<uint64_t> modifiers,
- VkImageUsageFlags usage,
- VkImageCreateFlags flags) {
- DCHECK(gfx::HasExtension(device_queue->enabled_extensions(),
- VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_EXTENSION_NAME));
- DCHECK(!modifiers.empty());
- VkPhysicalDevice physical_device = device_queue->GetVulkanPhysicalDevice();
- // Query all supported format modifiers.
- VkDrmFormatModifierPropertiesListEXT modifier_props_list = {
- .sType = VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_EXT,
- };
- VkFormatProperties2 format_props = {
- .sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2,
- .pNext = &modifier_props_list,
- };
- vkGetPhysicalDeviceFormatProperties2(physical_device, format, &format_props);
- std::vector<VkDrmFormatModifierPropertiesEXT> props_vector;
- props_vector.resize(modifier_props_list.drmFormatModifierCount);
- modifier_props_list.pDrmFormatModifierProperties = props_vector.data();
- vkGetPhysicalDeviceFormatProperties2(physical_device, format, &format_props);
- // Call GetImageFormatProperties with every modifier and filter the list
- // down to those that we know work.
- base::EraseIf(props_vector, [&](const VkDrmFormatModifierPropertiesEXT& p) {
- VkPhysicalDeviceImageDrmFormatModifierInfoEXT mod_info = {
- .sType =
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_DRM_FORMAT_MODIFIER_INFO_EXT,
- .drmFormatModifier = p.drmFormatModifier,
- .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
- };
- VkPhysicalDeviceImageFormatInfo2 format_info = {
- .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2,
- .pNext = &mod_info,
- .format = format,
- .type = VK_IMAGE_TYPE_2D,
- .tiling = VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT,
- .usage = usage,
- .flags = flags,
- };
- VkImageFormatProperties2 format_props = {
- .sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2,
- };
- auto result = vkGetPhysicalDeviceImageFormatProperties2(
- physical_device, &format_info, &format_props);
- return result != VK_SUCCESS;
- });
- if (props_vector.empty())
- return false;
- // Find compatible modifiers.
- base::EraseIf(modifiers, [&props_vector](uint64_t modifier) {
- for (const auto& modifier_props : props_vector) {
- if (modifier == modifier_props.drmFormatModifier)
- return false;
- }
- return true;
- });
- if (modifiers.empty())
- return false;
- VkImageDrmFormatModifierListCreateInfoEXT modifier_list = {
- .sType = VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_LIST_CREATE_INFO_EXT,
- .drmFormatModifierCount = static_cast<uint32_t>(modifiers.size()),
- .pDrmFormatModifiers = modifiers.data(),
- };
- if (!InitializeWithExternalMemory(device_queue, size, format, usage, flags,
- VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT,
- &modifier_list,
- /*memory_allocation_info_next=*/nullptr)) {
- return false;
- }
- // Vulkan implementation will select a modifier from |modifiers|, so we need
- // to query it from the VkImage.
- VkImageDrmFormatModifierPropertiesEXT image_modifier_props = {
- .sType = VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_PROPERTIES_EXT,
- };
- auto result = vkGetImageDrmFormatModifierPropertiesEXT(
- device_queue->GetVulkanDevice(), image_, &image_modifier_props);
- DCHECK_EQ(result, VK_SUCCESS);
- modifier_ = image_modifier_props.drmFormatModifier;
- for (auto props : props_vector) {
- if (props.drmFormatModifier == modifier_) {
- plane_count_ = props.drmFormatModifierPlaneCount;
- break;
- }
- }
- DCHECK_GE(plane_count_, 1u);
- DCHECK_LE(plane_count_, 3u);
- for (uint32_t i = 0; i < plane_count_; i++) {
- // Based on spec VK_IMAGE_ASPECT_MEMORY_PLANE_i_BIT_EXT should be used for
- // VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT tiling. But we have to use
- // VK_IMAGE_ASPECT_PLANE_i_BIT because mesa only handles
- // VK_IMAGE_ASPECT_PLANE_i_BIT.
- // TODO(penghuang): use VK_IMAGE_ASPECT_MEMORY_PLANE_i_BIT_EXT when the mesa
- // can handle VK_IMAGE_ASPECT_MEMORY_PLANE_i_BIT_EXT.
- const VkImageSubresource image_subresource = {
- .aspectMask =
- static_cast<VkImageAspectFlags>(VK_IMAGE_ASPECT_PLANE_0_BIT << i),
- .mipLevel = 0,
- .arrayLayer = 0,
- };
- vkGetImageSubresourceLayout(device_queue->GetVulkanDevice(), image_,
- &image_subresource, &layouts_[i]);
- }
- return true;
- }
- } // namespace gpu
|