diff --git a/src/dawn_native/DawnNative.cpp b/src/dawn_native/DawnNative.cpp index b7bb94b32d..22b3ddedc9 100644 --- a/src/dawn_native/DawnNative.cpp +++ b/src/dawn_native/DawnNative.cpp @@ -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 diff --git a/src/dawn_native/d3d12/D3D12Backend.cpp b/src/dawn_native/d3d12/D3D12Backend.cpp index 7196599426..73175faaee 100644 --- a/src/dawn_native/d3d12/D3D12Backend.cpp +++ b/src/dawn_native/d3d12/D3D12Backend.cpp @@ -48,7 +48,7 @@ namespace dawn_native { namespace d3d12 { } ExternalImageDescriptorDXGISharedHandle::ExternalImageDescriptorDXGISharedHandle() - : ExternalImageDescriptor(ExternalImageDescriptorType::DXGISharedHandle) { + : ExternalImageDescriptor(ExternalImageType::DXGISharedHandle) { } uint64_t SetExternalMemoryReservation(WGPUDevice device, diff --git a/src/dawn_native/d3d12/TextureD3D12.cpp b/src/dawn_native/d3d12/TextureD3D12.cpp index e30534a791..d9ef627e98 100644 --- a/src/dawn_native/d3d12/TextureD3D12.cpp +++ b/src/dawn_native/d3d12/TextureD3D12.cpp @@ -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); } diff --git a/src/dawn_native/metal/MetalBackend.mm b/src/dawn_native/metal/MetalBackend.mm index 24c44810e9..74265a23e9 100644 --- a/src/dawn_native/metal/MetalBackend.mm +++ b/src/dawn_native/metal/MetalBackend.mm @@ -28,7 +28,7 @@ namespace dawn_native { namespace metal { } ExternalImageDescriptorIOSurface::ExternalImageDescriptorIOSurface() - : ExternalImageDescriptor(ExternalImageDescriptorType::IOSurface) { + : ExternalImageDescriptor(ExternalImageType::IOSurface) { } WGPUTexture WrapIOSurface(WGPUDevice cDevice, diff --git a/src/dawn_native/metal/TextureMTL.mm b/src/dawn_native/metal/TextureMTL.mm index 22931fd5ca..c1a6abfa8d 100644 --- a/src/dawn_native/metal/TextureMTL.mm +++ b/src/dawn_native/metal/TextureMTL.mm @@ -355,7 +355,7 @@ namespace dawn_native { namespace metal { plane:plane]; [mtlDesc release]; - SetIsSubresourceContentInitialized(descriptor->isCleared, GetAllSubresources()); + SetIsSubresourceContentInitialized(descriptor->isInitialized, GetAllSubresources()); } Texture::~Texture() { diff --git a/src/dawn_native/vulkan/DeviceVk.cpp b/src/dawn_native/vulkan/DeviceVk.cpp index b8388581a1..c96cede4b1 100644 --- a/src/dawn_native/vulkan/DeviceVk.cpp +++ b/src/dawn_native/vulkan/DeviceVk.cpp @@ -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& 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* 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& waitHandles) { const TextureDescriptor* textureDescriptor = diff --git a/src/dawn_native/vulkan/DeviceVk.h b/src/dawn_native/vulkan/DeviceVk.h index 9adf3eea61..1b44bb7e3c 100644 --- a/src/dawn_native/vulkan/DeviceVk.h +++ b/src/dawn_native/vulkan/DeviceVk.h @@ -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& waitHandles); - - MaybeError SignalAndExportExternalTexture(Texture* texture, - ExternalSemaphoreHandle* outHandle); + bool SignalAndExportExternalTexture(Texture* texture, + VkImageLayout desiredLayout, + ExternalImageExportInfoVk* info, + std::vector* 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& waitHandles, @@ -203,4 +204,4 @@ namespace dawn_native { namespace vulkan { }} // namespace dawn_native::vulkan -#endif // DAWNNATIVE_VULKAN_DEVICEVK_H_ \ No newline at end of file +#endif // DAWNNATIVE_VULKAN_DEVICEVK_H_ diff --git a/src/dawn_native/vulkan/TextureVk.cpp b/src/dawn_native/vulkan/TextureVk.cpp index 5112a4cf07..7627282f77 100644 --- a/src/dawn_native/vulkan/TextureVk.cpp +++ b/src/dawn_native/vulkan/TextureVk.cpp @@ -462,7 +462,7 @@ namespace dawn_native { namespace vulkan { // static ResultOrError Texture::CreateFromExternal( Device* device, - const ExternalImageDescriptor* descriptor, + const ExternalImageDescriptorVk* descriptor, const TextureDescriptor* textureDescriptor, external_memory::Service* externalMemoryService) { Ref 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 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; diff --git a/src/dawn_native/vulkan/TextureVk.h b/src/dawn_native/vulkan/TextureVk.h index 6cf52f5007..1eafb0e3a8 100644 --- a/src/dawn_native/vulkan/TextureVk.h +++ b/src/dawn_native/vulkan/TextureVk.h @@ -49,7 +49,7 @@ namespace dawn_native { namespace vulkan { // image must be bound via Texture::BindExternalMemory. static ResultOrError 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 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 mWaitRequirements; diff --git a/src/dawn_native/vulkan/VulkanBackend.cpp b/src/dawn_native/vulkan/VulkanBackend.cpp index c1458a00fc..faf17f86e6 100644 --- a/src/dawn_native/vulkan/VulkanBackend.cpp +++ b/src/dawn_native/vulkan/VulkanBackend.cpp @@ -59,51 +59,75 @@ namespace dawn_native { namespace vulkan { return static_cast(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(cDevice); - Texture* texture = reinterpret_cast(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(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(descriptor); + Device* device = reinterpret_cast(cDevice); TextureBase* texture = device->CreateTextureWrappingVulkanImage( - descriptor, fdDescriptor->memoryFD, fdDescriptor->waitFDs); + fdDescriptor, fdDescriptor->memoryFD, fdDescriptor->waitFDs); return reinterpret_cast(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(cTexture); + Device* device = ToBackend(texture->GetDevice()); + ExternalImageExportInfoFD* fdInfo = static_cast(info); + return device->SignalAndExportExternalTexture(texture, desiredLayout, fdInfo, + &fdInfo->semaphoreHandles); + } +#endif // DAWN_PLATFORM_LINUX + default: + return false; + } + } }} // namespace dawn_native::vulkan diff --git a/src/dawn_native/vulkan/external_memory/MemoryServiceDmaBuf.cpp b/src/dawn_native/vulkan/external_memory/MemoryServiceDmaBuf.cpp index 4129745dc5..f173bab680 100644 --- a/src/dawn_native/vulkan/external_memory/MemoryServiceDmaBuf.cpp +++ b/src/dawn_native/vulkan/external_memory/MemoryServiceDmaBuf.cpp @@ -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 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 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 = diff --git a/src/dawn_native/vulkan/external_memory/MemoryServiceOpaqueFD.cpp b/src/dawn_native/vulkan/external_memory/MemoryServiceOpaqueFD.cpp index d43a10f703..ebdab5b2fd 100644 --- a/src/dawn_native/vulkan/external_memory/MemoryServiceOpaqueFD.cpp +++ b/src/dawn_native/vulkan/external_memory/MemoryServiceOpaqueFD.cpp @@ -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 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 = diff --git a/src/dawn_native/vulkan/external_memory/MemoryServiceZirconHandle.cpp b/src/dawn_native/vulkan/external_memory/MemoryServiceZirconHandle.cpp index 85c4e4a8d3..ae8744f406 100644 --- a/src/dawn_native/vulkan/external_memory/MemoryServiceZirconHandle.cpp +++ b/src/dawn_native/vulkan/external_memory/MemoryServiceZirconHandle.cpp @@ -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 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 = diff --git a/src/include/dawn_native/DawnNative.h b/src/include/dawn_native/DawnNative.h index a57baeb119..2199efa85b 100644 --- a/src/include/dawn_native/DawnNative.h +++ b/src/include/dawn_native/DawnNative.h @@ -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_ diff --git a/src/include/dawn_native/VulkanBackend.h b/src/include/dawn_native/VulkanBackend.h index 4e5aee995e..88cf03daf9 100644 --- a/src/include/dawn_native/VulkanBackend.h +++ b/src/include/dawn_native/VulkanBackend.h @@ -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 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 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 diff --git a/src/tests/end2end/D3D12ResourceWrappingTests.cpp b/src/tests/end2end/D3D12ResourceWrappingTests.cpp index b1187bc5a7..a028319f49 100644 --- a/src/tests/end2end/D3D12ResourceWrappingTests.cpp +++ b/src/tests/end2end/D3D12ResourceWrappingTests.cpp @@ -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 d3d11Texture; HRESULT hr = mD3d11Device->CreateTexture2D(d3dDescriptor, nullptr, &d3d11Texture); ASSERT_EQ(hr, S_OK); @@ -339,7 +339,7 @@ class D3D12SharedHandleUsageTests : public D3D12ResourceTestBase { reinterpret_cast(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}; diff --git a/src/tests/end2end/IOSurfaceWrappingTests.cpp b/src/tests/end2end/IOSurfaceWrappingTests.cpp index 9e44cb7a7c..ad025f3b35 100644 --- a/src/tests/end2end/IOSurfaceWrappingTests.cpp +++ b/src/tests/end2end/IOSurfaceWrappingTests.cpp @@ -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(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); } diff --git a/src/tests/white_box/VulkanImageWrappingTestsDmaBuf.cpp b/src/tests/white_box/VulkanImageWrappingTestsDmaBuf.cpp index f52b365560..8f6dae6335 100644 --- a/src/tests/white_box/VulkanImageWrappingTestsDmaBuf.cpp +++ b/src/tests/white_box/VulkanImageWrappingTestsDmaBuf.cpp @@ -104,16 +104,34 @@ namespace dawn_native { namespace vulkan { uint32_t stride, uint64_t drmModifier, std::vector 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 waitFDs, + VkImageLayout releasedOldLayout, + VkImageLayout releasedNewLayout, + bool isInitialized = true, bool expectValid = true) { dawn_native::vulkan::ExternalImageDescriptorDmaBuf descriptor; descriptor.cTextureDescriptor = reinterpret_cast(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(data.data()), copyDstBuffer, 0, data.size() / 4); - IgnoreSignalSemaphore(device, nextWrappedTexture); + IgnoreSignalSemaphore(nextWrappedTexture); } DAWN_INSTANTIATE_TEST(VulkanImageWrappingValidationTests, VulkanBackend()); diff --git a/src/tests/white_box/VulkanImageWrappingTestsOpaqueFD.cpp b/src/tests/white_box/VulkanImageWrappingTestsOpaqueFD.cpp index cfd3c60ff3..3259429db1 100644 --- a/src/tests/white_box/VulkanImageWrappingTestsOpaqueFD.cpp +++ b/src/tests/white_box/VulkanImageWrappingTestsOpaqueFD.cpp @@ -157,16 +157,34 @@ namespace dawn_native { namespace vulkan { VkDeviceSize allocationSize, uint32_t memoryTypeIndex, std::vector 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 waitFDs, + VkImageLayout releasedOldLayout, + VkImageLayout releasedNewLayout, + bool isInitialized = true, bool expectValid = true) { dawn_native::vulkan::ExternalImageDescriptorOpaqueFD descriptor; descriptor.cTextureDescriptor = reinterpret_cast(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(data.data()), copyDstBuffer, 0, data.size() / 4); - IgnoreSignalSemaphore(device, nextWrappedTexture); + IgnoreSignalSemaphore(nextWrappedTexture); secondDeviceVk->GetFencedDeleter()->DeleteWhenUnused(imageA); secondDeviceVk->GetFencedDeleter()->DeleteWhenUnused(allocationA); }