Pass the old/new VkImageLayouts to Vulkan image import/export

Returning the layouts from an export operation and then using
them in a subsequent import operation allows the import to preserve
the texture contents.

This fixes Vukan image wrapping on some AMD/NVIDIA devices.

Bug: dawn:200
Change-Id: Icbb6e759856d410bb69724b9f439bc3088756d19
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/28380
Commit-Queue: Austin Eng <enga@chromium.org>
Reviewed-by: Kai Ninomiya <kainino@chromium.org>
This commit is contained in:
Austin Eng 2020-09-22 20:10:46 +00:00 committed by Commit Bot service account
parent 670858da9b
commit 0b29732cd8
19 changed files with 635 additions and 377 deletions

View File

@ -195,8 +195,14 @@ namespace dawn_native {
return GetProcMapNamesForTestingInternal();
}
ExternalImageDescriptor::ExternalImageDescriptor(ExternalImageDescriptorType type)
: type(type) {
// ExternalImageDescriptor
ExternalImageDescriptor::ExternalImageDescriptor(ExternalImageType type) : type(type) {
}
// ExternalImageExportInfo
ExternalImageExportInfo::ExternalImageExportInfo(ExternalImageType type) : type(type) {
}
} // namespace dawn_native

View File

@ -48,7 +48,7 @@ namespace dawn_native { namespace d3d12 {
}
ExternalImageDescriptorDXGISharedHandle::ExternalImageDescriptorDXGISharedHandle()
: ExternalImageDescriptor(ExternalImageDescriptorType::DXGISharedHandle) {
: ExternalImageDescriptor(ExternalImageType::DXGISharedHandle) {
}
uint64_t SetExternalMemoryReservation(WGPUDevice device,

View File

@ -396,7 +396,7 @@ namespace dawn_native { namespace d3d12 {
AcquireRef(new Texture(device, textureDescriptor, TextureState::OwnedExternal));
DAWN_TRY(dawnTexture->InitializeAsExternalTexture(textureDescriptor, sharedHandle,
acquireMutexKey, isSwapChainTexture));
dawnTexture->SetIsSubresourceContentInitialized(descriptor->isCleared,
dawnTexture->SetIsSubresourceContentInitialized(descriptor->isInitialized,
dawnTexture->GetAllSubresources());
return std::move(dawnTexture);
}

View File

@ -28,7 +28,7 @@ namespace dawn_native { namespace metal {
}
ExternalImageDescriptorIOSurface::ExternalImageDescriptorIOSurface()
: ExternalImageDescriptor(ExternalImageDescriptorType::IOSurface) {
: ExternalImageDescriptor(ExternalImageType::IOSurface) {
}
WGPUTexture WrapIOSurface(WGPUDevice cDevice,

View File

@ -355,7 +355,7 @@ namespace dawn_native { namespace metal {
plane:plane];
[mtlDesc release];
SetIsSubresourceContentInitialized(descriptor->isCleared, GetAllSubresources());
SetIsSubresourceContentInitialized(descriptor->isInitialized, GetAllSubresources());
}
Texture::~Texture() {

View File

@ -658,7 +658,7 @@ namespace dawn_native { namespace vulkan {
return {};
}
MaybeError Device::ImportExternalImage(const ExternalImageDescriptor* descriptor,
MaybeError Device::ImportExternalImage(const ExternalImageDescriptorVk* descriptor,
ExternalMemoryHandle memoryHandle,
VkImage image,
const std::vector<ExternalSemaphoreHandle>& waitHandles,
@ -702,22 +702,35 @@ namespace dawn_native { namespace vulkan {
return {};
}
MaybeError Device::SignalAndExportExternalTexture(Texture* texture,
ExternalSemaphoreHandle* outHandle) {
DAWN_TRY(ValidateObject(texture));
bool Device::SignalAndExportExternalTexture(
Texture* texture,
VkImageLayout desiredLayout,
ExternalImageExportInfoVk* info,
std::vector<ExternalSemaphoreHandle>* semaphoreHandles) {
return !ConsumedError([&]() -> MaybeError {
DAWN_TRY(ValidateObject(texture));
VkSemaphore outSignalSemaphore;
DAWN_TRY(texture->SignalAndDestroy(&outSignalSemaphore));
VkSemaphore signalSemaphore;
VkImageLayout releasedOldLayout;
VkImageLayout releasedNewLayout;
DAWN_TRY(texture->ExportExternalTexture(desiredLayout, &signalSemaphore,
&releasedOldLayout, &releasedNewLayout));
// This has to happen right after SignalAndDestroy, since the semaphore will be
// deleted when the fenced deleter runs after the queue submission
DAWN_TRY_ASSIGN(*outHandle, mExternalSemaphoreService->ExportSemaphore(outSignalSemaphore));
ExternalSemaphoreHandle semaphoreHandle;
DAWN_TRY_ASSIGN(semaphoreHandle,
mExternalSemaphoreService->ExportSemaphore(signalSemaphore));
semaphoreHandles->push_back(semaphoreHandle);
info->releasedOldLayout = releasedOldLayout;
info->releasedNewLayout = releasedNewLayout;
info->isInitialized =
texture->IsSubresourceContentInitialized(texture->GetAllSubresources());
return {};
return {};
}());
}
TextureBase* Device::CreateTextureWrappingVulkanImage(
const ExternalImageDescriptor* descriptor,
const ExternalImageDescriptorVk* descriptor,
ExternalMemoryHandle memoryHandle,
const std::vector<ExternalSemaphoreHandle>& waitHandles) {
const TextureDescriptor* textureDescriptor =

View File

@ -69,12 +69,13 @@ namespace dawn_native { namespace vulkan {
// Dawn Native API
TextureBase* CreateTextureWrappingVulkanImage(
const ExternalImageDescriptor* descriptor,
const ExternalImageDescriptorVk* descriptor,
ExternalMemoryHandle memoryHandle,
const std::vector<ExternalSemaphoreHandle>& waitHandles);
MaybeError SignalAndExportExternalTexture(Texture* texture,
ExternalSemaphoreHandle* outHandle);
bool SignalAndExportExternalTexture(Texture* texture,
VkImageLayout desiredLayout,
ExternalImageExportInfoVk* info,
std::vector<ExternalSemaphoreHandle>* semaphoreHandle);
// Dawn API
CommandBufferBase* CreateCommandBuffer(CommandEncoder* encoder,
@ -192,7 +193,7 @@ namespace dawn_native { namespace vulkan {
// There is always a valid recording context stored in mRecordingContext
CommandRecordingContext mRecordingContext;
MaybeError ImportExternalImage(const ExternalImageDescriptor* descriptor,
MaybeError ImportExternalImage(const ExternalImageDescriptorVk* descriptor,
ExternalMemoryHandle memoryHandle,
VkImage image,
const std::vector<ExternalSemaphoreHandle>& waitHandles,
@ -203,4 +204,4 @@ namespace dawn_native { namespace vulkan {
}} // namespace dawn_native::vulkan
#endif // DAWNNATIVE_VULKAN_DEVICEVK_H_
#endif // DAWNNATIVE_VULKAN_DEVICEVK_H_

View File

@ -462,7 +462,7 @@ namespace dawn_native { namespace vulkan {
// static
ResultOrError<Texture*> Texture::CreateFromExternal(
Device* device,
const ExternalImageDescriptor* descriptor,
const ExternalImageDescriptorVk* descriptor,
const TextureDescriptor* textureDescriptor,
external_memory::Service* externalMemoryService) {
Ref<Texture> texture =
@ -537,7 +537,7 @@ namespace dawn_native { namespace vulkan {
}
// Internally managed, but imported from external handle
MaybeError Texture::InitializeFromExternal(const ExternalImageDescriptor* descriptor,
MaybeError Texture::InitializeFromExternal(const ExternalImageDescriptorVk* descriptor,
external_memory::Service* externalMemoryService) {
VkFormat format = VulkanImageFormat(ToBackend(GetDevice()), GetFormat().format);
VkImageUsageFlags usage = VulkanImageUsage(GetUsage(), GetFormat());
@ -547,6 +547,9 @@ namespace dawn_native { namespace vulkan {
mExternalState = ExternalState::PendingAcquire;
mPendingAcquireOldLayout = descriptor->releasedOldLayout;
mPendingAcquireNewLayout = descriptor->releasedNewLayout;
VkImageCreateInfo baseCreateInfo = {};
FillVulkanCreateInfoSizesAndType(*this, &baseCreateInfo);
@ -571,7 +574,7 @@ namespace dawn_native { namespace vulkan {
mHandle = nativeImage;
}
MaybeError Texture::BindExternalMemory(const ExternalImageDescriptor* descriptor,
MaybeError Texture::BindExternalMemory(const ExternalImageDescriptorVk* descriptor,
VkSemaphore signalSemaphore,
VkDeviceMemory externalMemoryAllocation,
std::vector<VkSemaphore> waitSemaphores) {
@ -580,8 +583,8 @@ namespace dawn_native { namespace vulkan {
device->fn.BindImageMemory(device->GetVkDevice(), mHandle, externalMemoryAllocation, 0),
"BindImageMemory (external)"));
// Don't clear imported texture if already cleared
if (descriptor->isCleared) {
// Don't clear imported texture if already initialized
if (descriptor->isInitialized) {
SetIsSubresourceContentInitialized(true, GetAllSubresources());
}
@ -592,7 +595,10 @@ namespace dawn_native { namespace vulkan {
return {};
}
MaybeError Texture::SignalAndDestroy(VkSemaphore* outSignalSemaphore) {
MaybeError Texture::ExportExternalTexture(VkImageLayout desiredLayout,
VkSemaphore* signalSemaphore,
VkImageLayout* releasedOldLayout,
VkImageLayout* releasedNewLayout) {
Device* device = ToBackend(GetDevice());
if (mExternalState == ExternalState::Released) {
@ -605,17 +611,60 @@ namespace dawn_native { namespace vulkan {
}
ASSERT(mSignalSemaphore != VK_NULL_HANDLE);
ASSERT(GetNumMipLevels() == 1 && GetArrayLayers() == 1);
// Release the texture
mExternalState = ExternalState::PendingRelease;
TransitionFullUsage(device->GetPendingRecordingContext(), wgpu::TextureUsage::None);
mExternalState = ExternalState::Released;
wgpu::TextureUsage usage = mSubresourceLastUsages[0];
VkImageMemoryBarrier barrier;
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
barrier.pNext = nullptr;
barrier.image = GetHandle();
barrier.subresourceRange.aspectMask = VulkanAspectMask(GetFormat().aspects);
barrier.subresourceRange.baseMipLevel = 0;
barrier.subresourceRange.levelCount = 1;
barrier.subresourceRange.baseArrayLayer = 0;
barrier.subresourceRange.layerCount = 1;
barrier.srcAccessMask = VulkanAccessFlags(usage, GetFormat());
barrier.dstAccessMask = 0; // The barrier must be paired with another barrier that will
// specify the dst access mask on the importing queue.
barrier.oldLayout = VulkanImageLayout(usage, GetFormat());
if (desiredLayout == VK_IMAGE_LAYOUT_UNDEFINED) {
// VK_IMAGE_LAYOUT_UNDEFINED is invalid here. We use it as a
// special value to indicate no layout transition should be done.
barrier.newLayout = barrier.oldLayout;
} else {
barrier.newLayout = desiredLayout;
}
barrier.srcQueueFamilyIndex = device->GetGraphicsQueueFamily();
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_EXTERNAL_KHR;
VkPipelineStageFlags srcStages = VulkanPipelineStage(usage, GetFormat());
VkPipelineStageFlags dstStages =
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; // We don't know when the importing queue will need
// the texture, so pass
// VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT to ensure
// the barrier happens-before any usage in the
// importing queue.
CommandRecordingContext* recordingContext = device->GetPendingRecordingContext();
device->fn.CmdPipelineBarrier(recordingContext->commandBuffer, srcStages, dstStages, 0, 0,
nullptr, 0, nullptr, 1, &barrier);
// Queue submit to signal we are done with the texture
device->GetPendingRecordingContext()->signalSemaphores.push_back(mSignalSemaphore);
recordingContext->signalSemaphores.push_back(mSignalSemaphore);
DAWN_TRY(device->SubmitPendingCommands());
// Write out the signal semaphore
*outSignalSemaphore = mSignalSemaphore;
// Write out the layouts and signal semaphore
*releasedOldLayout = barrier.oldLayout;
*releasedNewLayout = barrier.newLayout;
*signalSemaphore = mSignalSemaphore;
mSignalSemaphore = VK_NULL_HANDLE;
// Destroy the texture so it can't be used again
@ -688,26 +737,58 @@ namespace dawn_native { namespace vulkan {
SubresourceRange::SingleMipAndLayer(0, 0, GetFormat().aspects)));
}
VkImageMemoryBarrier* barrier = &(*barriers)[transitionBarrierStart];
// Transfer texture from external queue to graphics queue
(*barriers)[transitionBarrierStart].srcQueueFamilyIndex = VK_QUEUE_FAMILY_EXTERNAL_KHR;
(*barriers)[transitionBarrierStart].dstQueueFamilyIndex =
ToBackend(GetDevice())->GetGraphicsQueueFamily();
// Don't override oldLayout to leave it as VK_IMAGE_LAYOUT_UNDEFINED
// TODO(http://crbug.com/dawn/200)
mExternalState = ExternalState::Acquired;
} else if (mExternalState == ExternalState::PendingRelease) {
if (barriers->size() == transitionBarrierStart) {
barriers->push_back(BuildMemoryBarrier(
GetFormat(), mHandle, wgpu::TextureUsage::None, wgpu::TextureUsage::None,
SubresourceRange::SingleMipAndLayer(0, 0, GetFormat().aspects)));
barrier->srcQueueFamilyIndex = VK_QUEUE_FAMILY_EXTERNAL_KHR;
barrier->dstQueueFamilyIndex = ToBackend(GetDevice())->GetGraphicsQueueFamily();
// srcAccessMask means nothing when importing. Queue transfers require a barrier on
// both the importing and exporting queues. The exporting queue should have specified
// this.
barrier->srcAccessMask = 0;
// This should be the first barrier after import.
ASSERT(barrier->oldLayout == VK_IMAGE_LAYOUT_UNDEFINED);
// Save the desired layout. We may need to transition through an intermediate
// |mPendingAcquireLayout| first.
VkImageLayout desiredLayout = barrier->newLayout;
bool isInitialized = IsSubresourceContentInitialized(GetAllSubresources());
// We don't care about the pending old layout if the texture is uninitialized. The
// driver is free to discard it. Likewise, we don't care about the pending new layout if
// the texture is uninitialized. We can skip the layout transition.
if (!isInitialized) {
barrier->oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
barrier->newLayout = desiredLayout;
} else {
barrier->oldLayout = mPendingAcquireOldLayout;
barrier->newLayout = mPendingAcquireNewLayout;
}
// Transfer texture from graphics queue to external queue
(*barriers)[transitionBarrierStart].srcQueueFamilyIndex =
ToBackend(GetDevice())->GetGraphicsQueueFamily();
(*barriers)[transitionBarrierStart].dstQueueFamilyIndex = VK_QUEUE_FAMILY_EXTERNAL_KHR;
(*barriers)[transitionBarrierStart].newLayout = VK_IMAGE_LAYOUT_GENERAL;
mExternalState = ExternalState::Released;
// If these are unequal, we need an another barrier to transition the layout.
if (barrier->newLayout != desiredLayout) {
VkImageMemoryBarrier layoutBarrier;
layoutBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
layoutBarrier.pNext = nullptr;
layoutBarrier.image = GetHandle();
layoutBarrier.subresourceRange = barrier->subresourceRange;
// Transition from the acquired new layout to the desired layout.
layoutBarrier.oldLayout = barrier->newLayout;
layoutBarrier.newLayout = desiredLayout;
// We already transitioned these.
layoutBarrier.srcAccessMask = 0;
layoutBarrier.dstAccessMask = 0;
layoutBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
layoutBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barriers->push_back(layoutBarrier);
}
mExternalState = ExternalState::Acquired;
}
mLastExternalState = mExternalState;

View File

@ -49,7 +49,7 @@ namespace dawn_native { namespace vulkan {
// image must be bound via Texture::BindExternalMemory.
static ResultOrError<Texture*> CreateFromExternal(
Device* device,
const ExternalImageDescriptor* descriptor,
const ExternalImageDescriptorVk* descriptor,
const TextureDescriptor* textureDescriptor,
external_memory::Service* externalMemoryService);
@ -84,20 +84,24 @@ namespace dawn_native { namespace vulkan {
void EnsureSubresourceContentInitialized(CommandRecordingContext* recordingContext,
const SubresourceRange& range);
MaybeError SignalAndDestroy(VkSemaphore* outSignalSemaphore);
// Binds externally allocated memory to the VkImage and on success, takes ownership of
// semaphores.
MaybeError BindExternalMemory(const ExternalImageDescriptor* descriptor,
MaybeError BindExternalMemory(const ExternalImageDescriptorVk* descriptor,
VkSemaphore signalSemaphore,
VkDeviceMemory externalMemoryAllocation,
std::vector<VkSemaphore> waitSemaphores);
MaybeError ExportExternalTexture(VkImageLayout desiredLayout,
VkSemaphore* signalSemaphore,
VkImageLayout* releasedOldLayout,
VkImageLayout* releasedNewLayout);
private:
~Texture() override;
using TextureBase::TextureBase;
MaybeError InitializeAsInternalTexture();
MaybeError InitializeFromExternal(const ExternalImageDescriptor* descriptor,
MaybeError InitializeFromExternal(const ExternalImageDescriptorVk* descriptor,
external_memory::Service* externalMemoryService);
void InitializeForSwapChain(VkImage nativeImage);
@ -119,12 +123,14 @@ namespace dawn_native { namespace vulkan {
InternalOnly,
PendingAcquire,
Acquired,
PendingRelease,
Released
};
ExternalState mExternalState = ExternalState::InternalOnly;
ExternalState mLastExternalState = ExternalState::InternalOnly;
VkImageLayout mPendingAcquireOldLayout;
VkImageLayout mPendingAcquireNewLayout;
VkSemaphore mSignalSemaphore = VK_NULL_HANDLE;
std::vector<VkSemaphore> mWaitRequirements;

View File

@ -59,51 +59,75 @@ namespace dawn_native { namespace vulkan {
return static_cast<WGPUTextureFormat>(impl->GetPreferredFormat());
}
#ifdef DAWN_PLATFORM_LINUX
ExternalImageDescriptorFD::ExternalImageDescriptorFD(ExternalImageDescriptorType descType)
: ExternalImageDescriptor(descType) {
}
#if defined(DAWN_PLATFORM_LINUX)
ExternalImageDescriptorOpaqueFD::ExternalImageDescriptorOpaqueFD()
: ExternalImageDescriptorFD(ExternalImageDescriptorType::OpaqueFD) {
: ExternalImageDescriptorFD(ExternalImageType::OpaqueFD) {
}
ExternalImageDescriptorDmaBuf::ExternalImageDescriptorDmaBuf()
: ExternalImageDescriptorFD(ExternalImageDescriptorType::DmaBuf) {
: ExternalImageDescriptorFD(ExternalImageType::DmaBuf) {
}
ExternalImageExportInfoOpaqueFD::ExternalImageExportInfoOpaqueFD()
: ExternalImageExportInfoFD(ExternalImageType::OpaqueFD) {
}
ExternalImageExportInfoDmaBuf::ExternalImageExportInfoDmaBuf()
: ExternalImageExportInfoFD(ExternalImageType::DmaBuf) {
}
int ExportSignalSemaphoreOpaqueFD(WGPUDevice cDevice, WGPUTexture cTexture) {
// Doesn't actually matter if we use OpaqueFD or DmaBuf since these paths are the same right
// now. This function will be removed.
Device* device = reinterpret_cast<Device*>(cDevice);
Texture* texture = reinterpret_cast<Texture*>(cTexture);
if (!texture) {
device->EmitDeprecationWarning(
"ExportSignalSemaphoreOpaqueFD is deprecated. Please use ExportVulkanImage instead.");
ExternalImageExportInfoOpaqueFD info;
if (!ExportVulkanImage(cTexture, VK_IMAGE_LAYOUT_GENERAL, &info)) {
return -1;
}
ExternalSemaphoreHandle outHandle;
if (device->ConsumedError(device->SignalAndExportExternalTexture(texture, &outHandle))) {
return -1;
}
return outHandle;
return info.semaphoreHandles[0];
}
#endif // DAWN_PLATFORM_LINUX
WGPUTexture WrapVulkanImage(WGPUDevice cDevice, const ExternalImageDescriptor* descriptor) {
Device* device = reinterpret_cast<Device*>(cDevice);
WGPUTexture WrapVulkanImage(WGPUDevice cDevice, const ExternalImageDescriptorVk* descriptor) {
switch (descriptor->type) {
case ExternalImageDescriptorType::OpaqueFD:
case ExternalImageDescriptorType::DmaBuf: {
#if defined(DAWN_PLATFORM_LINUX)
case ExternalImageType::OpaqueFD:
case ExternalImageType::DmaBuf: {
const ExternalImageDescriptorFD* fdDescriptor =
static_cast<const ExternalImageDescriptorFD*>(descriptor);
Device* device = reinterpret_cast<Device*>(cDevice);
TextureBase* texture = device->CreateTextureWrappingVulkanImage(
descriptor, fdDescriptor->memoryFD, fdDescriptor->waitFDs);
fdDescriptor, fdDescriptor->memoryFD, fdDescriptor->waitFDs);
return reinterpret_cast<WGPUTexture>(texture);
}
#endif // DAWN_PLATFORM_LINUX
default:
return nullptr;
}
}
#endif
bool ExportVulkanImage(WGPUTexture cTexture,
VkImageLayout desiredLayout,
ExternalImageExportInfoVk* info) {
if (cTexture == nullptr) {
return false;
}
switch (info->type) {
#if defined(DAWN_PLATFORM_LINUX)
case ExternalImageType::OpaqueFD:
case ExternalImageType::DmaBuf: {
Texture* texture = reinterpret_cast<Texture*>(cTexture);
Device* device = ToBackend(texture->GetDevice());
ExternalImageExportInfoFD* fdInfo = static_cast<ExternalImageExportInfoFD*>(info);
return device->SignalAndExportExternalTexture(texture, desiredLayout, fdInfo,
&fdInfo->semaphoreHandles);
}
#endif // DAWN_PLATFORM_LINUX
default:
return false;
}
}
}} // namespace dawn_native::vulkan

View File

@ -83,7 +83,7 @@ namespace dawn_native { namespace vulkan { namespace external_memory {
if (!mSupported) {
return false;
}
if (descriptor->type != ExternalImageDescriptorType::DmaBuf) {
if (descriptor->type != ExternalImageType::DmaBuf) {
return false;
}
const ExternalImageDescriptorDmaBuf* dmaBufDescriptor =
@ -150,7 +150,7 @@ namespace dawn_native { namespace vulkan { namespace external_memory {
ResultOrError<MemoryImportParams> Service::GetMemoryImportParams(
const ExternalImageDescriptor* descriptor,
VkImage image) {
if (descriptor->type != ExternalImageDescriptorType::DmaBuf) {
if (descriptor->type != ExternalImageType::DmaBuf) {
return DAWN_VALIDATION_ERROR("ExternalImageDescriptor is not a dma-buf descriptor");
}
const ExternalImageDescriptorDmaBuf* dmaBufDescriptor =
@ -216,7 +216,7 @@ namespace dawn_native { namespace vulkan { namespace external_memory {
ResultOrError<VkImage> Service::CreateImage(const ExternalImageDescriptor* descriptor,
const VkImageCreateInfo& baseCreateInfo) {
if (descriptor->type != ExternalImageDescriptorType::DmaBuf) {
if (descriptor->type != ExternalImageType::DmaBuf) {
return DAWN_VALIDATION_ERROR("ExternalImageDescriptor is not a dma-buf descriptor");
}
const ExternalImageDescriptorDmaBuf* dmaBufDescriptor =

View File

@ -71,8 +71,7 @@ namespace dawn_native { namespace vulkan { namespace external_memory {
// TODO(http://crbug.com/dawn/206): Investigate dedicated only images
VkFlags memoryFlags =
externalFormatProperties.externalMemoryProperties.externalMemoryFeatures;
return (memoryFlags & VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT_KHR) &&
!(memoryFlags & VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT_KHR);
return (memoryFlags & VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT_KHR) != 0;
}
bool Service::SupportsCreateImage(const ExternalImageDescriptor* descriptor,
@ -84,7 +83,7 @@ namespace dawn_native { namespace vulkan { namespace external_memory {
ResultOrError<MemoryImportParams> Service::GetMemoryImportParams(
const ExternalImageDescriptor* descriptor,
VkImage image) {
if (descriptor->type != ExternalImageDescriptorType::OpaqueFD) {
if (descriptor->type != ExternalImageType::OpaqueFD) {
return DAWN_VALIDATION_ERROR("ExternalImageDescriptor is not an OpaqueFD descriptor");
}
const ExternalImageDescriptorOpaqueFD* opaqueFDDescriptor =

View File

@ -71,8 +71,7 @@ namespace dawn_native { namespace vulkan { namespace external_memory {
// TODO(http://crbug.com/dawn/206): Investigate dedicated only images
VkFlags memoryFlags =
externalFormatProperties.externalMemoryProperties.externalMemoryFeatures;
return (memoryFlags & VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT_KHR) &&
!(memoryFlags & VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT_KHR);
return (memoryFlags & VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT_KHR) != 0;
}
bool Service::SupportsCreateImage(const ExternalImageDescriptor* descriptor,
@ -84,7 +83,7 @@ namespace dawn_native { namespace vulkan { namespace external_memory {
ResultOrError<MemoryImportParams> Service::GetMemoryImportParams(
const ExternalImageDescriptor* descriptor,
VkImage image) {
if (descriptor->type != ExternalImageDescriptorType::OpaqueFD) {
if (descriptor->type != ExternalImageType::OpaqueFD) {
return DAWN_VALIDATION_ERROR("ExternalImageDescriptor is not an OpaqueFD descriptor");
}
const ExternalImageDescriptorOpaqueFD* opaqueFDDescriptor =

View File

@ -200,8 +200,8 @@ namespace dawn_native {
DAWN_NATIVE_EXPORT uint64_t AcquireErrorInjectorCallCount();
DAWN_NATIVE_EXPORT void InjectErrorAt(uint64_t index);
// The different types of ExternalImageDescriptors
enum ExternalImageDescriptorType {
// The different types of external images
enum ExternalImageType {
OpaqueFD,
DmaBuf,
IOSurface,
@ -211,13 +211,26 @@ namespace dawn_native {
// Common properties of external images
struct DAWN_NATIVE_EXPORT ExternalImageDescriptor {
public:
const ExternalImageDescriptorType type;
const ExternalImageType type;
const WGPUTextureDescriptor* cTextureDescriptor; // Must match image creation params
bool isCleared; // Sets whether the texture will be cleared before use
union {
bool isInitialized; // Whether the texture is initialized on import
bool isCleared; // DEPRECATED: Sets whether the texture will be cleared before use
};
protected:
ExternalImageDescriptor(ExternalImageDescriptorType type);
ExternalImageDescriptor(ExternalImageType type);
};
struct DAWN_NATIVE_EXPORT ExternalImageExportInfo {
public:
const ExternalImageType type;
bool isInitialized; // Whether the texture is initialized after export
protected:
ExternalImageExportInfo(ExternalImageType type);
};
} // namespace dawn_native
#endif // DAWNNATIVE_DAWNNATIVE_H_

View File

@ -33,19 +33,49 @@ namespace dawn_native { namespace vulkan {
DAWN_NATIVE_EXPORT WGPUTextureFormat
GetNativeSwapChainPreferredFormat(const DawnSwapChainImplementation* swapChain);
// Can't use DAWN_PLATFORM_LINUX since header included in both dawn and chrome
struct DAWN_NATIVE_EXPORT ExternalImageDescriptorVk : ExternalImageDescriptor {
public:
// The following members may be ignored if |ExternalImageDescriptor::isInitialized| is false
// since the import does not need to preserve texture contents.
// See https://www.khronos.org/registry/vulkan/specs/1.1/html/chap7.html. The acquire
// operation old/new layouts must match exactly the layouts in the release operation. So
// we may need to issue two barriers releasedOldLayout -> releasedNewLayout ->
// cTextureDescriptor.usage if the new layout is not compatible with the desired usage.
// The first barrier is the queue transfer, the second is the layout transition to our
// desired usage.
VkImageLayout releasedOldLayout = VK_IMAGE_LAYOUT_GENERAL;
VkImageLayout releasedNewLayout = VK_IMAGE_LAYOUT_GENERAL;
protected:
using ExternalImageDescriptor::ExternalImageDescriptor;
};
struct ExternalImageExportInfoVk : ExternalImageExportInfo {
public:
// See comments in |ExternalImageDescriptorVk|
// Contains the old/new layouts used in the queue release operation.
VkImageLayout releasedOldLayout;
VkImageLayout releasedNewLayout;
protected:
using ExternalImageExportInfo::ExternalImageExportInfo;
};
// Can't use DAWN_PLATFORM_LINUX since header included in both Dawn and Chrome
#ifdef __linux__
// Common properties of external images represented by FDs. On successful import the file
// descriptor's ownership is transferred to the Dawn implementation and they shouldn't be
// used outside of Dawn again. TODO(enga): Also transfer ownership in the error case so the
// caller can assume the FD is always consumed.
struct DAWN_NATIVE_EXPORT ExternalImageDescriptorFD : ExternalImageDescriptor {
struct DAWN_NATIVE_EXPORT ExternalImageDescriptorFD : ExternalImageDescriptorVk {
public:
int memoryFD; // A file descriptor from an export of the memory of the image
std::vector<int> waitFDs; // File descriptors of semaphores which will be waited on
protected:
ExternalImageDescriptorFD(ExternalImageDescriptorType type);
using ExternalImageDescriptorVk::ExternalImageDescriptorVk;
};
// Descriptor for opaque file descriptor image import
@ -64,8 +94,29 @@ namespace dawn_native { namespace vulkan {
uint64_t drmModifier; // DRM modifier of the buffer
};
// Info struct that is written to in |ExportVulkanImage|.
struct DAWN_NATIVE_EXPORT ExternalImageExportInfoFD : ExternalImageExportInfoVk {
public:
// Contains the exported semaphore handles.
std::vector<int> semaphoreHandles;
protected:
using ExternalImageExportInfoVk::ExternalImageExportInfoVk;
};
struct DAWN_NATIVE_EXPORT ExternalImageExportInfoOpaqueFD : ExternalImageExportInfoFD {
ExternalImageExportInfoOpaqueFD();
};
struct DAWN_NATIVE_EXPORT ExternalImageExportInfoDmaBuf : ExternalImageExportInfoFD {
ExternalImageExportInfoDmaBuf();
};
#endif // __linux__
// Exports a signal semaphore from a wrapped texture. This must be called on wrapped
// textures before they are destroyed. On failure, returns -1
// TODO(enga): Remove after updating Chromium to use ExportVulkanImage.
DAWN_NATIVE_EXPORT int ExportSignalSemaphoreOpaqueFD(WGPUDevice cDevice,
WGPUTexture cTexture);
@ -74,8 +125,15 @@ namespace dawn_native { namespace vulkan {
// primitives before the texture can be used.
// On failure, returns a nullptr.
DAWN_NATIVE_EXPORT WGPUTexture WrapVulkanImage(WGPUDevice cDevice,
const ExternalImageDescriptor* descriptor);
#endif // __linux__
const ExternalImageDescriptorVk* descriptor);
// Exports external memory from a Vulkan image. This must be called on wrapped textures
// before they are destroyed. It writes the semaphore to wait on and the old/new image
// layouts to |info|. Pass VK_IMAGE_LAYOUT_UNDEFINED as |desiredLayout| if you don't want to
// perform a layout transition.
DAWN_NATIVE_EXPORT bool ExportVulkanImage(WGPUTexture cTexture,
VkImageLayout desiredLayout,
ExternalImageExportInfoVk* info);
}} // namespace dawn_native::vulkan

View File

@ -300,7 +300,7 @@ class D3D12SharedHandleUsageTests : public D3D12ResourceTestBase {
const wgpu::Color& clearColor,
ID3D11Texture2D** d3d11TextureOut,
IDXGIKeyedMutex** dxgiKeyedMutexOut,
bool isCleared = true) const {
bool isInitialized = true) const {
ComPtr<ID3D11Texture2D> d3d11Texture;
HRESULT hr = mD3d11Device->CreateTexture2D(d3dDescriptor, nullptr, &d3d11Texture);
ASSERT_EQ(hr, S_OK);
@ -339,7 +339,7 @@ class D3D12SharedHandleUsageTests : public D3D12ResourceTestBase {
reinterpret_cast<const WGPUTextureDescriptor*>(dawnDescriptor);
externDesc.sharedHandle = sharedHandle;
externDesc.acquireMutexKey = 1;
externDesc.isCleared = isCleared;
externDesc.isInitialized = isInitialized;
WGPUTexture dawnTexture = dawn_native::d3d12::WrapSharedHandle(device.Get(), &externDesc);
*dawnTextureOut = wgpu::Texture::Acquire(dawnTexture);
@ -502,9 +502,9 @@ TEST_P(D3D12SharedHandleUsageTests, ClearTwiceInD3D12ReadbackInD3D11) {
}
// 1. Create and clear a D3D11 texture with clearColor
// 2. Import the texture with isCleared = false
// 2. Import the texture with isInitialized = false
// 3. Verify clearColor is not visible in wrapped texture
TEST_P(D3D12SharedHandleUsageTests, UnclearedTextureIsCleared) {
TEST_P(D3D12SharedHandleUsageTests, UninitializedTextureIsCleared) {
DAWN_SKIP_TEST_IF(UsesWire());
const wgpu::Color clearColor{1.0f, 0.0f, 0.0f, 1.0f};

View File

@ -97,13 +97,13 @@ namespace {
wgpu::Texture WrapIOSurface(const wgpu::TextureDescriptor* descriptor,
IOSurfaceRef ioSurface,
uint32_t plane,
bool isCleared = true) {
bool isInitialized = true) {
dawn_native::metal::ExternalImageDescriptorIOSurface externDesc;
externDesc.cTextureDescriptor =
reinterpret_cast<const WGPUTextureDescriptor*>(descriptor);
externDesc.ioSurface = ioSurface;
externDesc.plane = plane;
externDesc.isCleared = isCleared;
externDesc.isInitialized = isInitialized;
WGPUTexture texture = dawn_native::metal::WrapIOSurface(device.Get(), &externDesc);
return wgpu::Texture::Acquire(texture);
}
@ -446,8 +446,8 @@ TEST_P(IOSurfaceUsageTests, ClearRGBA8IOSurface) {
DoClearTest(ioSurface.get(), wgpu::TextureFormat::RGBA8Unorm, &data, sizeof(data));
}
// Test that texture with color is cleared when isCleared = false
TEST_P(IOSurfaceUsageTests, UnclearedTextureIsCleared) {
// Test that texture with color is cleared when isInitialized = false
TEST_P(IOSurfaceUsageTests, UninitializedTextureIsCleared) {
DAWN_SKIP_TEST_IF(UsesWire());
ScopedIOSurfaceRef ioSurface = CreateSinglePlaneIOSurface(1, 1, kCVPixelFormatType_32RGBA, 4);
@ -465,7 +465,7 @@ TEST_P(IOSurfaceUsageTests, UnclearedTextureIsCleared) {
textureDescriptor.mipLevelCount = 1;
textureDescriptor.usage = wgpu::TextureUsage::OutputAttachment | wgpu::TextureUsage::CopySrc;
// wrap ioSurface and ensure color is not visible when isCleared set to false
// wrap ioSurface and ensure color is not visible when isInitialized set to false
wgpu::Texture ioSurfaceTexture = WrapIOSurface(&textureDescriptor, ioSurface.get(), 0, false);
EXPECT_PIXEL_RGBA8_EQ(RGBA8(0, 0, 0, 0), ioSurfaceTexture, 0, 0);
}

View File

@ -104,16 +104,34 @@ namespace dawn_native { namespace vulkan {
uint32_t stride,
uint64_t drmModifier,
std::vector<int> waitFDs,
bool isCleared = true,
bool isInitialized = true,
bool expectValid = true) {
dawn_native::vulkan::ExternalImageDescriptorDmaBuf descriptor;
return WrapVulkanImage(dawnDevice, textureDescriptor, memoryFd, stride, drmModifier,
waitFDs, descriptor.releasedOldLayout,
descriptor.releasedNewLayout, isInitialized, expectValid);
}
wgpu::Texture WrapVulkanImage(wgpu::Device dawnDevice,
const wgpu::TextureDescriptor* textureDescriptor,
int memoryFd,
uint32_t stride,
uint64_t drmModifier,
std::vector<int> waitFDs,
VkImageLayout releasedOldLayout,
VkImageLayout releasedNewLayout,
bool isInitialized = true,
bool expectValid = true) {
dawn_native::vulkan::ExternalImageDescriptorDmaBuf descriptor;
descriptor.cTextureDescriptor =
reinterpret_cast<const WGPUTextureDescriptor*>(textureDescriptor);
descriptor.isCleared = isCleared;
descriptor.isInitialized = isInitialized;
descriptor.stride = stride;
descriptor.drmModifier = drmModifier;
descriptor.memoryFD = memoryFd;
descriptor.waitFDs = waitFDs;
descriptor.releasedOldLayout = releasedOldLayout;
descriptor.releasedNewLayout = releasedNewLayout;
WGPUTexture texture =
dawn_native::vulkan::WrapVulkanImage(dawnDevice.Get(), &descriptor);
@ -131,11 +149,13 @@ namespace dawn_native { namespace vulkan {
// Exports the signal from a wrapped texture and ignores it
// We have to export the signal before destroying the wrapped texture else it's an
// assertion failure
void IgnoreSignalSemaphore(wgpu::Device dawnDevice, wgpu::Texture wrappedTexture) {
int fd = dawn_native::vulkan::ExportSignalSemaphoreOpaqueFD(dawnDevice.Get(),
wrappedTexture.Get());
ASSERT_NE(fd, -1);
close(fd);
void IgnoreSignalSemaphore(wgpu::Texture wrappedTexture) {
dawn_native::vulkan::ExternalImageExportInfoDmaBuf exportInfo;
dawn_native::vulkan::ExportVulkanImage(wrappedTexture.Get(), VK_IMAGE_LAYOUT_GENERAL, &exportInfo));
for (int handle : info.semaphoreHandles) {
ASSERT_NE(handle, -1);
close(handle);
}
}
protected:
@ -157,7 +177,7 @@ namespace dawn_native { namespace vulkan {
wgpu::Texture texture = WrapVulkanImage(device, &defaultDescriptor, defaultFd,
defaultStride, defaultModifier, {}, true, true);
EXPECT_NE(texture.Get(), nullptr);
IgnoreSignalSemaphore(device, texture);
IgnoreSignalSemaphore(texture);
}
// Test an error occurs if the texture descriptor is missing
@ -230,10 +250,12 @@ namespace dawn_native { namespace vulkan {
wgpu::Texture texture = WrapVulkanImage(device, &defaultDescriptor, defaultFd,
defaultStride, defaultModifier, {}, true, true);
ASSERT_NE(texture.Get(), nullptr);
IgnoreSignalSemaphore(device, texture);
ASSERT_DEVICE_ERROR(int fd = dawn_native::vulkan::ExportSignalSemaphoreOpaqueFD(
device.Get(), texture.Get()));
ASSERT_EQ(fd, -1);
IgnoreSignalSemaphore(texture);
dawn_native::vulkan::ExternalImageExportInfoDmaBuf exportInfo;
ASSERT_DEVICE_ERROR(bool success = dawn_native::vulkan::ExportVulkanImage(
texture.Get(), VK_IMAGE_LAYOUT_GENERAL, &exportInfo));
ASSERT_FALSE(success);
}
// Test an error occurs if we try to export the signal semaphore from a normal texture
@ -242,9 +264,11 @@ namespace dawn_native { namespace vulkan {
wgpu::Texture texture = device.CreateTexture(&defaultDescriptor);
ASSERT_NE(texture.Get(), nullptr);
ASSERT_DEVICE_ERROR(int fd = dawn_native::vulkan::ExportSignalSemaphoreOpaqueFD(
device.Get(), texture.Get()));
ASSERT_EQ(fd, -1);
dawn_native::vulkan::ExternalImageExportInfoDmaBuf exportInfo;
ASSERT_DEVICE_ERROR(bool success = dawn_native::vulkan::ExportVulkanImage(
texture.Get(), VK_IMAGE_LAYOUT_GENERAL, &exportInfo));
ASSERT_FALSE(success);
}
// Test an error occurs if we try to export the signal semaphore from a destroyed texture
@ -254,9 +278,11 @@ namespace dawn_native { namespace vulkan {
wgpu::Texture texture = device.CreateTexture(&defaultDescriptor);
ASSERT_NE(texture.Get(), nullptr);
texture.Destroy();
ASSERT_DEVICE_ERROR(int fd = dawn_native::vulkan::ExportSignalSemaphoreOpaqueFD(
device.Get(), texture.Get()));
ASSERT_EQ(fd, -1);
dawn_native::vulkan::ExternalImageExportInfoDmaBuf exportInfo;
ASSERT_DEVICE_ERROR(bool success = dawn_native::vulkan::ExportVulkanImage(
texture.Get(), VK_IMAGE_LAYOUT_GENERAL, &exportInfo));
ASSERT_FALSE(success);
}
// Fixture to test using external memory textures through different usages.
@ -330,84 +356,56 @@ namespace dawn_native { namespace vulkan {
// Verify clear color is visible in |device|
TEST_P(VulkanImageWrappingUsageTests, ClearImageAcrossDevices) {
// Import the image on |secondDevice|
wgpu::Texture wrappedTexture = WrapVulkanImage(secondDevice, &defaultDescriptor, defaultFd,
defaultStride, defaultModifier, {});
wgpu::Texture wrappedTexture = WrapVulkanImage(
secondDevice, &defaultDescriptor, defaultFd, defaultStride, defaultModifier, {},
VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
// Clear |wrappedTexture| on |secondDevice|
ClearImage(secondDevice, wrappedTexture, {1 / 255.0f, 2 / 255.0f, 3 / 255.0f, 4 / 255.0f});
int signalFd = dawn_native::vulkan::ExportSignalSemaphoreOpaqueFD(secondDevice.Get(),
wrappedTexture.Get());
dawn_native::vulkan::ExternalImageExportInfoDmaBuf exportInfo;
dawn_native::vulkan::ExportVulkanImage(wrappedTexture.Get(),
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, &exportInfo);
// Import the image to |device|, making sure we wait on signalFd
int nextFd = gbm_bo_get_fd(defaultGbmBo);
wgpu::Texture nextWrappedTexture = WrapVulkanImage(
device, &defaultDescriptor, nextFd, defaultStride, defaultModifier, {signalFd});
wgpu::Texture nextWrappedTexture =
WrapVulkanImage(device, &defaultDescriptor, nextFd, defaultStride, defaultModifier,
exportInfo.semaphoreHandles, exportInfo.releasedOldLayout,
exportInfo.releasedNewLayout);
// Verify |device| sees the changes from |secondDevice|
EXPECT_PIXEL_RGBA8_EQ(RGBA8(1, 2, 3, 4), nextWrappedTexture, 0, 0);
IgnoreSignalSemaphore(device, nextWrappedTexture);
}
// Import texture to |device| and |secondDevice|
// Clear image in |secondDevice|
// Verify clear color is visible in |device|
// Verify the very first import into |device| also sees the change, since it should
// alias the same memory
TEST_P(VulkanImageWrappingUsageTests, ClearImageAcrossDevicesAliased) {
// Import the image on |device|
wgpu::Texture wrappedTextureAlias = WrapVulkanImage(device, &defaultDescriptor, defaultFd,
defaultStride, defaultModifier, {});
// Import the image on |secondDevice|
int nextFd = gbm_bo_get_fd(defaultGbmBo);
wgpu::Texture wrappedTexture = WrapVulkanImage(secondDevice, &defaultDescriptor, nextFd,
defaultStride, defaultModifier, {});
// Clear |wrappedTexture| on |secondDevice|
ClearImage(secondDevice, wrappedTexture, {1 / 255.0f, 2 / 255.0f, 3 / 255.0f, 4 / 255.0f});
int signalFd = dawn_native::vulkan::ExportSignalSemaphoreOpaqueFD(secondDevice.Get(),
wrappedTexture.Get());
// Import the image to |device|, making sure we wait on signalFd
nextFd = gbm_bo_get_fd(defaultGbmBo);
wgpu::Texture nextWrappedTexture = WrapVulkanImage(
device, &defaultDescriptor, nextFd, defaultStride, defaultModifier, {signalFd});
// Verify |device| sees the changes from |secondDevice| (waits)
EXPECT_PIXEL_RGBA8_EQ(RGBA8(1, 2, 3, 4), nextWrappedTexture, 0, 0);
// Verify aliased texture sees changes from |secondDevice| (without waiting!)
EXPECT_PIXEL_RGBA8_EQ(RGBA8(1, 2, 3, 4), wrappedTextureAlias, 0, 0);
IgnoreSignalSemaphore(device, nextWrappedTexture);
IgnoreSignalSemaphore(device, wrappedTextureAlias);
IgnoreSignalSemaphore(nextWrappedTexture);
}
// Clear an image in |secondDevice|
// Verify clear color is not visible in |device| if we import the texture as not cleared
TEST_P(VulkanImageWrappingUsageTests, UnclearedTextureIsCleared) {
TEST_P(VulkanImageWrappingUsageTests, UninitializedTextureIsCleared) {
// Import the image on |secondDevice|
wgpu::Texture wrappedTexture = WrapVulkanImage(secondDevice, &defaultDescriptor, defaultFd,
defaultStride, defaultModifier, {});
wgpu::Texture wrappedTexture = WrapVulkanImage(
secondDevice, &defaultDescriptor, defaultFd, defaultStride, defaultModifier, {},
VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
// Clear |wrappedTexture| on |secondDevice|
ClearImage(secondDevice, wrappedTexture, {1 / 255.0f, 2 / 255.0f, 3 / 255.0f, 4 / 255.0f});
int signalFd = dawn_native::vulkan::ExportSignalSemaphoreOpaqueFD(secondDevice.Get(),
wrappedTexture.Get());
dawn_native::vulkan::ExternalImageExportInfoDmaBuf exportInfo;
dawn_native::vulkan::ExportVulkanImage(wrappedTexture.Get(),
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, &exportInfo);
// Import the image to |device|, making sure we wait on signalFd
int nextFd = gbm_bo_get_fd(defaultGbmBo);
wgpu::Texture nextWrappedTexture = WrapVulkanImage(
device, &defaultDescriptor, nextFd, defaultStride, defaultModifier, {signalFd}, false);
wgpu::Texture nextWrappedTexture =
WrapVulkanImage(device, &defaultDescriptor, nextFd, defaultStride, defaultModifier,
exportInfo.semaphoreHandles, exportInfo.releasedOldLayout,
exportInfo.releasedNewLayout, false);
// Verify |device| doesn't see the changes from |secondDevice|
EXPECT_PIXEL_RGBA8_EQ(RGBA8(0, 0, 0, 0), nextWrappedTexture, 0, 0);
IgnoreSignalSemaphore(device, nextWrappedTexture);
IgnoreSignalSemaphore(nextWrappedTexture);
}
// Import a texture into |secondDevice|
@ -416,19 +414,23 @@ namespace dawn_native { namespace vulkan {
// Verify the clear color from |secondDevice| is visible in |copyDstTexture|
TEST_P(VulkanImageWrappingUsageTests, CopyTextureToTextureSrcSync) {
// Import the image on |secondDevice|
wgpu::Texture wrappedTexture = WrapVulkanImage(secondDevice, &defaultDescriptor, defaultFd,
defaultStride, defaultModifier, {});
wgpu::Texture wrappedTexture = WrapVulkanImage(
secondDevice, &defaultDescriptor, defaultFd, defaultStride, defaultModifier, {},
VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
// Clear |wrappedTexture| on |secondDevice|
ClearImage(secondDevice, wrappedTexture, {1 / 255.0f, 2 / 255.0f, 3 / 255.0f, 4 / 255.0f});
int signalFd = dawn_native::vulkan::ExportSignalSemaphoreOpaqueFD(secondDevice.Get(),
wrappedTexture.Get());
dawn_native::vulkan::ExternalImageExportInfoDmaBuf exportInfo;
dawn_native::vulkan::ExportVulkanImage(wrappedTexture.Get(),
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, &exportInfo);
// Import the image to |device|, making sure we wait on |signalFd|
int nextFd = gbm_bo_get_fd(defaultGbmBo);
wgpu::Texture deviceWrappedTexture = WrapVulkanImage(
device, &defaultDescriptor, nextFd, defaultStride, defaultModifier, {signalFd});
wgpu::Texture deviceWrappedTexture =
WrapVulkanImage(device, &defaultDescriptor, nextFd, defaultStride, defaultModifier,
exportInfo.semaphoreHandles, exportInfo.releasedOldLayout,
exportInfo.releasedNewLayout);
// Create a second texture on |device|
wgpu::Texture copyDstTexture = device.CreateTexture(&defaultDescriptor);
@ -439,7 +441,7 @@ namespace dawn_native { namespace vulkan {
// Verify |copyDstTexture| sees changes from |secondDevice|
EXPECT_PIXEL_RGBA8_EQ(RGBA8(1, 2, 3, 4), copyDstTexture, 0, 0);
IgnoreSignalSemaphore(device, deviceWrappedTexture);
IgnoreSignalSemaphore(deviceWrappedTexture);
}
// Import a texture into |device|
@ -453,19 +455,23 @@ namespace dawn_native { namespace vulkan {
// into the texture first, then |device| writes color A
TEST_P(VulkanImageWrappingUsageTests, CopyTextureToTextureDstSync) {
// Import the image on |device|
wgpu::Texture wrappedTexture = WrapVulkanImage(device, &defaultDescriptor, defaultFd,
defaultStride, defaultModifier, {});
wgpu::Texture wrappedTexture = WrapVulkanImage(
device, &defaultDescriptor, defaultFd, defaultStride, defaultModifier, {},
VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
// Clear |wrappedTexture| on |device|
ClearImage(device, wrappedTexture, {5 / 255.0f, 6 / 255.0f, 7 / 255.0f, 8 / 255.0f});
int signalFd =
dawn_native::vulkan::ExportSignalSemaphoreOpaqueFD(device.Get(), wrappedTexture.Get());
dawn_native::vulkan::ExternalImageExportInfoDmaBuf exportInfo;
dawn_native::vulkan::ExportVulkanImage(wrappedTexture.Get(),
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &exportInfo);
// Import the image to |secondDevice|, making sure we wait on |signalFd|
int nextFd = gbm_bo_get_fd(defaultGbmBo);
wgpu::Texture secondDeviceWrappedTexture = WrapVulkanImage(
secondDevice, &defaultDescriptor, nextFd, defaultStride, defaultModifier, {signalFd});
wgpu::Texture secondDeviceWrappedTexture =
WrapVulkanImage(secondDevice, &defaultDescriptor, nextFd, defaultStride,
defaultModifier, exportInfo.semaphoreHandles,
exportInfo.releasedOldLayout, exportInfo.releasedNewLayout);
// Create a texture with color B on |secondDevice|
wgpu::Texture copySrcTexture = secondDevice.CreateTexture(&defaultDescriptor);
@ -477,17 +483,21 @@ namespace dawn_native { namespace vulkan {
secondDeviceWrappedTexture);
// Re-import back into |device|, waiting on |secondDevice|'s signal
signalFd = dawn_native::vulkan::ExportSignalSemaphoreOpaqueFD(
secondDevice.Get(), secondDeviceWrappedTexture.Get());
dawn_native::vulkan::ExternalImageExportInfoDmaBuf secondExportInfo;
dawn_native::vulkan::ExportVulkanImage(secondDeviceWrappedTexture.Get(),
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
&secondExportInfo);
nextFd = gbm_bo_get_fd(defaultGbmBo);
wgpu::Texture nextWrappedTexture = WrapVulkanImage(
device, &defaultDescriptor, nextFd, defaultStride, defaultModifier, {signalFd});
wgpu::Texture nextWrappedTexture =
WrapVulkanImage(device, &defaultDescriptor, nextFd, defaultStride, defaultModifier,
secondExportInfo.semaphoreHandles, secondExportInfo.releasedOldLayout,
secondExportInfo.releasedNewLayout);
// Verify |nextWrappedTexture| contains the color from our copy
EXPECT_PIXEL_RGBA8_EQ(RGBA8(1, 2, 3, 4), nextWrappedTexture, 0, 0);
IgnoreSignalSemaphore(device, nextWrappedTexture);
IgnoreSignalSemaphore(nextWrappedTexture);
}
// Import a texture from |secondDevice|
@ -496,19 +506,23 @@ namespace dawn_native { namespace vulkan {
// Verify the clear color from |secondDevice| is visible in |copyDstBuffer|
TEST_P(VulkanImageWrappingUsageTests, CopyTextureToBufferSrcSync) {
// Import the image on |secondDevice|
wgpu::Texture wrappedTexture = WrapVulkanImage(secondDevice, &defaultDescriptor, defaultFd,
defaultStride, defaultModifier, {});
wgpu::Texture wrappedTexture = WrapVulkanImage(
secondDevice, &defaultDescriptor, defaultFd, defaultStride, defaultModifier, {},
VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
// Clear |wrappedTexture| on |secondDevice|
ClearImage(secondDevice, wrappedTexture, {1 / 255.0f, 2 / 255.0f, 3 / 255.0f, 4 / 255.0f});
int signalFd = dawn_native::vulkan::ExportSignalSemaphoreOpaqueFD(secondDevice.Get(),
wrappedTexture.Get());
dawn_native::vulkan::ExternalImageExportInfoDmaBuf exportInfo;
dawn_native::vulkan::ExportVulkanImage(wrappedTexture.Get(),
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, &exportInfo);
// Import the image to |device|, making sure we wait on |signalFd|
int nextFd = gbm_bo_get_fd(defaultGbmBo);
wgpu::Texture deviceWrappedTexture = WrapVulkanImage(
device, &defaultDescriptor, nextFd, defaultStride, defaultModifier, {signalFd});
wgpu::Texture deviceWrappedTexture =
WrapVulkanImage(device, &defaultDescriptor, nextFd, defaultStride, defaultModifier,
exportInfo.semaphoreHandles, exportInfo.releasedOldLayout,
exportInfo.releasedNewLayout);
// Create a destination buffer on |device|
wgpu::BufferDescriptor bufferDesc;
@ -532,7 +546,7 @@ namespace dawn_native { namespace vulkan {
uint32_t expected = 1;
EXPECT_BUFFER_U32_EQ(expected, copyDstBuffer, 0);
IgnoreSignalSemaphore(device, deviceWrappedTexture);
IgnoreSignalSemaphore(deviceWrappedTexture);
}
// Import a texture into |device|
@ -545,19 +559,23 @@ namespace dawn_native { namespace vulkan {
// into the texture first, then |device| writes color A
TEST_P(VulkanImageWrappingUsageTests, CopyBufferToTextureDstSync) {
// Import the image on |device|
wgpu::Texture wrappedTexture = WrapVulkanImage(device, &defaultDescriptor, defaultFd,
defaultStride, defaultModifier, {});
wgpu::Texture wrappedTexture = WrapVulkanImage(
device, &defaultDescriptor, defaultFd, defaultStride, defaultModifier, {},
VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
// Clear |wrappedTexture| on |device|
ClearImage(device, wrappedTexture, {5 / 255.0f, 6 / 255.0f, 7 / 255.0f, 8 / 255.0f});
int signalFd =
dawn_native::vulkan::ExportSignalSemaphoreOpaqueFD(device.Get(), wrappedTexture.Get());
dawn_native::vulkan::ExternalImageExportInfoDmaBuf exportInfo;
dawn_native::vulkan::ExportVulkanImage(wrappedTexture.Get(),
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, &exportInfo);
// Import the image to |secondDevice|, making sure we wait on |signalFd|
int nextFd = gbm_bo_get_fd(defaultGbmBo);
wgpu::Texture secondDeviceWrappedTexture = WrapVulkanImage(
secondDevice, &defaultDescriptor, nextFd, defaultStride, defaultModifier, {signalFd});
wgpu::Texture secondDeviceWrappedTexture =
WrapVulkanImage(secondDevice, &defaultDescriptor, nextFd, defaultStride,
defaultModifier, exportInfo.semaphoreHandles,
exportInfo.releasedOldLayout, exportInfo.releasedNewLayout);
// Copy color B on |secondDevice|
wgpu::Queue secondDeviceQueue = secondDevice.GetDefaultQueue();
@ -579,17 +597,21 @@ namespace dawn_native { namespace vulkan {
secondDeviceQueue.Submit(1, &commands);
// Re-import back into |device|, waiting on |secondDevice|'s signal
signalFd = dawn_native::vulkan::ExportSignalSemaphoreOpaqueFD(
secondDevice.Get(), secondDeviceWrappedTexture.Get());
dawn_native::vulkan::ExternalImageExportInfoDmaBuf secondExportInfo;
dawn_native::vulkan::ExportVulkanImage(secondDeviceWrappedTexture.Get(),
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
&secondExportInfo);
nextFd = gbm_bo_get_fd(defaultGbmBo);
wgpu::Texture nextWrappedTexture = WrapVulkanImage(
device, &defaultDescriptor, nextFd, defaultStride, defaultModifier, {signalFd});
wgpu::Texture nextWrappedTexture =
WrapVulkanImage(device, &defaultDescriptor, nextFd, defaultStride, defaultModifier,
secondExportInfo.semaphoreHandles, secondExportInfo.releasedOldLayout,
secondExportInfo.releasedNewLayout);
// Verify |nextWrappedTexture| contains the color from our copy
EXPECT_PIXEL_RGBA8_EQ(RGBA8(1, 2, 3, 4), nextWrappedTexture, 0, 0);
IgnoreSignalSemaphore(device, nextWrappedTexture);
IgnoreSignalSemaphore(nextWrappedTexture);
}
// Import a texture from |secondDevice|
@ -599,19 +621,23 @@ namespace dawn_native { namespace vulkan {
// Verify the clear color from |secondDevice| is visible in both copies
TEST_P(VulkanImageWrappingUsageTests, DoubleTextureUsage) {
// Import the image on |secondDevice|
wgpu::Texture wrappedTexture = WrapVulkanImage(secondDevice, &defaultDescriptor, defaultFd,
defaultStride, defaultModifier, {});
wgpu::Texture wrappedTexture = WrapVulkanImage(
secondDevice, &defaultDescriptor, defaultFd, defaultStride, defaultModifier, {},
VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
// Clear |wrappedTexture| on |secondDevice|
ClearImage(secondDevice, wrappedTexture, {1 / 255.0f, 2 / 255.0f, 3 / 255.0f, 4 / 255.0f});
int signalFd = dawn_native::vulkan::ExportSignalSemaphoreOpaqueFD(secondDevice.Get(),
wrappedTexture.Get());
dawn_native::vulkan::ExternalImageExportInfoDmaBuf exportInfo;
dawn_native::vulkan::ExportVulkanImage(wrappedTexture.Get(),
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, &exportInfo);
// Import the image to |device|, making sure we wait on |signalFd|
int nextFd = gbm_bo_get_fd(defaultGbmBo);
wgpu::Texture deviceWrappedTexture = WrapVulkanImage(
device, &defaultDescriptor, nextFd, defaultStride, defaultModifier, {signalFd});
wgpu::Texture deviceWrappedTexture =
WrapVulkanImage(device, &defaultDescriptor, nextFd, defaultStride, defaultModifier,
exportInfo.semaphoreHandles, exportInfo.releasedOldLayout,
exportInfo.releasedNewLayout);
// Create a second texture on |device|
wgpu::Texture copyDstTexture = device.CreateTexture(&defaultDescriptor);
@ -631,7 +657,7 @@ namespace dawn_native { namespace vulkan {
// Verify |secondCopyDstTexture| sees changes from |secondDevice|
EXPECT_PIXEL_RGBA8_EQ(RGBA8(1, 2, 3, 4), secondCopyDstTexture, 0, 0);
IgnoreSignalSemaphore(device, deviceWrappedTexture);
IgnoreSignalSemaphore(deviceWrappedTexture);
}
// Tex A on device 3 (external export)
@ -676,10 +702,12 @@ namespace dawn_native { namespace vulkan {
// Import TexA, TexB on device 3
wgpu::Texture wrappedTexADevice3 =
WrapVulkanImage(thirdDevice, &defaultDescriptor, fdA, strideA, modifierA, {});
WrapVulkanImage(thirdDevice, &defaultDescriptor, fdA, strideA, modifierA, {},
VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
wgpu::Texture wrappedTexBDevice3 =
WrapVulkanImage(thirdDevice, &defaultDescriptor, fdB, strideB, modifierB, {});
WrapVulkanImage(thirdDevice, &defaultDescriptor, fdB, strideB, modifierB, {},
VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
// Clear TexA
ClearImage(thirdDevice, wrappedTexADevice3,
@ -689,30 +717,37 @@ namespace dawn_native { namespace vulkan {
SimpleCopyTextureToTexture(thirdDevice, thirdDeviceQueue, wrappedTexADevice3,
wrappedTexBDevice3);
int signalFdTexBDevice3 = dawn_native::vulkan::ExportSignalSemaphoreOpaqueFD(
thirdDevice.Get(), wrappedTexBDevice3.Get());
IgnoreSignalSemaphore(thirdDevice, wrappedTexADevice3);
dawn_native::vulkan::ExternalImageExportInfoDmaBuf exportInfoTexBDevice3;
dawn_native::vulkan::ExportVulkanImage(
wrappedTexBDevice3.Get(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, &exportInfoTexBDevice3);
IgnoreSignalSemaphore(wrappedTexADevice3);
// Import TexB, TexC on device 2
fdB = gbm_bo_get_fd(gbmBoB);
wgpu::Texture wrappedTexBDevice2 = WrapVulkanImage(
secondDevice, &defaultDescriptor, fdB, strideB, modifierB, {signalFdTexBDevice3});
secondDevice, &defaultDescriptor, fdB, strideB, modifierB,
exportInfoTexBDevice3.semaphoreHandles, exportInfoTexBDevice3.releasedOldLayout,
exportInfoTexBDevice3.releasedNewLayout);
wgpu::Texture wrappedTexCDevice2 =
WrapVulkanImage(secondDevice, &defaultDescriptor, fdC, strideC, modifierC, {});
WrapVulkanImage(secondDevice, &defaultDescriptor, fdC, strideC, modifierC, {},
VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
// Copy B->C on device 2
SimpleCopyTextureToTexture(secondDevice, secondDeviceQueue, wrappedTexBDevice2,
wrappedTexCDevice2);
int signalFdTexCDevice2 = dawn_native::vulkan::ExportSignalSemaphoreOpaqueFD(
secondDevice.Get(), wrappedTexCDevice2.Get());
IgnoreSignalSemaphore(secondDevice, wrappedTexBDevice2);
dawn_native::vulkan::ExternalImageExportInfoDmaBuf exportInfoTexCDevice2;
dawn_native::vulkan::ExportVulkanImage(
wrappedTexCDevice2.Get(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, &exportInfoTexCDevice2);
IgnoreSignalSemaphore(wrappedTexBDevice2);
// Import TexC on device 1
fdC = gbm_bo_get_fd(gbmBoC);
wgpu::Texture wrappedTexCDevice1 = WrapVulkanImage(device, &defaultDescriptor, fdC, strideC,
modifierC, {signalFdTexCDevice2});
wgpu::Texture wrappedTexCDevice1 = WrapVulkanImage(
device, &defaultDescriptor, fdC, strideC, modifierC,
exportInfoTexCDevice2.semaphoreHandles, exportInfoTexCDevice2.releasedOldLayout,
exportInfoTexCDevice2.releasedNewLayout);
// Create TexD on device 1
wgpu::Texture texD = device.CreateTexture(&defaultDescriptor);
@ -723,7 +758,7 @@ namespace dawn_native { namespace vulkan {
// Verify D matches clear color
EXPECT_PIXEL_RGBA8_EQ(RGBA8(1, 2, 3, 4), texD, 0, 0);
IgnoreSignalSemaphore(device, wrappedTexCDevice1);
IgnoreSignalSemaphore(wrappedTexCDevice1);
}
// Tests a larger image is preserved when importing
@ -756,7 +791,8 @@ namespace dawn_native { namespace vulkan {
// Import the image on |secondDevice|
wgpu::Texture wrappedTexture =
WrapVulkanImage(secondDevice, &descriptor, fd, stride, modifier, {});
WrapVulkanImage(secondDevice, &descriptor, fd, stride, modifier, {},
VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
// Draw a non-trivial picture
uint32_t width = 640, height = 480, pixelSize = 4;
@ -791,14 +827,15 @@ namespace dawn_native { namespace vulkan {
wgpu::CommandBuffer commands = encoder.Finish();
secondDeviceQueue.Submit(1, &commands);
}
int signalFd = dawn_native::vulkan::ExportSignalSemaphoreOpaqueFD(secondDevice.Get(),
wrappedTexture.Get());
dawn_native::vulkan::ExternalImageExportInfoDmaBuf exportInfo;
dawn_native::vulkan::ExportVulkanImage(wrappedTexture.Get(),
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, &exportInfo);
int nextFd = gbm_bo_get_fd(gbmBo);
// Import the image on |device|
wgpu::Texture nextWrappedTexture =
WrapVulkanImage(device, &descriptor, nextFd, stride, modifier, {signalFd});
wgpu::Texture nextWrappedTexture = WrapVulkanImage(
device, &descriptor, nextFd, stride, modifier, exportInfo.semaphoreHandles,
exportInfo.releasedOldLayout, exportInfo.releasedNewLayout);
// Copy the image into a buffer for comparison
wgpu::BufferDescriptor copyDesc;
@ -823,7 +860,7 @@ namespace dawn_native { namespace vulkan {
EXPECT_BUFFER_U32_RANGE_EQ(reinterpret_cast<uint32_t*>(data.data()), copyDstBuffer, 0,
data.size() / 4);
IgnoreSignalSemaphore(device, nextWrappedTexture);
IgnoreSignalSemaphore(nextWrappedTexture);
}
DAWN_INSTANTIATE_TEST(VulkanImageWrappingValidationTests, VulkanBackend());

View File

@ -157,16 +157,34 @@ namespace dawn_native { namespace vulkan {
VkDeviceSize allocationSize,
uint32_t memoryTypeIndex,
std::vector<int> waitFDs,
bool isCleared = true,
bool isInitialized = true,
bool expectValid = true) {
dawn_native::vulkan::ExternalImageDescriptorOpaqueFD descriptor;
return WrapVulkanImage(dawnDevice, textureDescriptor, memoryFd, allocationSize,
memoryTypeIndex, waitFDs, descriptor.releasedOldLayout,
descriptor.releasedNewLayout, isInitialized, expectValid);
}
wgpu::Texture WrapVulkanImage(wgpu::Device dawnDevice,
const wgpu::TextureDescriptor* textureDescriptor,
int memoryFd,
VkDeviceSize allocationSize,
uint32_t memoryTypeIndex,
std::vector<int> waitFDs,
VkImageLayout releasedOldLayout,
VkImageLayout releasedNewLayout,
bool isInitialized = true,
bool expectValid = true) {
dawn_native::vulkan::ExternalImageDescriptorOpaqueFD descriptor;
descriptor.cTextureDescriptor =
reinterpret_cast<const WGPUTextureDescriptor*>(textureDescriptor);
descriptor.isCleared = isCleared;
descriptor.isInitialized = isInitialized;
descriptor.allocationSize = allocationSize;
descriptor.memoryTypeIndex = memoryTypeIndex;
descriptor.memoryFD = memoryFd;
descriptor.waitFDs = waitFDs;
descriptor.releasedOldLayout = releasedOldLayout;
descriptor.releasedNewLayout = releasedNewLayout;
WGPUTexture texture =
dawn_native::vulkan::WrapVulkanImage(dawnDevice.Get(), &descriptor);
@ -184,11 +202,14 @@ namespace dawn_native { namespace vulkan {
// Exports the signal from a wrapped texture and ignores it
// We have to export the signal before destroying the wrapped texture else it's an
// assertion failure
void IgnoreSignalSemaphore(wgpu::Device dawnDevice, wgpu::Texture wrappedTexture) {
int fd = dawn_native::vulkan::ExportSignalSemaphoreOpaqueFD(dawnDevice.Get(),
wrappedTexture.Get());
ASSERT_NE(fd, -1);
close(fd);
void IgnoreSignalSemaphore(wgpu::Texture wrappedTexture) {
dawn_native::vulkan::ExternalImageExportInfoOpaqueFD info;
dawn_native::vulkan::ExportVulkanImage(wrappedTexture.Get(),
VK_IMAGE_LAYOUT_GENERAL, &info);
for (int handle : info.semaphoreHandles) {
ASSERT_NE(handle, -1);
close(handle);
}
}
protected:
@ -244,7 +265,7 @@ namespace dawn_native { namespace vulkan {
WrapVulkanImage(device, &defaultDescriptor, defaultFd, defaultAllocationSize,
defaultMemoryTypeIndex, {}, true, true);
EXPECT_NE(texture.Get(), nullptr);
IgnoreSignalSemaphore(device, texture);
IgnoreSignalSemaphore(texture);
}
// Test an error occurs if the texture descriptor is missing
@ -319,10 +340,12 @@ namespace dawn_native { namespace vulkan {
WrapVulkanImage(device, &defaultDescriptor, defaultFd, defaultAllocationSize,
defaultMemoryTypeIndex, {}, true, true);
ASSERT_NE(texture.Get(), nullptr);
IgnoreSignalSemaphore(device, texture);
ASSERT_DEVICE_ERROR(int fd = dawn_native::vulkan::ExportSignalSemaphoreOpaqueFD(
device.Get(), texture.Get()));
ASSERT_EQ(fd, -1);
IgnoreSignalSemaphore(texture);
dawn_native::vulkan::ExternalImageExportInfoOpaqueFD exportInfo;
ASSERT_DEVICE_ERROR(bool success = dawn_native::vulkan::ExportVulkanImage(
texture.Get(), VK_IMAGE_LAYOUT_GENERAL, &exportInfo));
ASSERT_FALSE(success);
}
// Test an error occurs if we try to export the signal semaphore from a normal texture
@ -330,9 +353,11 @@ namespace dawn_native { namespace vulkan {
DAWN_SKIP_TEST_IF(UsesWire());
wgpu::Texture texture = device.CreateTexture(&defaultDescriptor);
ASSERT_NE(texture.Get(), nullptr);
ASSERT_DEVICE_ERROR(int fd = dawn_native::vulkan::ExportSignalSemaphoreOpaqueFD(
device.Get(), texture.Get()));
ASSERT_EQ(fd, -1);
dawn_native::vulkan::ExternalImageExportInfoOpaqueFD exportInfo;
ASSERT_DEVICE_ERROR(bool success = dawn_native::vulkan::ExportVulkanImage(
texture.Get(), VK_IMAGE_LAYOUT_GENERAL, &exportInfo));
ASSERT_FALSE(success);
}
// Test an error occurs if we try to export the signal semaphore from a destroyed texture
@ -341,9 +366,11 @@ namespace dawn_native { namespace vulkan {
wgpu::Texture texture = device.CreateTexture(&defaultDescriptor);
ASSERT_NE(texture.Get(), nullptr);
texture.Destroy();
ASSERT_DEVICE_ERROR(int fd = dawn_native::vulkan::ExportSignalSemaphoreOpaqueFD(
device.Get(), texture.Get()));
ASSERT_EQ(fd, -1);
dawn_native::vulkan::ExternalImageExportInfoOpaqueFD exportInfo;
ASSERT_DEVICE_ERROR(bool success = dawn_native::vulkan::ExportVulkanImage(
texture.Get(), VK_IMAGE_LAYOUT_GENERAL, &exportInfo));
ASSERT_FALSE(success);
}
// Fixture to test using external memory textures through different usages.
@ -456,97 +483,58 @@ namespace dawn_native { namespace vulkan {
// Import the image on |secondDevice|
wgpu::Texture wrappedTexture =
WrapVulkanImage(secondDevice, &defaultDescriptor, defaultFd, defaultAllocationSize,
defaultMemoryTypeIndex, {});
defaultMemoryTypeIndex, {}, VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
// Clear |wrappedTexture| on |secondDevice|
ClearImage(secondDevice, wrappedTexture, {1 / 255.0f, 2 / 255.0f, 3 / 255.0f, 4 / 255.0f});
int signalFd = dawn_native::vulkan::ExportSignalSemaphoreOpaqueFD(secondDevice.Get(),
wrappedTexture.Get());
dawn_native::vulkan::ExternalImageExportInfoOpaqueFD exportInfo;
dawn_native::vulkan::ExportVulkanImage(wrappedTexture.Get(),
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, &exportInfo);
// Import the image to |device|, making sure we wait on signalFd
int memoryFd = GetMemoryFd(deviceVk, defaultAllocation);
wgpu::Texture nextWrappedTexture =
WrapVulkanImage(device, &defaultDescriptor, memoryFd, defaultAllocationSize,
defaultMemoryTypeIndex, {signalFd});
defaultMemoryTypeIndex, exportInfo.semaphoreHandles,
exportInfo.releasedOldLayout, exportInfo.releasedNewLayout);
// Verify |device| sees the changes from |secondDevice|
EXPECT_PIXEL_RGBA8_EQ(RGBA8(1, 2, 3, 4), nextWrappedTexture, 0, 0);
IgnoreSignalSemaphore(device, nextWrappedTexture);
}
// Import texture to |device| and |secondDevice|
// Clear image in |secondDevice|
// Verify clear color is visible in |device|
// Verify the very first import into |device| also sees the change, since it should
// alias the same memory
TEST_P(VulkanImageWrappingUsageTests, ClearImageAcrossDevicesAliased) {
DAWN_SKIP_TEST_IF(UsesWire());
// WrapVulkanImage consumes the file descriptor so we can't import defaultFd twice.
// Duplicate the file descriptor so we can import it twice.
int defaultFdCopy = dup(defaultFd);
ASSERT(defaultFdCopy != -1);
// Import the image on |device
wgpu::Texture wrappedTextureAlias =
WrapVulkanImage(device, &defaultDescriptor, defaultFdCopy, defaultAllocationSize,
defaultMemoryTypeIndex, {});
// Import the image on |secondDevice|
wgpu::Texture wrappedTexture =
WrapVulkanImage(secondDevice, &defaultDescriptor, defaultFd, defaultAllocationSize,
defaultMemoryTypeIndex, {});
// Clear |wrappedTexture| on |secondDevice|
ClearImage(secondDevice, wrappedTexture, {1 / 255.0f, 2 / 255.0f, 3 / 255.0f, 4 / 255.0f});
int signalFd = dawn_native::vulkan::ExportSignalSemaphoreOpaqueFD(secondDevice.Get(),
wrappedTexture.Get());
// Import the image to |device|, making sure we wait on signalFd
int memoryFd = GetMemoryFd(deviceVk, defaultAllocation);
wgpu::Texture nextWrappedTexture =
WrapVulkanImage(device, &defaultDescriptor, memoryFd, defaultAllocationSize,
defaultMemoryTypeIndex, {signalFd});
// Verify |device| sees the changes from |secondDevice| (waits)
EXPECT_PIXEL_RGBA8_EQ(RGBA8(1, 2, 3, 4), nextWrappedTexture, 0, 0);
// Verify aliased texture sees changes from |secondDevice| (without waiting!)
EXPECT_PIXEL_RGBA8_EQ(RGBA8(1, 2, 3, 4), wrappedTextureAlias, 0, 0);
IgnoreSignalSemaphore(device, nextWrappedTexture);
IgnoreSignalSemaphore(device, wrappedTextureAlias);
IgnoreSignalSemaphore(nextWrappedTexture);
}
// Clear an image in |secondDevice|
// Verify clear color is not visible in |device| if we import the texture as not cleared
TEST_P(VulkanImageWrappingUsageTests, UnclearedTextureIsCleared) {
TEST_P(VulkanImageWrappingUsageTests, UninitializedTextureIsCleared) {
DAWN_SKIP_TEST_IF(UsesWire());
// Import the image on |secondDevice|
wgpu::Texture wrappedTexture =
WrapVulkanImage(secondDevice, &defaultDescriptor, defaultFd, defaultAllocationSize,
defaultMemoryTypeIndex, {});
defaultMemoryTypeIndex, {}, VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
// Clear |wrappedTexture| on |secondDevice|
ClearImage(secondDevice, wrappedTexture, {1 / 255.0f, 2 / 255.0f, 3 / 255.0f, 4 / 255.0f});
int signalFd = dawn_native::vulkan::ExportSignalSemaphoreOpaqueFD(secondDevice.Get(),
wrappedTexture.Get());
dawn_native::vulkan::ExternalImageExportInfoOpaqueFD exportInfo;
dawn_native::vulkan::ExportVulkanImage(wrappedTexture.Get(),
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, &exportInfo);
// Import the image to |device|, making sure we wait on signalFd
// Import the image to |device|, making sure we wait on the semaphore
int memoryFd = GetMemoryFd(deviceVk, defaultAllocation);
wgpu::Texture nextWrappedTexture =
WrapVulkanImage(device, &defaultDescriptor, memoryFd, defaultAllocationSize,
defaultMemoryTypeIndex, {signalFd}, false);
defaultMemoryTypeIndex, exportInfo.semaphoreHandles,
exportInfo.releasedOldLayout, exportInfo.releasedNewLayout, false);
// Verify |device| doesn't see the changes from |secondDevice|
EXPECT_PIXEL_RGBA8_EQ(RGBA8(0, 0, 0, 0), nextWrappedTexture, 0, 0);
IgnoreSignalSemaphore(device, nextWrappedTexture);
IgnoreSignalSemaphore(nextWrappedTexture);
}
// Import a texture into |secondDevice|
@ -558,19 +546,22 @@ namespace dawn_native { namespace vulkan {
// Import the image on |secondDevice|
wgpu::Texture wrappedTexture =
WrapVulkanImage(secondDevice, &defaultDescriptor, defaultFd, defaultAllocationSize,
defaultMemoryTypeIndex, {});
defaultMemoryTypeIndex, {}, VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
// Clear |wrappedTexture| on |secondDevice|
ClearImage(secondDevice, wrappedTexture, {1 / 255.0f, 2 / 255.0f, 3 / 255.0f, 4 / 255.0f});
int signalFd = dawn_native::vulkan::ExportSignalSemaphoreOpaqueFD(secondDevice.Get(),
wrappedTexture.Get());
dawn_native::vulkan::ExternalImageExportInfoOpaqueFD exportInfo;
dawn_native::vulkan::ExportVulkanImage(wrappedTexture.Get(),
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, &exportInfo);
// Import the image to |device|, making sure we wait on |signalFd|
// Import the image to |device|, making sure we wait on the semaphore
int memoryFd = GetMemoryFd(deviceVk, defaultAllocation);
wgpu::Texture deviceWrappedTexture =
WrapVulkanImage(device, &defaultDescriptor, memoryFd, defaultAllocationSize,
defaultMemoryTypeIndex, {signalFd});
defaultMemoryTypeIndex, exportInfo.semaphoreHandles,
exportInfo.releasedOldLayout, exportInfo.releasedNewLayout);
// Create a second texture on |device|
wgpu::Texture copyDstTexture = device.CreateTexture(&defaultDescriptor);
@ -581,7 +572,7 @@ namespace dawn_native { namespace vulkan {
// Verify |copyDstTexture| sees changes from |secondDevice|
EXPECT_PIXEL_RGBA8_EQ(RGBA8(1, 2, 3, 4), copyDstTexture, 0, 0);
IgnoreSignalSemaphore(device, deviceWrappedTexture);
IgnoreSignalSemaphore(deviceWrappedTexture);
}
// Import a texture into |device|
@ -596,21 +587,23 @@ namespace dawn_native { namespace vulkan {
DAWN_SKIP_TEST_IF(UsesWire());
// Import the image on |device|
wgpu::Texture wrappedTexture =
WrapVulkanImage(device, &defaultDescriptor, defaultFd, defaultAllocationSize,
defaultMemoryTypeIndex, {});
wgpu::Texture wrappedTexture = WrapVulkanImage(
device, &defaultDescriptor, defaultFd, defaultAllocationSize, defaultMemoryTypeIndex,
{}, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
// Clear |wrappedTexture| on |device|
ClearImage(device, wrappedTexture, {5 / 255.0f, 6 / 255.0f, 7 / 255.0f, 8 / 255.0f});
int signalFd =
dawn_native::vulkan::ExportSignalSemaphoreOpaqueFD(device.Get(), wrappedTexture.Get());
dawn_native::vulkan::ExternalImageExportInfoOpaqueFD exportInfo;
dawn_native::vulkan::ExportVulkanImage(wrappedTexture.Get(),
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &exportInfo);
// Import the image to |secondDevice|, making sure we wait on |signalFd|
// Import the image to |secondDevice|, making sure we wait on the semaphore
int memoryFd = GetMemoryFd(deviceVk, defaultAllocation);
wgpu::Texture secondDeviceWrappedTexture =
WrapVulkanImage(secondDevice, &defaultDescriptor, memoryFd, defaultAllocationSize,
defaultMemoryTypeIndex, {signalFd});
defaultMemoryTypeIndex, exportInfo.semaphoreHandles,
exportInfo.releasedOldLayout, exportInfo.releasedNewLayout);
// Create a texture with color B on |secondDevice|
wgpu::Texture copySrcTexture = secondDevice.CreateTexture(&defaultDescriptor);
@ -622,18 +615,21 @@ namespace dawn_native { namespace vulkan {
secondDeviceWrappedTexture);
// Re-import back into |device|, waiting on |secondDevice|'s signal
signalFd = dawn_native::vulkan::ExportSignalSemaphoreOpaqueFD(
secondDevice.Get(), secondDeviceWrappedTexture.Get());
dawn_native::vulkan::ExternalImageExportInfoOpaqueFD secondExportInfo;
dawn_native::vulkan::ExportVulkanImage(secondDeviceWrappedTexture.Get(),
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
&secondExportInfo);
memoryFd = GetMemoryFd(deviceVk, defaultAllocation);
wgpu::Texture nextWrappedTexture =
WrapVulkanImage(device, &defaultDescriptor, memoryFd, defaultAllocationSize,
defaultMemoryTypeIndex, {signalFd});
defaultMemoryTypeIndex, secondExportInfo.semaphoreHandles,
secondExportInfo.releasedOldLayout, secondExportInfo.releasedNewLayout);
// Verify |nextWrappedTexture| contains the color from our copy
EXPECT_PIXEL_RGBA8_EQ(RGBA8(1, 2, 3, 4), nextWrappedTexture, 0, 0);
IgnoreSignalSemaphore(device, nextWrappedTexture);
IgnoreSignalSemaphore(nextWrappedTexture);
}
// Import a texture from |secondDevice|
@ -645,19 +641,22 @@ namespace dawn_native { namespace vulkan {
// Import the image on |secondDevice|
wgpu::Texture wrappedTexture =
WrapVulkanImage(secondDevice, &defaultDescriptor, defaultFd, defaultAllocationSize,
defaultMemoryTypeIndex, {});
defaultMemoryTypeIndex, {}, VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
// Clear |wrappedTexture| on |secondDevice|
ClearImage(secondDevice, wrappedTexture, {1 / 255.0f, 2 / 255.0f, 3 / 255.0f, 4 / 255.0f});
int signalFd = dawn_native::vulkan::ExportSignalSemaphoreOpaqueFD(secondDevice.Get(),
wrappedTexture.Get());
dawn_native::vulkan::ExternalImageExportInfoOpaqueFD exportInfo;
dawn_native::vulkan::ExportVulkanImage(wrappedTexture.Get(),
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, &exportInfo);
// Import the image to |device|, making sure we wait on |signalFd|
// Import the image to |device|, making sure we wait on the semaphore
int memoryFd = GetMemoryFd(deviceVk, defaultAllocation);
wgpu::Texture deviceWrappedTexture =
WrapVulkanImage(device, &defaultDescriptor, memoryFd, defaultAllocationSize,
defaultMemoryTypeIndex, {signalFd});
defaultMemoryTypeIndex, exportInfo.semaphoreHandles,
exportInfo.releasedOldLayout, exportInfo.releasedNewLayout);
// Create a destination buffer on |device|
wgpu::BufferDescriptor bufferDesc;
@ -681,7 +680,7 @@ namespace dawn_native { namespace vulkan {
uint32_t expected = 0x04030201;
EXPECT_BUFFER_U32_EQ(expected, copyDstBuffer, 0);
IgnoreSignalSemaphore(device, deviceWrappedTexture);
IgnoreSignalSemaphore(deviceWrappedTexture);
}
// Import a texture into |device|
@ -696,21 +695,23 @@ namespace dawn_native { namespace vulkan {
DAWN_SKIP_TEST_IF(UsesWire());
// Import the image on |device|
wgpu::Texture wrappedTexture =
WrapVulkanImage(device, &defaultDescriptor, defaultFd, defaultAllocationSize,
defaultMemoryTypeIndex, {});
wgpu::Texture wrappedTexture = WrapVulkanImage(
device, &defaultDescriptor, defaultFd, defaultAllocationSize, defaultMemoryTypeIndex,
{}, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
// Clear |wrappedTexture| on |device|
ClearImage(device, wrappedTexture, {5 / 255.0f, 6 / 255.0f, 7 / 255.0f, 8 / 255.0f});
int signalFd =
dawn_native::vulkan::ExportSignalSemaphoreOpaqueFD(device.Get(), wrappedTexture.Get());
dawn_native::vulkan::ExternalImageExportInfoOpaqueFD exportInfo;
dawn_native::vulkan::ExportVulkanImage(wrappedTexture.Get(),
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, &exportInfo);
// Import the image to |secondDevice|, making sure we wait on |signalFd|
int memoryFd = GetMemoryFd(deviceVk, defaultAllocation);
wgpu::Texture secondDeviceWrappedTexture =
WrapVulkanImage(secondDevice, &defaultDescriptor, memoryFd, defaultAllocationSize,
defaultMemoryTypeIndex, {signalFd});
defaultMemoryTypeIndex, exportInfo.semaphoreHandles,
exportInfo.releasedOldLayout, exportInfo.releasedNewLayout);
// Copy color B on |secondDevice|
wgpu::Queue secondDeviceQueue = secondDevice.GetDefaultQueue();
@ -732,18 +733,21 @@ namespace dawn_native { namespace vulkan {
secondDeviceQueue.Submit(1, &commands);
// Re-import back into |device|, waiting on |secondDevice|'s signal
signalFd = dawn_native::vulkan::ExportSignalSemaphoreOpaqueFD(
secondDevice.Get(), secondDeviceWrappedTexture.Get());
dawn_native::vulkan::ExternalImageExportInfoOpaqueFD secondExportInfo;
dawn_native::vulkan::ExportVulkanImage(secondDeviceWrappedTexture.Get(),
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
&secondExportInfo);
memoryFd = GetMemoryFd(deviceVk, defaultAllocation);
wgpu::Texture nextWrappedTexture =
WrapVulkanImage(device, &defaultDescriptor, memoryFd, defaultAllocationSize,
defaultMemoryTypeIndex, {signalFd});
defaultMemoryTypeIndex, secondExportInfo.semaphoreHandles,
secondExportInfo.releasedOldLayout, secondExportInfo.releasedNewLayout);
// Verify |nextWrappedTexture| contains the color from our copy
EXPECT_PIXEL_RGBA8_EQ(RGBA8(1, 2, 3, 4), nextWrappedTexture, 0, 0);
IgnoreSignalSemaphore(device, nextWrappedTexture);
IgnoreSignalSemaphore(nextWrappedTexture);
}
// Import a texture from |secondDevice|
@ -756,19 +760,22 @@ namespace dawn_native { namespace vulkan {
// Import the image on |secondDevice|
wgpu::Texture wrappedTexture =
WrapVulkanImage(secondDevice, &defaultDescriptor, defaultFd, defaultAllocationSize,
defaultMemoryTypeIndex, {});
defaultMemoryTypeIndex, {}, VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
// Clear |wrappedTexture| on |secondDevice|
ClearImage(secondDevice, wrappedTexture, {1 / 255.0f, 2 / 255.0f, 3 / 255.0f, 4 / 255.0f});
int signalFd = dawn_native::vulkan::ExportSignalSemaphoreOpaqueFD(secondDevice.Get(),
wrappedTexture.Get());
dawn_native::vulkan::ExternalImageExportInfoOpaqueFD exportInfo;
dawn_native::vulkan::ExportVulkanImage(wrappedTexture.Get(),
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, &exportInfo);
// Import the image to |device|, making sure we wait on |signalFd|
// Import the image to |device|, making sure we wait on the semaphore
int memoryFd = GetMemoryFd(deviceVk, defaultAllocation);
wgpu::Texture deviceWrappedTexture =
WrapVulkanImage(device, &defaultDescriptor, memoryFd, defaultAllocationSize,
defaultMemoryTypeIndex, {signalFd});
defaultMemoryTypeIndex, exportInfo.semaphoreHandles,
exportInfo.releasedOldLayout, exportInfo.releasedNewLayout);
// Create a second texture on |device|
wgpu::Texture copyDstTexture = device.CreateTexture(&defaultDescriptor);
@ -788,7 +795,7 @@ namespace dawn_native { namespace vulkan {
// Verify |secondCopyDstTexture| sees changes from |secondDevice|
EXPECT_PIXEL_RGBA8_EQ(RGBA8(1, 2, 3, 4), secondCopyDstTexture, 0, 0);
IgnoreSignalSemaphore(device, deviceWrappedTexture);
IgnoreSignalSemaphore(deviceWrappedTexture);
}
// Tex A on device 3 (external export)
@ -844,10 +851,12 @@ namespace dawn_native { namespace vulkan {
// Import TexA, TexB on device 3
wgpu::Texture wrappedTexADevice3 = WrapVulkanImage(
thirdDevice, &defaultDescriptor, memoryFdA, allocationSizeA, memoryTypeIndexA, {});
thirdDevice, &defaultDescriptor, memoryFdA, allocationSizeA, memoryTypeIndexA, {},
VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
wgpu::Texture wrappedTexBDevice3 = WrapVulkanImage(
thirdDevice, &defaultDescriptor, memoryFdB, allocationSizeB, memoryTypeIndexB, {});
thirdDevice, &defaultDescriptor, memoryFdB, allocationSizeB, memoryTypeIndexB, {},
VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
// Clear TexA
ClearImage(thirdDevice, wrappedTexADevice3,
@ -857,32 +866,39 @@ namespace dawn_native { namespace vulkan {
SimpleCopyTextureToTexture(thirdDevice, thirdDeviceQueue, wrappedTexADevice3,
wrappedTexBDevice3);
int signalFdTexBDevice3 = dawn_native::vulkan::ExportSignalSemaphoreOpaqueFD(
thirdDevice.Get(), wrappedTexBDevice3.Get());
IgnoreSignalSemaphore(thirdDevice, wrappedTexADevice3);
dawn_native::vulkan::ExternalImageExportInfoOpaqueFD exportInfoTexBDevice3;
dawn_native::vulkan::ExportVulkanImage(
wrappedTexBDevice3.Get(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, &exportInfoTexBDevice3);
IgnoreSignalSemaphore(wrappedTexADevice3);
// Import TexB, TexC on device 2
memoryFdB = GetMemoryFd(secondDeviceVk, allocationB);
wgpu::Texture wrappedTexBDevice2 =
WrapVulkanImage(secondDevice, &defaultDescriptor, memoryFdB, allocationSizeB,
memoryTypeIndexB, {signalFdTexBDevice3});
wgpu::Texture wrappedTexBDevice2 = WrapVulkanImage(
secondDevice, &defaultDescriptor, memoryFdB, allocationSizeB, memoryTypeIndexB,
exportInfoTexBDevice3.semaphoreHandles, exportInfoTexBDevice3.releasedOldLayout,
exportInfoTexBDevice3.releasedNewLayout);
wgpu::Texture wrappedTexCDevice2 = WrapVulkanImage(
secondDevice, &defaultDescriptor, memoryFdC, allocationSizeC, memoryTypeIndexC, {});
secondDevice, &defaultDescriptor, memoryFdC, allocationSizeC, memoryTypeIndexC, {},
VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
// Copy B->C on device 2
SimpleCopyTextureToTexture(secondDevice, secondDeviceQueue, wrappedTexBDevice2,
wrappedTexCDevice2);
int signalFdTexCDevice2 = dawn_native::vulkan::ExportSignalSemaphoreOpaqueFD(
secondDevice.Get(), wrappedTexCDevice2.Get());
IgnoreSignalSemaphore(secondDevice, wrappedTexBDevice2);
dawn_native::vulkan::ExternalImageExportInfoOpaqueFD exportInfoTexCDevice2;
dawn_native::vulkan::ExportVulkanImage(
wrappedTexCDevice2.Get(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, &exportInfoTexCDevice2);
IgnoreSignalSemaphore(wrappedTexBDevice2);
// Import TexC on device 1
memoryFdC = GetMemoryFd(deviceVk, allocationC);
wgpu::Texture wrappedTexCDevice1 =
WrapVulkanImage(device, &defaultDescriptor, memoryFdC, allocationSizeC,
memoryTypeIndexC, {signalFdTexCDevice2});
wgpu::Texture wrappedTexCDevice1 = WrapVulkanImage(
device, &defaultDescriptor, memoryFdC, allocationSizeC, memoryTypeIndexC,
exportInfoTexCDevice2.semaphoreHandles, exportInfoTexCDevice2.releasedOldLayout,
exportInfoTexCDevice2.releasedNewLayout);
// Create TexD on device 1
wgpu::Texture texD = device.CreateTexture(&defaultDescriptor);
@ -900,7 +916,7 @@ namespace dawn_native { namespace vulkan {
deviceVk->GetFencedDeleter()->DeleteWhenUnused(imageC);
deviceVk->GetFencedDeleter()->DeleteWhenUnused(allocationC);
IgnoreSignalSemaphore(device, wrappedTexCDevice1);
IgnoreSignalSemaphore(wrappedTexCDevice1);
}
// Tests a larger image is preserved when importing
@ -938,8 +954,9 @@ namespace dawn_native { namespace vulkan {
&allocationA, &allocationSizeA, &memoryTypeIndexA, &memoryFdA);
// Import the image on |secondDevice|
wgpu::Texture wrappedTexture = WrapVulkanImage(secondDevice, &descriptor, memoryFdA,
allocationSizeA, memoryTypeIndexA, {});
wgpu::Texture wrappedTexture =
WrapVulkanImage(secondDevice, &descriptor, memoryFdA, allocationSizeA, memoryTypeIndexA,
{}, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
// Draw a non-trivial picture
uint32_t width = 640, height = 480, pixelSize = 4;
@ -975,13 +992,17 @@ namespace dawn_native { namespace vulkan {
secondDeviceQueue.Submit(1, &commands);
}
int signalFd = dawn_native::vulkan::ExportSignalSemaphoreOpaqueFD(secondDevice.Get(),
wrappedTexture.Get());
dawn_native::vulkan::ExternalImageExportInfoOpaqueFD exportInfo;
dawn_native::vulkan::ExportVulkanImage(wrappedTexture.Get(),
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, &exportInfo);
int memoryFd = GetMemoryFd(secondDeviceVk, allocationA);
// Import the image on |device|
wgpu::Texture nextWrappedTexture = WrapVulkanImage(
device, &descriptor, memoryFd, allocationSizeA, memoryTypeIndexA, {signalFd});
wgpu::Texture nextWrappedTexture =
WrapVulkanImage(device, &descriptor, memoryFd, allocationSizeA, memoryTypeIndexA,
exportInfo.semaphoreHandles, exportInfo.releasedOldLayout,
exportInfo.releasedNewLayout);
// Copy the image into a buffer for comparison
wgpu::BufferDescriptor copyDesc;
@ -1006,7 +1027,7 @@ namespace dawn_native { namespace vulkan {
EXPECT_BUFFER_U32_RANGE_EQ(reinterpret_cast<uint32_t*>(data.data()), copyDstBuffer, 0,
data.size() / 4);
IgnoreSignalSemaphore(device, nextWrappedTexture);
IgnoreSignalSemaphore(nextWrappedTexture);
secondDeviceVk->GetFencedDeleter()->DeleteWhenUnused(imageA);
secondDeviceVk->GetFencedDeleter()->DeleteWhenUnused(allocationA);
}