Commit a90e54ef authored by Michael Spang's avatar Michael Spang Committed by Commit Bot

gpu: Request all VkImageUsageFlags for VkImages that alias GL textures

Different VkImageUsageFlags may create VkImages with different
characteristics. glTexStorageMem2DEXTFn doesn't accept a usage flag
argument, instead the spec requires us to request all supported flags for
allocations that will alias GL textures.

This fixes ExternalVkImageFactory to comply this requirement. It's an
issue on ARM where VK_IMAGE_USAGE_STORAGE_BIT affects VkImage memory
requirements.

Bug: 1058958

Change-Id: I711f8463f709e9c77811325e004018c87bcd0626
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2090454Reviewed-by: default avatarPeng Huang <penghuang@chromium.org>
Reviewed-by: default avatarZhenyao Mo <zmo@chromium.org>
Commit-Queue: Michael Spang <spang@chromium.org>
Cr-Commit-Position: refs/heads/master@{#747826}
parent b30d09e7
...@@ -442,6 +442,32 @@ bool GLSupportsFormat(ResourceFormat format) { ...@@ -442,6 +442,32 @@ bool GLSupportsFormat(ResourceFormat format) {
} }
#if BUILDFLAG(ENABLE_VULKAN) #if BUILDFLAG(ENABLE_VULKAN)
bool HasVkFormat(ResourceFormat format) {
switch (format) {
case RGBA_8888:
case RGBA_4444:
case BGRA_8888:
case RED_8:
case RGB_565:
case BGR_565:
case RG_88:
case RGBA_F16:
case R16_EXT:
case RGBX_8888:
case BGRX_8888:
case RGBA_1010102:
case BGRA_1010102:
case ALPHA_8:
case LUMINANCE_8:
case YVU_420:
case YUV_420_BIPLANAR:
case ETC1:
return true;
default:
return false;
}
}
VkFormat ToVkFormat(ResourceFormat format) { VkFormat ToVkFormat(ResourceFormat format) {
switch (format) { switch (format) {
case RGBA_8888: case RGBA_8888:
......
...@@ -63,6 +63,7 @@ GetResourceFormat(gfx::BufferFormat format); ...@@ -63,6 +63,7 @@ GetResourceFormat(gfx::BufferFormat format);
VIZ_RESOURCE_FORMAT_EXPORT bool GLSupportsFormat(ResourceFormat format); VIZ_RESOURCE_FORMAT_EXPORT bool GLSupportsFormat(ResourceFormat format);
#if BUILDFLAG(ENABLE_VULKAN) #if BUILDFLAG(ENABLE_VULKAN)
VIZ_RESOURCE_FORMAT_EXPORT bool HasVkFormat(ResourceFormat format);
VIZ_RESOURCE_FORMAT_EXPORT VkFormat ToVkFormat(ResourceFormat format); VIZ_RESOURCE_FORMAT_EXPORT VkFormat ToVkFormat(ResourceFormat format);
#endif #endif
......
...@@ -98,11 +98,13 @@ GrVkImageInfo CreateGrVkImageInfo( ...@@ -98,11 +98,13 @@ GrVkImageInfo CreateGrVkImageInfo(
} }
VkResult CreateVkImage(SharedContextState* context_state, VkResult CreateVkImage(SharedContextState* context_state,
viz::ResourceFormat viz_format,
VkFormat format, VkFormat format,
const gfx::Size& size, const gfx::Size& size,
bool is_transfer_dst, bool is_transfer_dst,
bool is_external, bool is_external,
bool use_protected_memory, uint32_t shared_image_usage,
const VulkanImageUsageCache* image_usage_cache,
VkImage* image) { VkImage* image) {
VkExternalMemoryImageCreateInfoKHR external_info = { VkExternalMemoryImageCreateInfoKHR external_info = {
.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO_KHR, .sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO_KHR,
...@@ -111,14 +113,26 @@ VkResult CreateVkImage(SharedContextState* context_state, ...@@ -111,14 +113,26 @@ VkResult CreateVkImage(SharedContextState* context_state,
->GetExternalImageHandleType(), ->GetExternalImageHandleType(),
}; };
auto usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT; VkImageUsageFlags usage =
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
if (is_transfer_dst) if (is_transfer_dst)
usage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT; usage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT;
// Requested usage flags must be supported.
DCHECK_EQ(usage & image_usage_cache->optimal_tiling_usage[viz_format], usage);
if (is_external && (shared_image_usage & SHARED_IMAGE_USAGE_GLES2)) {
// Must request all available image usage flags if aliasing GL texture. This
// is a spec requirement.
usage |= image_usage_cache->optimal_tiling_usage[viz_format];
}
VkImageCreateInfo create_info = { VkImageCreateInfo create_info = {
.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
.pNext = is_external ? &external_info : nullptr, .pNext = is_external ? &external_info : nullptr,
.flags = use_protected_memory ? VK_IMAGE_CREATE_PROTECTED_BIT : 0, .flags = shared_image_usage & SHARED_IMAGE_USAGE_PROTECTED
? VK_IMAGE_CREATE_PROTECTED_BIT
: 0,
.imageType = VK_IMAGE_TYPE_2D, .imageType = VK_IMAGE_TYPE_2D,
.format = format, .format = format,
.extent = {size.width(), size.height(), 1}, .extent = {size.width(), size.height(), 1},
...@@ -213,6 +227,7 @@ std::unique_ptr<ExternalVkImageBacking> ExternalVkImageBacking::Create( ...@@ -213,6 +227,7 @@ std::unique_ptr<ExternalVkImageBacking> ExternalVkImageBacking::Create(
const gfx::Size& size, const gfx::Size& size,
const gfx::ColorSpace& color_space, const gfx::ColorSpace& color_space,
uint32_t usage, uint32_t usage,
const VulkanImageUsageCache* image_usage_cache,
base::span<const uint8_t> pixel_data, base::span<const uint8_t> pixel_data,
bool using_gmb) { bool using_gmb) {
VkDevice device = VkDevice device =
...@@ -227,8 +242,8 @@ std::unique_ptr<ExternalVkImageBacking> ExternalVkImageBacking::Create( ...@@ -227,8 +242,8 @@ std::unique_ptr<ExternalVkImageBacking> ExternalVkImageBacking::Create(
usage |= SHARED_IMAGE_USAGE_PROTECTED; usage |= SHARED_IMAGE_USAGE_PROTECTED;
} }
VkResult result = VkResult result =
CreateVkImage(context_state, vk_format, size, is_transfer_dst, CreateVkImage(context_state, format, vk_format, size, is_transfer_dst,
is_external, usage & SHARED_IMAGE_USAGE_PROTECTED, &image); is_external, usage, image_usage_cache, &image);
if (result != VK_SUCCESS) { if (result != VK_SUCCESS) {
DLOG(ERROR) << "Failed to create external VkImage: " << result; DLOG(ERROR) << "Failed to create external VkImage: " << result;
return nullptr; return nullptr;
...@@ -315,7 +330,8 @@ std::unique_ptr<ExternalVkImageBacking> ExternalVkImageBacking::CreateFromGMB( ...@@ -315,7 +330,8 @@ std::unique_ptr<ExternalVkImageBacking> ExternalVkImageBacking::CreateFromGMB(
gfx::BufferFormat buffer_format, gfx::BufferFormat buffer_format,
const gfx::Size& size, const gfx::Size& size,
const gfx::ColorSpace& color_space, const gfx::ColorSpace& color_space,
uint32_t usage) { uint32_t usage,
const VulkanImageUsageCache* image_usage_cache) {
if (!gpu::IsImageSizeValidForGpuMemoryBufferFormat(size, buffer_format)) { if (!gpu::IsImageSizeValidForGpuMemoryBufferFormat(size, buffer_format)) {
DLOG(ERROR) << "Invalid image size for format."; DLOG(ERROR) << "Invalid image size for format.";
return nullptr; return nullptr;
...@@ -444,8 +460,8 @@ std::unique_ptr<ExternalVkImageBacking> ExternalVkImageBacking::CreateFromGMB( ...@@ -444,8 +460,8 @@ std::unique_ptr<ExternalVkImageBacking> ExternalVkImageBacking::CreateFromGMB(
} }
auto backing = Create(context_state, command_pool, mailbox, resource_format, auto backing = Create(context_state, command_pool, mailbox, resource_format,
size, color_space, usage, base::span<const uint8_t>(), size, color_space, usage, image_usage_cache,
true /* using_gmb */); base::span<const uint8_t>(), true /* using_gmb */);
if (!backing) if (!backing)
return nullptr; return nullptr;
......
...@@ -25,6 +25,11 @@ namespace gpu { ...@@ -25,6 +25,11 @@ namespace gpu {
class VulkanCommandPool; class VulkanCommandPool;
struct VulkanImageUsageCache {
// Maximal usage flags for VK_IMAGE_TILING_OPTIMAL each ResourceFormat.
VkImageUsageFlags optimal_tiling_usage[viz::RESOURCE_FORMAT_MAX + 1];
};
class ExternalVkImageBacking final : public ClearTrackingSharedImageBacking { class ExternalVkImageBacking final : public ClearTrackingSharedImageBacking {
public: public:
static std::unique_ptr<ExternalVkImageBacking> Create( static std::unique_ptr<ExternalVkImageBacking> Create(
...@@ -35,6 +40,7 @@ class ExternalVkImageBacking final : public ClearTrackingSharedImageBacking { ...@@ -35,6 +40,7 @@ class ExternalVkImageBacking final : public ClearTrackingSharedImageBacking {
const gfx::Size& size, const gfx::Size& size,
const gfx::ColorSpace& color_space, const gfx::ColorSpace& color_space,
uint32_t usage, uint32_t usage,
const VulkanImageUsageCache* image_usage_cache,
base::span<const uint8_t> pixel_data, base::span<const uint8_t> pixel_data,
bool using_gmb = false); bool using_gmb = false);
...@@ -46,7 +52,8 @@ class ExternalVkImageBacking final : public ClearTrackingSharedImageBacking { ...@@ -46,7 +52,8 @@ class ExternalVkImageBacking final : public ClearTrackingSharedImageBacking {
gfx::BufferFormat buffer_format, gfx::BufferFormat buffer_format,
const gfx::Size& size, const gfx::Size& size,
const gfx::ColorSpace& color_space, const gfx::ColorSpace& color_space,
uint32_t usage); uint32_t usage,
const VulkanImageUsageCache* image_usage_cache);
~ExternalVkImageBacking() override; ~ExternalVkImageBacking() override;
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include <unistd.h> #include <unistd.h>
#include "components/viz/common/gpu/vulkan_context_provider.h" #include "components/viz/common/gpu/vulkan_context_provider.h"
#include "components/viz/common/resources/resource_format_utils.h"
#include "gpu/command_buffer/service/external_vk_image_backing.h" #include "gpu/command_buffer/service/external_vk_image_backing.h"
#include "gpu/command_buffer/service/shared_image_representation.h" #include "gpu/command_buffer/service/shared_image_representation.h"
#include "gpu/vulkan/vulkan_command_buffer.h" #include "gpu/vulkan/vulkan_command_buffer.h"
...@@ -18,12 +19,59 @@ ...@@ -18,12 +19,59 @@
namespace gpu { namespace gpu {
namespace {
VkImageUsageFlags GetMaximalImageUsageFlags(
VkFormatFeatureFlags feature_flags) {
VkImageUsageFlags usage_flags = 0;
if (feature_flags & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT)
usage_flags |= VK_IMAGE_USAGE_SAMPLED_BIT;
if (feature_flags & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT)
usage_flags |= VK_IMAGE_USAGE_STORAGE_BIT;
if (feature_flags & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT)
usage_flags |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
if (feature_flags & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)
usage_flags |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
if (feature_flags & VK_FORMAT_FEATURE_TRANSFER_SRC_BIT)
usage_flags |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
if (feature_flags & VK_FORMAT_FEATURE_TRANSFER_DST_BIT)
usage_flags |= VK_IMAGE_USAGE_TRANSFER_DST_BIT;
usage_flags |= VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
return usage_flags;
}
VulkanImageUsageCache CreateImageUsageCache(
VkPhysicalDevice vk_physical_device) {
VulkanImageUsageCache image_usage_cache = {};
for (int i = 0; i <= static_cast<int>(viz::RESOURCE_FORMAT_MAX); ++i) {
viz::ResourceFormat format = static_cast<viz::ResourceFormat>(i);
if (!viz::HasVkFormat(format))
continue;
VkFormat vk_format = viz::ToVkFormat(format);
DCHECK_NE(vk_format, VK_FORMAT_UNDEFINED);
VkFormatProperties format_props = {};
vkGetPhysicalDeviceFormatProperties(vk_physical_device, vk_format,
&format_props);
image_usage_cache.optimal_tiling_usage[format] =
GetMaximalImageUsageFlags(format_props.optimalTilingFeatures);
}
return image_usage_cache;
}
} // namespace
ExternalVkImageFactory::ExternalVkImageFactory( ExternalVkImageFactory::ExternalVkImageFactory(
SharedContextState* context_state) SharedContextState* context_state)
: context_state_(context_state), : context_state_(context_state),
command_pool_(context_state_->vk_context_provider() command_pool_(context_state_->vk_context_provider()
->GetDeviceQueue() ->GetDeviceQueue()
->CreateCommandPool()) {} ->CreateCommandPool()),
image_usage_cache_(
CreateImageUsageCache(context_state_->vk_context_provider()
->GetDeviceQueue()
->GetVulkanPhysicalDevice())) {}
ExternalVkImageFactory::~ExternalVkImageFactory() { ExternalVkImageFactory::~ExternalVkImageFactory() {
if (command_pool_) { if (command_pool_) {
...@@ -43,9 +91,9 @@ std::unique_ptr<SharedImageBacking> ExternalVkImageFactory::CreateSharedImage( ...@@ -43,9 +91,9 @@ std::unique_ptr<SharedImageBacking> ExternalVkImageFactory::CreateSharedImage(
uint32_t usage, uint32_t usage,
bool is_thread_safe) { bool is_thread_safe) {
DCHECK(!is_thread_safe); DCHECK(!is_thread_safe);
return ExternalVkImageBacking::Create(context_state_, command_pool_.get(), return ExternalVkImageBacking::Create(
mailbox, format, size, color_space, context_state_, command_pool_.get(), mailbox, format, size, color_space,
usage, base::span<const uint8_t>()); usage, &image_usage_cache_, base::span<const uint8_t>());
} }
std::unique_ptr<SharedImageBacking> ExternalVkImageFactory::CreateSharedImage( std::unique_ptr<SharedImageBacking> ExternalVkImageFactory::CreateSharedImage(
...@@ -57,7 +105,7 @@ std::unique_ptr<SharedImageBacking> ExternalVkImageFactory::CreateSharedImage( ...@@ -57,7 +105,7 @@ std::unique_ptr<SharedImageBacking> ExternalVkImageFactory::CreateSharedImage(
base::span<const uint8_t> pixel_data) { base::span<const uint8_t> pixel_data) {
return ExternalVkImageBacking::Create(context_state_, command_pool_.get(), return ExternalVkImageBacking::Create(context_state_, command_pool_.get(),
mailbox, format, size, color_space, mailbox, format, size, color_space,
usage, pixel_data); usage, &image_usage_cache_, pixel_data);
} }
std::unique_ptr<SharedImageBacking> ExternalVkImageFactory::CreateSharedImage( std::unique_ptr<SharedImageBacking> ExternalVkImageFactory::CreateSharedImage(
...@@ -72,7 +120,7 @@ std::unique_ptr<SharedImageBacking> ExternalVkImageFactory::CreateSharedImage( ...@@ -72,7 +120,7 @@ std::unique_ptr<SharedImageBacking> ExternalVkImageFactory::CreateSharedImage(
DCHECK(CanImportGpuMemoryBuffer(handle.type)); DCHECK(CanImportGpuMemoryBuffer(handle.type));
return ExternalVkImageBacking::CreateFromGMB( return ExternalVkImageBacking::CreateFromGMB(
context_state_, command_pool_.get(), mailbox, std::move(handle), context_state_, command_pool_.get(), mailbox, std::move(handle),
buffer_format, size, color_space, usage); buffer_format, size, color_space, usage, &image_usage_cache_);
} }
bool ExternalVkImageFactory::CanImportGpuMemoryBuffer( bool ExternalVkImageFactory::CanImportGpuMemoryBuffer(
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include <vulkan/vulkan.h> #include <vulkan/vulkan.h>
#include <memory> #include <memory>
#include "gpu/command_buffer/service/external_vk_image_backing.h"
#include "gpu/command_buffer/service/shared_image_backing_factory.h" #include "gpu/command_buffer/service/shared_image_backing_factory.h"
namespace gpu { namespace gpu {
...@@ -62,6 +63,8 @@ class ExternalVkImageFactory : public SharedImageBackingFactory { ...@@ -62,6 +63,8 @@ class ExternalVkImageFactory : public SharedImageBackingFactory {
SharedContextState* const context_state_; SharedContextState* const context_state_;
std::unique_ptr<VulkanCommandPool> command_pool_; std::unique_ptr<VulkanCommandPool> command_pool_;
const VulkanImageUsageCache image_usage_cache_;
DISALLOW_COPY_AND_ASSIGN(ExternalVkImageFactory); DISALLOW_COPY_AND_ASSIGN(ExternalVkImageFactory);
}; };
......
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