Commit 866a759c authored by Peng Huang's avatar Peng Huang Committed by Commit Bot

Add VulkanImage::CreateWithExternalMemoryAndModifiers()

Add VulkanImage::CreateWithExternalMemoryAndModifiers() which can be
used to create VkImage with a list of modifiers, and it will create a
VkImage with a modifier in the list. It is useful for creating VkImages
which can be handed to Xserver for scanout directly.

Bug: 1153156
Change-Id: I5cd92c57f4fadc5267575f4e6e3654d97166d51f
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2562974Reviewed-by: default avatarVasiliy Telezhnikov <vasilyt@chromium.org>
Commit-Queue: Peng Huang <penghuang@chromium.org>
Cr-Commit-Position: refs/heads/master@{#831872}
parent 70ca76dc
......@@ -249,7 +249,7 @@ VULKAN_DEVICE_FUNCTIONS = [
]
},
{
'ifdef': 'defined(OS_LINUX)',
'ifdef': 'defined(OS_LINUX) || defined(OS_CHROMEOS)',
'extension': 'VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_EXTENSION_NAME',
'functions': [
'vkGetImageDrmFormatModifierPropertiesEXT',
......
......@@ -1103,7 +1103,7 @@ bool VulkanFunctionPointers::BindDeviceFunctionPointers(
}
}
#if defined(OS_LINUX)
#if defined(OS_LINUX) || defined(OS_CHROMEOS)
if (gfx::HasExtension(enabled_extensions,
VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_EXTENSION_NAME)) {
vkGetImageDrmFormatModifierPropertiesEXT =
......@@ -1116,7 +1116,7 @@ bool VulkanFunctionPointers::BindDeviceFunctionPointers(
return false;
}
}
#endif // defined(OS_LINUX)
#endif // defined(OS_LINUX) || defined(OS_CHROMEOS)
return true;
}
......
......@@ -291,10 +291,10 @@ struct COMPONENT_EXPORT(VULKAN) VulkanFunctionPointers {
VulkanFunction<PFN_vkGetSwapchainImagesKHR> vkGetSwapchainImagesKHR;
VulkanFunction<PFN_vkQueuePresentKHR> vkQueuePresentKHR;
#if defined(OS_LINUX)
#if defined(OS_LINUX) || defined(OS_CHROMEOS)
VulkanFunction<PFN_vkGetImageDrmFormatModifierPropertiesEXT>
vkGetImageDrmFormatModifierPropertiesEXT;
#endif // defined(OS_LINUX)
#endif // defined(OS_LINUX) || defined(OS_CHROMEOS)
};
} // namespace gpu
......@@ -1113,7 +1113,7 @@ ALWAYS_INLINE VkResult vkQueuePresentKHR(VkQueue queue,
pPresentInfo);
}
#if defined(OS_LINUX)
#if defined(OS_LINUX) || defined(OS_CHROMEOS)
ALWAYS_INLINE VkResult vkGetImageDrmFormatModifierPropertiesEXT(
VkDevice device,
VkImage image,
......@@ -1121,6 +1121,6 @@ ALWAYS_INLINE VkResult vkGetImageDrmFormatModifierPropertiesEXT(
return gpu::GetVulkanFunctionPointers()
->vkGetImageDrmFormatModifierPropertiesEXT(device, image, pProperties);
}
#endif // defined(OS_LINUX)
#endif // defined(OS_LINUX) || defined(OS_CHROMEOS)
#endif // GPU_VULKAN_VULKAN_FUNCTION_POINTERS_H_
\ No newline at end of file
......@@ -270,6 +270,20 @@ bool VulkanImage::Initialize(VulkanDeviceQueue* device_queue,
return false;
}
// If the |image_tiling_| is VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT,
// The InitializeWithExternalMemoryAndModifiers() will get the layout.
if (image_tiling_ == VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT)
return true;
plane_count_ = 1;
const VkImageSubresource image_subresource = {
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.mipLevel = 0,
.arrayLayer = 0,
};
vkGetImageSubresourceLayout(device_queue_->GetVulkanDevice(), image_,
&image_subresource, &layouts_[0]);
return true;
}
......
......@@ -7,6 +7,9 @@
#include <vulkan/vulkan.h>
#include <array>
#include <vector>
#include "base/component_export.h"
#include "base/files/scoped_file.h"
#include "base/optional.h"
......@@ -81,6 +84,16 @@ class COMPONENT_EXPORT(VULKAN) VulkanImage {
VkImageUsageFlags usage,
VkImageCreateFlags flags);
#if defined(OS_LINUX) || defined(OS_CHROMEOS)
static std::unique_ptr<VulkanImage> CreateWithExternalMemoryAndModifiers(
VulkanDeviceQueue* device_queue,
const gfx::Size& size,
VkFormat format,
std::vector<uint64_t> modifiers,
VkImageUsageFlags usage,
VkImageCreateFlags flags);
#endif
void Destroy();
#if defined(OS_POSIX)
......@@ -122,6 +135,9 @@ class COMPONENT_EXPORT(VULKAN) VulkanImage {
const scoped_refptr<gfx::NativePixmap>& native_pixmap() const {
return native_pixmap_;
}
uint64_t modifier() const { return modifier_; }
size_t plane_count() const { return plane_count_; }
const std::array<VkSubresourceLayout, 4>& layouts() const { return layouts_; }
private:
bool Initialize(VulkanDeviceQueue* device_queue,
......@@ -150,6 +166,15 @@ class COMPONENT_EXPORT(VULKAN) VulkanImage {
VkImageCreateFlags flags,
VkImageTiling image_tiling);
#if defined(OS_LINUX) || defined(OS_CHROMEOS)
bool InitializeWithExternalMemoryAndModifiers(VulkanDeviceQueue* device_queue,
const gfx::Size& size,
VkFormat format,
std::vector<uint64_t> modifiers,
VkImageUsageFlags usage,
VkImageCreateFlags flags);
#endif
VulkanDeviceQueue* device_queue_ = nullptr;
gfx::Size size_;
VkFormat format_ = VK_FORMAT_UNDEFINED;
......@@ -165,6 +190,9 @@ class COMPONENT_EXPORT(VULKAN) VulkanImage {
VkDeviceMemory device_memory_ = VK_NULL_HANDLE;
VkExternalMemoryHandleTypeFlags handle_types_ = 0;
scoped_refptr<gfx::NativePixmap> native_pixmap_;
uint64_t modifier_ = 0;
size_t plane_count_ = 0;
std::array<VkSubresourceLayout, 4> layouts_ = {};
};
} // namespace gpu
......
......@@ -6,9 +6,26 @@
#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,
......@@ -71,4 +88,121 @@ bool VulkanImage::InitializeFromGpuMemoryBufferHandle(
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 = 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 = VK_IMAGE_ASPECT_PLANE_0_BIT << i,
.mipLevel = 0,
.arrayLayer = 0,
};
vkGetImageSubresourceLayout(device_queue->GetVulkanDevice(), image_,
&image_subresource, &layouts_[i]);
}
return true;
}
} // namespace gpu
\ No newline at end of file
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment