Add CreateImage support to MemoryService

This CL introduces SupportsCreateImage and CreateImage to the
external memory service API to provide different implementations for
creating VkImages for different types of external image handles.

While opaque FD and Zircon seem to share the same vkCreateImage
implementation, dma-buf import will require the use of the
VkImageDrmFormatModifierExplicitCreateInfoEXT [1] struct (among
other differences) with vkCreateImage.

[1] https://www.khronos.org/registry/vulkan/specs/1.1-extensions/man/html/VkImageDrmFormatModifierExplicitCreateInfoEXT.html

BUG=chromium:996470

Change-Id: I3eb11f8877d4465f5fcdd4089d5fdd8acbc1da10
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/13781
Reviewed-by: Austin Eng <enga@chromium.org>
Commit-Queue: Brian Ho <hob@chromium.org>
This commit is contained in:
Brian Ho 2019-11-20 23:53:43 +00:00 committed by Commit Bot service account
parent 858f93b86f
commit ae687f5b83
7 changed files with 131 additions and 69 deletions

View File

@ -615,7 +615,7 @@ namespace dawn_native { namespace vulkan {
if (!mExternalSemaphoreService->Supported()) {
return DAWN_VALIDATION_ERROR("External semaphore usage not supported");
}
if (!mExternalMemoryService->Supported(
if (!mExternalMemoryService->SupportsImportMemory(
VulkanImageFormat(textureDescriptor->format), VK_IMAGE_TYPE_2D,
VK_IMAGE_TILING_OPTIMAL,
VulkanImageUsage(textureDescriptor->usage,
@ -683,7 +683,8 @@ namespace dawn_native { namespace vulkan {
// if a failure happems.
Texture* result = nullptr;
// TODO(crbug.com/1026480): Consolidate this into a single CreateFromExternal call.
if (ConsumedError(Texture::CreateFromExternal(this, descriptor, textureDescriptor),
if (ConsumedError(Texture::CreateFromExternal(this, descriptor, textureDescriptor,
mExternalMemoryService.get()),
&result) ||
ConsumedError(ImportExternalImage(descriptor, memoryHandle, result->GetHandle(),
waitHandles, &signalSemaphore, &allocation,

View File

@ -200,22 +200,6 @@ namespace dawn_native { namespace vulkan {
return {extent.width, extent.height, extent.depth};
}
bool IsSampleCountSupported(const dawn_native::vulkan::Device* device,
const VkImageCreateInfo& imageCreateInfo) {
ASSERT(device);
VkPhysicalDevice physicalDevice = ToBackend(device->GetAdapter())->GetPhysicalDevice();
VkImageFormatProperties properties;
if (device->fn.GetPhysicalDeviceImageFormatProperties(
physicalDevice, imageCreateInfo.format, imageCreateInfo.imageType,
imageCreateInfo.tiling, imageCreateInfo.usage, imageCreateInfo.flags,
&properties) != VK_SUCCESS) {
UNREACHABLE();
}
return properties.sampleCounts & imageCreateInfo.samples;
}
} // namespace
// Converts Dawn texture format to Vulkan formats.
@ -397,6 +381,22 @@ namespace dawn_native { namespace vulkan {
return {};
}
bool IsSampleCountSupported(const dawn_native::vulkan::Device* device,
const VkImageCreateInfo& imageCreateInfo) {
ASSERT(device);
VkPhysicalDevice physicalDevice = ToBackend(device->GetAdapter())->GetPhysicalDevice();
VkImageFormatProperties properties;
if (device->fn.GetPhysicalDeviceImageFormatProperties(
physicalDevice, imageCreateInfo.format, imageCreateInfo.imageType,
imageCreateInfo.tiling, imageCreateInfo.usage, imageCreateInfo.flags,
&properties) != VK_SUCCESS) {
UNREACHABLE();
}
return properties.sampleCounts & imageCreateInfo.samples;
}
// static
ResultOrError<Texture*> Texture::Create(Device* device, const TextureDescriptor* descriptor) {
std::unique_ptr<Texture> texture =
@ -409,10 +409,11 @@ namespace dawn_native { namespace vulkan {
ResultOrError<Texture*> Texture::CreateFromExternal(
Device* device,
const ExternalImageDescriptor* descriptor,
const TextureDescriptor* textureDescriptor) {
const TextureDescriptor* textureDescriptor,
external_memory::Service* externalMemoryService) {
std::unique_ptr<Texture> texture =
std::make_unique<Texture>(device, textureDescriptor, TextureState::OwnedInternal);
DAWN_TRY(texture->InitializeFromExternal(descriptor));
DAWN_TRY(texture->InitializeFromExternal(descriptor, externalMemoryService));
return texture.release();
}
@ -481,38 +482,34 @@ namespace dawn_native { namespace vulkan {
}
// Internally managed, but imported from external handle
MaybeError Texture::InitializeFromExternal(const ExternalImageDescriptor* descriptor) {
MaybeError Texture::InitializeFromExternal(const ExternalImageDescriptor* descriptor,
external_memory::Service* externalMemoryService) {
VkFormat format = VulkanImageFormat(GetFormat().format);
if (!externalMemoryService->SupportsCreateImage(descriptor, format)) {
return DAWN_VALIDATION_ERROR("Creating an image from external memory is not supported");
}
mExternalState = ExternalState::PendingAcquire;
Device* device = ToBackend(GetDevice());
VkImageCreateInfo createInfo = {};
createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
createInfo.pNext = nullptr;
createInfo.flags = VK_IMAGE_CREATE_ALIAS_BIT_KHR;
createInfo.imageType = VulkanImageType(GetDimension());
createInfo.format = VulkanImageFormat(GetFormat().format);
createInfo.extent = VulkanExtent3D(GetSize());
createInfo.mipLevels = GetNumMipLevels();
createInfo.arrayLayers = GetArrayLayers();
createInfo.samples = VulkanSampleCount(GetSampleCount());
createInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
createInfo.usage = VulkanImageUsage(GetUsage(), GetFormat());
createInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
createInfo.queueFamilyIndexCount = 0;
createInfo.pQueueFamilyIndices = nullptr;
createInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
ASSERT(IsSampleCountSupported(device, createInfo));
VkImageCreateInfo baseCreateInfo = {};
baseCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
baseCreateInfo.pNext = nullptr;
baseCreateInfo.imageType = VulkanImageType(GetDimension());
baseCreateInfo.format = format;
baseCreateInfo.extent = VulkanExtent3D(GetSize());
baseCreateInfo.mipLevels = GetNumMipLevels();
baseCreateInfo.arrayLayers = GetArrayLayers();
baseCreateInfo.samples = VulkanSampleCount(GetSampleCount());
baseCreateInfo.usage = VulkanImageUsage(GetUsage(), GetFormat());
baseCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
baseCreateInfo.queueFamilyIndexCount = 0;
baseCreateInfo.pQueueFamilyIndices = nullptr;
// We always set VK_IMAGE_USAGE_TRANSFER_DST_BIT unconditionally beause the Vulkan images
// that are used in vkCmdClearColorImage() must have been created with this flag, which is
// also required for the implementation of robust resource initialization.
createInfo.usage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT;
DAWN_TRY(CheckVkSuccess(
device->fn.CreateImage(device->GetVkDevice(), &createInfo, nullptr, &mHandle),
"CreateImage"));
baseCreateInfo.usage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT;
DAWN_TRY_ASSIGN(mHandle, externalMemoryService->CreateImage(descriptor, baseCreateInfo));
return {};
}

View File

@ -20,6 +20,7 @@
#include "common/vulkan_platform.h"
#include "dawn_native/ResourceMemoryAllocation.h"
#include "dawn_native/vulkan/ExternalHandle.h"
#include "dawn_native/vulkan/external_memory/MemoryService.h"
namespace dawn_native { namespace vulkan {
@ -34,6 +35,9 @@ namespace dawn_native { namespace vulkan {
MaybeError ValidateVulkanImageCanBeWrapped(const DeviceBase* device,
const TextureDescriptor* descriptor);
bool IsSampleCountSupported(const dawn_native::vulkan::Device* device,
const VkImageCreateInfo& imageCreateInfo);
class Texture : public TextureBase {
public:
// Used to create a regular texture from a descriptor.
@ -45,7 +49,8 @@ namespace dawn_native { namespace vulkan {
static ResultOrError<Texture*> CreateFromExternal(
Device* device,
const ExternalImageDescriptor* descriptor,
const TextureDescriptor* textureDescriptor);
const TextureDescriptor* textureDescriptor,
external_memory::Service* externalMemoryService);
Texture(Device* device, const TextureDescriptor* descriptor, VkImage nativeImage);
~Texture();
@ -76,7 +81,8 @@ namespace dawn_native { namespace vulkan {
using TextureBase::TextureBase;
MaybeError InitializeAsInternalTexture();
MaybeError InitializeFromExternal(const ExternalImageDescriptor* descriptor);
MaybeError InitializeFromExternal(const ExternalImageDescriptor* descriptor,
external_memory::Service* externalMemoryService);
void DestroyImpl() override;
MaybeError ClearTexture(CommandRecordingContext* recordingContext,

View File

@ -36,12 +36,15 @@ namespace dawn_native { namespace vulkan { namespace external_memory {
explicit Service(Device* device);
~Service();
// True if the device reports it supports this feature
bool Supported(VkFormat format,
VkImageType type,
VkImageTiling tiling,
VkImageUsageFlags usage,
VkImageCreateFlags flags);
// True if the device reports it supports importing external memory.
bool SupportsImportMemory(VkFormat format,
VkImageType type,
VkImageTiling tiling,
VkImageUsageFlags usage,
VkImageCreateFlags flags);
// True if the device reports it supports creating VkImages from external memory.
bool SupportsCreateImage(const ExternalImageDescriptor* descriptor, VkFormat format);
// Returns the parameters required for importing memory
ResultOrError<MemoryImportParams> GetMemoryImportParams(
@ -53,6 +56,10 @@ namespace dawn_native { namespace vulkan { namespace external_memory {
const MemoryImportParams& importParams,
VkImage image);
// Create a VkImage for the given handle type
ResultOrError<VkImage> CreateImage(const ExternalImageDescriptor* descriptor,
const VkImageCreateInfo& baseCreateInfo);
private:
Device* mDevice = nullptr;

View File

@ -24,11 +24,15 @@ namespace dawn_native { namespace vulkan { namespace external_memory {
Service::~Service() = default;
bool Service::Supported(VkFormat format,
VkImageType type,
VkImageTiling tiling,
VkImageUsageFlags usage,
VkImageCreateFlags flags) {
bool Service::SupportsImportMemory(VkFormat format,
VkImageType type,
VkImageTiling tiling,
VkImageUsageFlags usage,
VkImageCreateFlags flags) {
return false;
}
bool Service::SupportsCreateImage(const ExternalImageDescriptor* descriptor, VkFormat format) {
return false;
}
@ -44,4 +48,9 @@ namespace dawn_native { namespace vulkan { namespace external_memory {
return DAWN_UNIMPLEMENTED_ERROR("Using null memory service to interop inside Vulkan");
}
ResultOrError<VkImage> Service::CreateImage(const ExternalImageDescriptor* descriptor,
const VkImageCreateInfo& baseCreateInfo) {
return DAWN_UNIMPLEMENTED_ERROR("Using null memory service to interop inside Vulkan");
}
}}} // namespace dawn_native::vulkan::external_memory

View File

@ -16,6 +16,7 @@
#include "dawn_native/vulkan/AdapterVk.h"
#include "dawn_native/vulkan/BackendVk.h"
#include "dawn_native/vulkan/DeviceVk.h"
#include "dawn_native/vulkan/TextureVk.h"
#include "dawn_native/vulkan/VulkanError.h"
#include "dawn_native/vulkan/external_memory/MemoryService.h"
@ -33,11 +34,11 @@ namespace dawn_native { namespace vulkan { namespace external_memory {
Service::~Service() = default;
bool Service::Supported(VkFormat format,
VkImageType type,
VkImageTiling tiling,
VkImageUsageFlags usage,
VkImageCreateFlags flags) {
bool Service::SupportsImportMemory(VkFormat format,
VkImageType type,
VkImageTiling tiling,
VkImageUsageFlags usage,
VkImageCreateFlags flags) {
// Early out before we try using extension functions
if (!mSupported) {
return false;
@ -80,6 +81,10 @@ namespace dawn_native { namespace vulkan { namespace external_memory {
!(memoryFlags & VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT_KHR);
}
bool Service::SupportsCreateImage(const ExternalImageDescriptor* descriptor, VkFormat format) {
return mSupported;
}
ResultOrError<MemoryImportParams> Service::GetMemoryImportParams(
const ExternalImageDescriptor* descriptor,
VkImage image) {
@ -113,4 +118,20 @@ namespace dawn_native { namespace vulkan { namespace external_memory {
return allocatedMemory;
}
ResultOrError<VkImage> Service::CreateImage(const ExternalImageDescriptor* descriptor,
const VkImageCreateInfo& baseCreateInfo) {
VkImageCreateInfo createInfo = baseCreateInfo;
createInfo.flags = VK_IMAGE_CREATE_ALIAS_BIT_KHR;
createInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
createInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
ASSERT(IsSampleCountSupported(mDevice, createInfo));
VkImage image;
DAWN_TRY(CheckVkSuccess(
mDevice->fn.CreateImage(mDevice->GetVkDevice(), &createInfo, nullptr, &image),
"CreateImage"));
return image;
}
}}} // namespace dawn_native::vulkan::external_memory

View File

@ -16,6 +16,7 @@
#include "dawn_native/vulkan/AdapterVk.h"
#include "dawn_native/vulkan/BackendVk.h"
#include "dawn_native/vulkan/DeviceVk.h"
#include "dawn_native/vulkan/TextureVk.h"
#include "dawn_native/vulkan/VulkanError.h"
#include "dawn_native/vulkan/external_memory/MemoryService.h"
@ -33,11 +34,11 @@ namespace dawn_native { namespace vulkan { namespace external_memory {
Service::~Service() = default;
bool Service::Supported(VkFormat format,
VkImageType type,
VkImageTiling tiling,
VkImageUsageFlags usage,
VkImageCreateFlags flags) {
bool Service::SupportsImportMemory(VkFormat format,
VkImageType type,
VkImageTiling tiling,
VkImageUsageFlags usage,
VkImageCreateFlags flags) {
// Early out before we try using extension functions
if (!mSupported) {
return false;
@ -80,6 +81,10 @@ namespace dawn_native { namespace vulkan { namespace external_memory {
!(memoryFlags & VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT_KHR);
}
bool Service::SupportsCreateImage(const ExternalImageDescriptor* descriptor, VkFormat format) {
return mSupported;
}
ResultOrError<MemoryImportParams> Service::GetMemoryImportParams(
const ExternalImageDescriptor* descriptor,
VkImage image) {
@ -115,4 +120,20 @@ namespace dawn_native { namespace vulkan { namespace external_memory {
return allocatedMemory;
}
ResultOrError<VkImage> Service::CreateImage(const ExternalImageDescriptor* descriptor,
const VkImageCreateInfo& baseCreateInfo) {
VkImageCreateInfo createInfo = baseCreateInfo;
createInfo.flags = VK_IMAGE_CREATE_ALIAS_BIT_KHR;
createInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
createInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
ASSERT(IsSampleCountSupported(mDevice, createInfo));
VkImage image;
DAWN_TRY(CheckVkSuccess(
mDevice->fn.CreateImage(mDevice->GetVkDevice(), &createInfo, nullptr, &image),
"CreateImage"));
return image;
}
}}} // namespace dawn_native::vulkan::external_memory