blob: ef0590469ddc8a4ece06d635f1665333f4e1d7ad [file] [log] [blame]
// Copyright 2019 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/command_buffer/service/external_vk_image_factory.h"
#include "build/build_config.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/shared_image_representation.h"
#include "gpu/vulkan/vulkan_command_buffer.h"
#include "gpu/vulkan/vulkan_command_pool.h"
#include "gpu/vulkan/vulkan_device_queue.h"
#include "gpu/vulkan/vulkan_fence_helper.h"
#include "gpu/vulkan/vulkan_function_pointers.h"
#include "gpu/vulkan/vulkan_implementation.h"
#include "ui/gfx/buffer_format_util.h"
namespace gpu {
namespace {
VkImageUsageFlags GetMaximalImageUsageFlags(
VkFormatFeatureFlags feature_flags) {
VkImageUsageFlags usage_flags = 0;
// The TRANSFER_SRC/DST format features were added in Vulkan 1.1 and their
// support is required when SAMPLED_IMAGE is supported. In Vulkan 1.0 all
// formats support these features implicitly. See discussion in
// https://github.com/KhronosGroup/Vulkan-Docs/issues/1223
if (feature_flags & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT)
usage_flags |= VK_IMAGE_USAGE_SAMPLED_BIT |
VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
VK_IMAGE_USAGE_TRANSFER_DST_BIT;
// VUID-VkImageViewCreateInfo-usage-02652: support for INPUT_ATTACHMENT is
// implied by both of COLOR_ATTACHNENT and DEPTH_STENCIL_ATTACHMENT
if (feature_flags & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT)
usage_flags |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
if (feature_flags & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)
usage_flags |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT |
VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
if (feature_flags & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT)
usage_flags |= VK_IMAGE_USAGE_STORAGE_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;
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(
scoped_refptr<SharedContextState> context_state)
: context_state_(std::move(context_state)),
command_pool_(context_state_->vk_context_provider()
->GetDeviceQueue()
->CreateCommandPool()),
image_usage_cache_(
CreateImageUsageCache(context_state_->vk_context_provider()
->GetDeviceQueue()
->GetVulkanPhysicalDevice())) {}
ExternalVkImageFactory::~ExternalVkImageFactory() {
if (command_pool_) {
context_state_->vk_context_provider()
->GetDeviceQueue()
->GetFenceHelper()
->EnqueueVulkanObjectCleanupForSubmittedWork(std::move(command_pool_));
}
}
std::unique_ptr<SharedImageBacking> ExternalVkImageFactory::CreateSharedImage(
const Mailbox& mailbox,
viz::ResourceFormat format,
SurfaceHandle surface_handle,
const gfx::Size& size,
const gfx::ColorSpace& color_space,
GrSurfaceOrigin surface_origin,
SkAlphaType alpha_type,
uint32_t usage,
bool is_thread_safe) {
DCHECK(!is_thread_safe);
return ExternalVkImageBacking::Create(
context_state_, command_pool_.get(), mailbox, format, size, color_space,
surface_origin, alpha_type, usage, &image_usage_cache_,
base::span<const uint8_t>());
}
std::unique_ptr<SharedImageBacking> ExternalVkImageFactory::CreateSharedImage(
const Mailbox& mailbox,
viz::ResourceFormat format,
const gfx::Size& size,
const gfx::ColorSpace& color_space,
GrSurfaceOrigin surface_origin,
SkAlphaType alpha_type,
uint32_t usage,
base::span<const uint8_t> pixel_data) {
return ExternalVkImageBacking::Create(
context_state_, command_pool_.get(), mailbox, format, size, color_space,
surface_origin, alpha_type, usage, &image_usage_cache_, pixel_data);
}
std::unique_ptr<SharedImageBacking> ExternalVkImageFactory::CreateSharedImage(
const Mailbox& mailbox,
int client_id,
gfx::GpuMemoryBufferHandle handle,
gfx::BufferFormat buffer_format,
gfx::BufferPlane plane,
SurfaceHandle surface_handle,
const gfx::Size& size,
const gfx::ColorSpace& color_space,
GrSurfaceOrigin surface_origin,
SkAlphaType alpha_type,
uint32_t usage) {
DCHECK(CanImportGpuMemoryBuffer(handle.type));
if (plane != gfx::BufferPlane::DEFAULT) {
LOG(ERROR) << "Invalid plane";
return nullptr;
}
return ExternalVkImageBacking::CreateFromGMB(
context_state_, command_pool_.get(), mailbox, std::move(handle),
buffer_format, size, color_space, surface_origin, alpha_type, usage,
&image_usage_cache_);
}
bool ExternalVkImageFactory::CanImportGpuMemoryBuffer(
gfx::GpuMemoryBufferType memory_buffer_type) {
return context_state_->vk_context_provider()
->GetVulkanImplementation()
->CanImportGpuMemoryBuffer(memory_buffer_type) ||
memory_buffer_type == gfx::SHARED_MEMORY_BUFFER;
}
bool ExternalVkImageFactory::IsSupported(uint32_t usage,
viz::ResourceFormat format,
bool thread_safe,
gfx::GpuMemoryBufferType gmb_type,
GrContextType gr_context_type,
bool* allow_legacy_mailbox,
bool is_pixel_used) {
if (is_pixel_used) {
return false;
}
if (gmb_type != gfx::EMPTY_BUFFER && !CanImportGpuMemoryBuffer(gmb_type)) {
return false;
}
// TODO(crbug.com/969114): Not all shared image factory implementations
// support concurrent read/write usage.
if (usage & SHARED_IMAGE_USAGE_CONCURRENT_READ_WRITE) {
return false;
}
if (thread_safe) {
LOG(ERROR) << "ExternalVkImageFactory currently do not support "
"cross-thread usage.";
return false;
}
#if defined(OS_ANDROID)
// Scanout on Android requires explicit fence synchronization which is only
// supported by the interop factory.
if (usage & SHARED_IMAGE_USAGE_SCANOUT) {
return false;
}
#endif
*allow_legacy_mailbox = false;
return true;
}
} // namespace gpu