Add eager Transition support for external textures
This eagerly transitions external textures to be ready for export on every submit. With this support, we can save the current submit of export. Bug: chromium:1258986 Change-Id: I92c2019ff486afc24adc190a1f7b2f85f416cd52 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/97642 Kokoro: Kokoro <noreply+kokoro@google.com> Reviewed-by: Austin Eng <enga@chromium.org> Commit-Queue: Jie A Chen <jie.a.chen@intel.com>
This commit is contained in:
parent
490294e6fe
commit
7126ed9111
|
@ -14,23 +14,30 @@
|
||||||
#ifndef SRC_DAWN_NATIVE_VULKAN_COMMANDRECORDINGCONTEXT_H_
|
#ifndef SRC_DAWN_NATIVE_VULKAN_COMMANDRECORDINGCONTEXT_H_
|
||||||
#define SRC_DAWN_NATIVE_VULKAN_COMMANDRECORDINGCONTEXT_H_
|
#define SRC_DAWN_NATIVE_VULKAN_COMMANDRECORDINGCONTEXT_H_
|
||||||
|
|
||||||
|
#include <set>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "dawn/common/vulkan_platform.h"
|
#include "dawn/common/vulkan_platform.h"
|
||||||
#include "dawn/native/vulkan/BufferVk.h"
|
#include "dawn/native/vulkan/BufferVk.h"
|
||||||
|
|
||||||
namespace dawn::native::vulkan {
|
namespace dawn::native::vulkan {
|
||||||
|
|
||||||
|
class Texture;
|
||||||
|
|
||||||
// Used to track operations that are handled after recording.
|
// Used to track operations that are handled after recording.
|
||||||
// Currently only tracks semaphores, but may be used to do barrier coalescing in the future.
|
// Currently only tracks semaphores, but may be used to do barrier coalescing in the future.
|
||||||
struct CommandRecordingContext {
|
struct CommandRecordingContext {
|
||||||
VkCommandBuffer commandBuffer = VK_NULL_HANDLE;
|
VkCommandBuffer commandBuffer = VK_NULL_HANDLE;
|
||||||
std::vector<VkSemaphore> waitSemaphores = {};
|
std::vector<VkSemaphore> waitSemaphores = {};
|
||||||
std::vector<VkSemaphore> signalSemaphores = {};
|
|
||||||
|
|
||||||
// The internal buffers used in the workaround of texture-to-texture copies with compressed
|
// The internal buffers used in the workaround of texture-to-texture copies with compressed
|
||||||
// formats.
|
// formats.
|
||||||
std::vector<Ref<Buffer>> tempBuffers;
|
std::vector<Ref<Buffer>> tempBuffers;
|
||||||
|
|
||||||
|
// External textures that will be eagerly transitioned just before VkSubmit. The textures are
|
||||||
|
// kept alive by the CommandBuffer so they don't need to be Ref-ed.
|
||||||
|
std::set<Texture*> externalTexturesForEagerTransition;
|
||||||
|
|
||||||
// For Device state tracking only.
|
// For Device state tracking only.
|
||||||
VkCommandPool commandPool = VK_NULL_HANDLE;
|
VkCommandPool commandPool = VK_NULL_HANDLE;
|
||||||
bool used = false;
|
bool used = false;
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#include "dawn/native/vulkan/DeviceVk.h"
|
#include "dawn/native/vulkan/DeviceVk.h"
|
||||||
|
|
||||||
#include "dawn/common/Log.h"
|
#include "dawn/common/Log.h"
|
||||||
|
#include "dawn/common/NonCopyable.h"
|
||||||
#include "dawn/common/Platform.h"
|
#include "dawn/common/Platform.h"
|
||||||
#include "dawn/native/BackendConnection.h"
|
#include "dawn/native/BackendConnection.h"
|
||||||
#include "dawn/native/ChainUtils_autogen.h"
|
#include "dawn/native/ChainUtils_autogen.h"
|
||||||
|
@ -47,6 +48,35 @@
|
||||||
|
|
||||||
namespace dawn::native::vulkan {
|
namespace dawn::native::vulkan {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
// Destroy the semaphore when out of scope.
|
||||||
|
class ScopedSignalSemaphore : public NonMovable {
|
||||||
|
public:
|
||||||
|
ScopedSignalSemaphore(Device* device, VkSemaphore semaphore)
|
||||||
|
: mDevice(device), mSemaphore(semaphore) {}
|
||||||
|
~ScopedSignalSemaphore() {
|
||||||
|
if (mSemaphore != VK_NULL_HANDLE) {
|
||||||
|
ASSERT(mDevice);
|
||||||
|
mDevice->fn.DestroySemaphore(mDevice->GetVkDevice(), mSemaphore, nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VkSemaphore Get() { return mSemaphore; }
|
||||||
|
VkSemaphore Detach() {
|
||||||
|
VkSemaphore semaphore = mSemaphore;
|
||||||
|
mSemaphore = VK_NULL_HANDLE;
|
||||||
|
return semaphore;
|
||||||
|
}
|
||||||
|
VkSemaphore* InitializeInto() { return &mSemaphore; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
Device* mDevice = nullptr;
|
||||||
|
VkSemaphore mSemaphore = VK_NULL_HANDLE;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
// static
|
// static
|
||||||
ResultOrError<Ref<Device>> Device::Create(Adapter* adapter, const DeviceDescriptor* descriptor) {
|
ResultOrError<Ref<Device>> Device::Create(Adapter* adapter, const DeviceDescriptor* descriptor) {
|
||||||
Ref<Device> device = AcquireRef(new Device(adapter, descriptor));
|
Ref<Device> device = AcquireRef(new Device(adapter, descriptor));
|
||||||
|
@ -245,6 +275,10 @@ ResourceMemoryAllocator* Device::GetResourceMemoryAllocator() const {
|
||||||
return mResourceMemoryAllocator.get();
|
return mResourceMemoryAllocator.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
external_semaphore::Service* Device::GetExternalSemaphoreService() const {
|
||||||
|
return mExternalSemaphoreService.get();
|
||||||
|
}
|
||||||
|
|
||||||
void Device::EnqueueDeferredDeallocation(DescriptorSetAllocator* allocator) {
|
void Device::EnqueueDeferredDeallocation(DescriptorSetAllocator* allocator) {
|
||||||
mDescriptorAllocatorsPendingDeallocation.Enqueue(allocator, GetPendingCommandSerial());
|
mDescriptorAllocatorsPendingDeallocation.Enqueue(allocator, GetPendingCommandSerial());
|
||||||
}
|
}
|
||||||
|
@ -260,6 +294,19 @@ MaybeError Device::SubmitPendingCommands() {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ScopedSignalSemaphore scopedSignalSemaphore(this, VK_NULL_HANDLE);
|
||||||
|
if (mRecordingContext.externalTexturesForEagerTransition.size() > 0) {
|
||||||
|
// Create an external semaphore for all external textures that have been used in the pending
|
||||||
|
// submit.
|
||||||
|
DAWN_TRY_ASSIGN(*scopedSignalSemaphore.InitializeInto(),
|
||||||
|
mExternalSemaphoreService->CreateExportableSemaphore());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Transition eagerly all used external textures for export.
|
||||||
|
for (auto* texture : mRecordingContext.externalTexturesForEagerTransition) {
|
||||||
|
texture->TransitionEagerlyForExport(&mRecordingContext);
|
||||||
|
}
|
||||||
|
|
||||||
DAWN_TRY(
|
DAWN_TRY(
|
||||||
CheckVkSuccess(fn.EndCommandBuffer(mRecordingContext.commandBuffer), "vkEndCommandBuffer"));
|
CheckVkSuccess(fn.EndCommandBuffer(mRecordingContext.commandBuffer), "vkEndCommandBuffer"));
|
||||||
|
|
||||||
|
@ -274,9 +321,8 @@ MaybeError Device::SubmitPendingCommands() {
|
||||||
submitInfo.pWaitDstStageMask = dstStageMasks.data();
|
submitInfo.pWaitDstStageMask = dstStageMasks.data();
|
||||||
submitInfo.commandBufferCount = 1;
|
submitInfo.commandBufferCount = 1;
|
||||||
submitInfo.pCommandBuffers = &mRecordingContext.commandBuffer;
|
submitInfo.pCommandBuffers = &mRecordingContext.commandBuffer;
|
||||||
submitInfo.signalSemaphoreCount =
|
submitInfo.signalSemaphoreCount = (scopedSignalSemaphore.Get() == VK_NULL_HANDLE ? 0 : 1);
|
||||||
static_cast<uint32_t>(mRecordingContext.signalSemaphores.size());
|
submitInfo.pSignalSemaphores = AsVkArray(scopedSignalSemaphore.InitializeInto());
|
||||||
submitInfo.pSignalSemaphores = AsVkArray(mRecordingContext.signalSemaphores.data());
|
|
||||||
|
|
||||||
VkFence fence = VK_NULL_HANDLE;
|
VkFence fence = VK_NULL_HANDLE;
|
||||||
DAWN_TRY_ASSIGN(fence, GetUnusedFence());
|
DAWN_TRY_ASSIGN(fence, GetUnusedFence());
|
||||||
|
@ -293,10 +339,6 @@ MaybeError Device::SubmitPendingCommands() {
|
||||||
for (VkSemaphore semaphore : mRecordingContext.waitSemaphores) {
|
for (VkSemaphore semaphore : mRecordingContext.waitSemaphores) {
|
||||||
mDeleter->DeleteWhenUnused(semaphore);
|
mDeleter->DeleteWhenUnused(semaphore);
|
||||||
}
|
}
|
||||||
for (VkSemaphore semaphore : mRecordingContext.signalSemaphores) {
|
|
||||||
mDeleter->DeleteWhenUnused(semaphore);
|
|
||||||
}
|
|
||||||
|
|
||||||
IncrementLastSubmittedCommandSerial();
|
IncrementLastSubmittedCommandSerial();
|
||||||
ExecutionSerial lastSubmittedSerial = GetLastSubmittedCommandSerial();
|
ExecutionSerial lastSubmittedSerial = GetLastSubmittedCommandSerial();
|
||||||
mFencesInFlight.emplace(fence, lastSubmittedSerial);
|
mFencesInFlight.emplace(fence, lastSubmittedSerial);
|
||||||
|
@ -304,6 +346,26 @@ MaybeError Device::SubmitPendingCommands() {
|
||||||
CommandPoolAndBuffer submittedCommands = {mRecordingContext.commandPool,
|
CommandPoolAndBuffer submittedCommands = {mRecordingContext.commandPool,
|
||||||
mRecordingContext.commandBuffer};
|
mRecordingContext.commandBuffer};
|
||||||
mCommandsInFlight.Enqueue(submittedCommands, lastSubmittedSerial);
|
mCommandsInFlight.Enqueue(submittedCommands, lastSubmittedSerial);
|
||||||
|
|
||||||
|
if (mRecordingContext.externalTexturesForEagerTransition.size() > 0) {
|
||||||
|
// Export the signal semaphore.
|
||||||
|
ExternalSemaphoreHandle semaphoreHandle;
|
||||||
|
DAWN_TRY_ASSIGN(semaphoreHandle,
|
||||||
|
mExternalSemaphoreService->ExportSemaphore(scopedSignalSemaphore.Get()));
|
||||||
|
// The ownership of signal semaphore has been transferred, we no longer need to track it.
|
||||||
|
scopedSignalSemaphore.Detach();
|
||||||
|
// Update all external textures, eagerly transitioned in the submit, with the exported
|
||||||
|
// handle, and the duplicated handles.
|
||||||
|
bool first = true;
|
||||||
|
for (auto* texture : mRecordingContext.externalTexturesForEagerTransition) {
|
||||||
|
ExternalSemaphoreHandle handle =
|
||||||
|
(first ? semaphoreHandle
|
||||||
|
: mExternalSemaphoreService->DuplicateHandle(semaphoreHandle));
|
||||||
|
first = false;
|
||||||
|
texture->UpdateExternalSemaphoreHandle(handle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
mRecordingContext = CommandRecordingContext();
|
mRecordingContext = CommandRecordingContext();
|
||||||
DAWN_TRY(PrepareRecordingContext());
|
DAWN_TRY(PrepareRecordingContext());
|
||||||
|
|
||||||
|
@ -770,7 +832,6 @@ MaybeError Device::ImportExternalImage(const ExternalImageDescriptorVk* descript
|
||||||
ExternalMemoryHandle memoryHandle,
|
ExternalMemoryHandle memoryHandle,
|
||||||
VkImage image,
|
VkImage image,
|
||||||
const std::vector<ExternalSemaphoreHandle>& waitHandles,
|
const std::vector<ExternalSemaphoreHandle>& waitHandles,
|
||||||
VkSemaphore* outSignalSemaphore,
|
|
||||||
VkDeviceMemory* outAllocation,
|
VkDeviceMemory* outAllocation,
|
||||||
std::vector<VkSemaphore>* outWaitSemaphores) {
|
std::vector<VkSemaphore>* outWaitSemaphores) {
|
||||||
const TextureDescriptor* textureDescriptor = FromAPI(descriptor->cTextureDescriptor);
|
const TextureDescriptor* textureDescriptor = FromAPI(descriptor->cTextureDescriptor);
|
||||||
|
@ -794,9 +855,6 @@ MaybeError Device::ImportExternalImage(const ExternalImageDescriptorVk* descript
|
||||||
VK_IMAGE_CREATE_ALIAS_BIT_KHR),
|
VK_IMAGE_CREATE_ALIAS_BIT_KHR),
|
||||||
"External memory usage not supported");
|
"External memory usage not supported");
|
||||||
|
|
||||||
// Create an external semaphore to signal when the texture is done being used
|
|
||||||
DAWN_TRY_ASSIGN(*outSignalSemaphore, mExternalSemaphoreService->CreateExportableSemaphore());
|
|
||||||
|
|
||||||
// Import the external image's memory
|
// Import the external image's memory
|
||||||
external_memory::MemoryImportParams importParams;
|
external_memory::MemoryImportParams importParams;
|
||||||
DAWN_TRY_ASSIGN(importParams, mExternalMemoryService->GetMemoryImportParams(descriptor, image));
|
DAWN_TRY_ASSIGN(importParams, mExternalMemoryService->GetMemoryImportParams(descriptor, image));
|
||||||
|
@ -821,15 +879,12 @@ bool Device::SignalAndExportExternalTexture(
|
||||||
return !ConsumedError([&]() -> MaybeError {
|
return !ConsumedError([&]() -> MaybeError {
|
||||||
DAWN_TRY(ValidateObject(texture));
|
DAWN_TRY(ValidateObject(texture));
|
||||||
|
|
||||||
VkSemaphore signalSemaphore;
|
ExternalSemaphoreHandle semaphoreHandle;
|
||||||
VkImageLayout releasedOldLayout;
|
VkImageLayout releasedOldLayout;
|
||||||
VkImageLayout releasedNewLayout;
|
VkImageLayout releasedNewLayout;
|
||||||
DAWN_TRY(texture->ExportExternalTexture(desiredLayout, &signalSemaphore, &releasedOldLayout,
|
DAWN_TRY(texture->ExportExternalTexture(desiredLayout, &semaphoreHandle, &releasedOldLayout,
|
||||||
&releasedNewLayout));
|
&releasedNewLayout));
|
||||||
|
|
||||||
ExternalSemaphoreHandle semaphoreHandle;
|
|
||||||
DAWN_TRY_ASSIGN(semaphoreHandle,
|
|
||||||
mExternalSemaphoreService->ExportSemaphore(signalSemaphore));
|
|
||||||
semaphoreHandles->push_back(semaphoreHandle);
|
semaphoreHandles->push_back(semaphoreHandle);
|
||||||
info->releasedOldLayout = releasedOldLayout;
|
info->releasedOldLayout = releasedOldLayout;
|
||||||
info->releasedNewLayout = releasedNewLayout;
|
info->releasedNewLayout = releasedNewLayout;
|
||||||
|
@ -856,7 +911,6 @@ TextureBase* Device::CreateTextureWrappingVulkanImage(
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
VkSemaphore signalSemaphore = VK_NULL_HANDLE;
|
|
||||||
VkDeviceMemory allocation = VK_NULL_HANDLE;
|
VkDeviceMemory allocation = VK_NULL_HANDLE;
|
||||||
std::vector<VkSemaphore> waitSemaphores;
|
std::vector<VkSemaphore> waitSemaphores;
|
||||||
waitSemaphores.reserve(waitHandles.size());
|
waitSemaphores.reserve(waitHandles.size());
|
||||||
|
@ -869,18 +923,13 @@ TextureBase* Device::CreateTextureWrappingVulkanImage(
|
||||||
mExternalMemoryService.get()),
|
mExternalMemoryService.get()),
|
||||||
&result) ||
|
&result) ||
|
||||||
ConsumedError(ImportExternalImage(descriptor, memoryHandle, result->GetHandle(),
|
ConsumedError(ImportExternalImage(descriptor, memoryHandle, result->GetHandle(),
|
||||||
waitHandles, &signalSemaphore, &allocation,
|
waitHandles, &allocation, &waitSemaphores)) ||
|
||||||
&waitSemaphores)) ||
|
ConsumedError(result->BindExternalMemory(descriptor, allocation, waitSemaphores))) {
|
||||||
ConsumedError(
|
|
||||||
result->BindExternalMemory(descriptor, signalSemaphore, allocation, waitSemaphores))) {
|
|
||||||
// Delete the Texture if it was created
|
// Delete the Texture if it was created
|
||||||
if (result != nullptr) {
|
if (result != nullptr) {
|
||||||
result->Release();
|
result->Release();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clear the signal semaphore
|
|
||||||
fn.DestroySemaphore(GetVkDevice(), signalSemaphore, nullptr);
|
|
||||||
|
|
||||||
// Clear image memory
|
// Clear image memory
|
||||||
fn.FreeMemory(GetVkDevice(), allocation, nullptr);
|
fn.FreeMemory(GetVkDevice(), allocation, nullptr);
|
||||||
|
|
||||||
|
@ -1015,11 +1064,6 @@ void Device::DestroyImpl() {
|
||||||
}
|
}
|
||||||
mRecordingContext.waitSemaphores.clear();
|
mRecordingContext.waitSemaphores.clear();
|
||||||
|
|
||||||
for (VkSemaphore semaphore : mRecordingContext.signalSemaphores) {
|
|
||||||
fn.DestroySemaphore(mVkDevice, semaphore, nullptr);
|
|
||||||
}
|
|
||||||
mRecordingContext.signalSemaphores.clear();
|
|
||||||
|
|
||||||
// Some commands might still be marked as in-flight if we shut down because of a device
|
// Some commands might still be marked as in-flight if we shut down because of a device
|
||||||
// loss. Recycle them as unused so that we free them below.
|
// loss. Recycle them as unused so that we free them below.
|
||||||
RecycleCompletedCommands();
|
RecycleCompletedCommands();
|
||||||
|
|
|
@ -61,6 +61,7 @@ class Device final : public DeviceBase {
|
||||||
FencedDeleter* GetFencedDeleter() const;
|
FencedDeleter* GetFencedDeleter() const;
|
||||||
RenderPassCache* GetRenderPassCache() const;
|
RenderPassCache* GetRenderPassCache() const;
|
||||||
ResourceMemoryAllocator* GetResourceMemoryAllocator() const;
|
ResourceMemoryAllocator* GetResourceMemoryAllocator() const;
|
||||||
|
external_semaphore::Service* GetExternalSemaphoreService() const;
|
||||||
|
|
||||||
CommandRecordingContext* GetPendingRecordingContext();
|
CommandRecordingContext* GetPendingRecordingContext();
|
||||||
MaybeError SubmitPendingCommands();
|
MaybeError SubmitPendingCommands();
|
||||||
|
@ -216,7 +217,6 @@ class Device final : public DeviceBase {
|
||||||
ExternalMemoryHandle memoryHandle,
|
ExternalMemoryHandle memoryHandle,
|
||||||
VkImage image,
|
VkImage image,
|
||||||
const std::vector<ExternalSemaphoreHandle>& waitHandles,
|
const std::vector<ExternalSemaphoreHandle>& waitHandles,
|
||||||
VkSemaphore* outSignalSemaphore,
|
|
||||||
VkDeviceMemory* outAllocation,
|
VkDeviceMemory* outAllocation,
|
||||||
std::vector<VkSemaphore>* outWaitSemaphores);
|
std::vector<VkSemaphore>* outWaitSemaphores);
|
||||||
};
|
};
|
||||||
|
|
|
@ -24,15 +24,18 @@ namespace dawn::native::vulkan {
|
||||||
using ExternalMemoryHandle = int;
|
using ExternalMemoryHandle = int;
|
||||||
// File descriptor
|
// File descriptor
|
||||||
using ExternalSemaphoreHandle = int;
|
using ExternalSemaphoreHandle = int;
|
||||||
|
const ExternalSemaphoreHandle kNullExternalSemaphoreHandle = -1;
|
||||||
#elif DAWN_PLATFORM_IS(FUCHSIA)
|
#elif DAWN_PLATFORM_IS(FUCHSIA)
|
||||||
// Really a Zircon vmo handle.
|
// Really a Zircon vmo handle.
|
||||||
using ExternalMemoryHandle = zx_handle_t;
|
using ExternalMemoryHandle = zx_handle_t;
|
||||||
// Really a Zircon event handle.
|
// Really a Zircon event handle.
|
||||||
using ExternalSemaphoreHandle = zx_handle_t;
|
using ExternalSemaphoreHandle = zx_handle_t;
|
||||||
|
const ExternalSemaphoreHandle kNullExternalSemaphoreHandle = ZX_HANDLE_INVALID;
|
||||||
#else
|
#else
|
||||||
// Generic types so that the Null service can compile, not used for real handles
|
// Generic types so that the Null service can compile, not used for real handles
|
||||||
using ExternalMemoryHandle = void*;
|
using ExternalMemoryHandle = void*;
|
||||||
using ExternalSemaphoreHandle = void*;
|
using ExternalSemaphoreHandle = void*;
|
||||||
|
const ExternalSemaphoreHandle kNullExternalSemaphoreHandle = nullptr;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
} // namespace dawn::native::vulkan
|
} // namespace dawn::native::vulkan
|
||||||
|
|
|
@ -783,7 +783,6 @@ void Texture::InitializeForSwapChain(VkImage nativeImage) {
|
||||||
}
|
}
|
||||||
|
|
||||||
MaybeError Texture::BindExternalMemory(const ExternalImageDescriptorVk* descriptor,
|
MaybeError Texture::BindExternalMemory(const ExternalImageDescriptorVk* descriptor,
|
||||||
VkSemaphore signalSemaphore,
|
|
||||||
VkDeviceMemory externalMemoryAllocation,
|
VkDeviceMemory externalMemoryAllocation,
|
||||||
std::vector<VkSemaphore> waitSemaphores) {
|
std::vector<VkSemaphore> waitSemaphores) {
|
||||||
Device* device = ToBackend(GetDevice());
|
Device* device = ToBackend(GetDevice());
|
||||||
|
@ -798,17 +797,53 @@ MaybeError Texture::BindExternalMemory(const ExternalImageDescriptorVk* descript
|
||||||
|
|
||||||
// Success, acquire all the external objects.
|
// Success, acquire all the external objects.
|
||||||
mExternalAllocation = externalMemoryAllocation;
|
mExternalAllocation = externalMemoryAllocation;
|
||||||
mSignalSemaphore = signalSemaphore;
|
|
||||||
mWaitRequirements = std::move(waitSemaphores);
|
mWaitRequirements = std::move(waitSemaphores);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Texture::TransitionEagerlyForExport(CommandRecordingContext* recordingContext) {
|
||||||
|
mExternalState = ExternalState::EagerlyTransitioned;
|
||||||
|
|
||||||
|
Aspect aspects = ComputeAspectsForSubresourceStorage();
|
||||||
|
ASSERT(GetNumMipLevels() == 1 && GetArrayLayers() == 1);
|
||||||
|
SubresourceRange range = {aspects, {0, 1}, {0, 1}};
|
||||||
|
|
||||||
|
wgpu::TextureUsage usage = mSubresourceLastUsages->Get(aspects, 0, 0);
|
||||||
|
|
||||||
|
std::vector<VkImageMemoryBarrier> barriers;
|
||||||
|
VkPipelineStageFlags srcStages = 0;
|
||||||
|
VkPipelineStageFlags dstStages = 0;
|
||||||
|
|
||||||
|
// Same usage as last.
|
||||||
|
TransitionUsageAndGetResourceBarrier(usage, range, &barriers, &srcStages, &dstStages);
|
||||||
|
|
||||||
|
ASSERT(barriers.size() == 1);
|
||||||
|
VkImageMemoryBarrier& barrier = barriers[0];
|
||||||
|
// The barrier must be paired with another barrier that will specify the dst access mask on the
|
||||||
|
// importing queue.
|
||||||
|
barrier.dstAccessMask = 0;
|
||||||
|
|
||||||
|
if (mDesiredExportLayout != VK_IMAGE_LAYOUT_UNDEFINED) {
|
||||||
|
barrier.newLayout = mDesiredExportLayout;
|
||||||
|
}
|
||||||
|
|
||||||
|
Device* device = ToBackend(GetDevice());
|
||||||
|
barrier.srcQueueFamilyIndex = device->GetGraphicsQueueFamily();
|
||||||
|
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_EXTERNAL_KHR;
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
dstStages = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
|
||||||
|
|
||||||
|
device->fn.CmdPipelineBarrier(recordingContext->commandBuffer, srcStages, dstStages, 0, 0,
|
||||||
|
nullptr, 0, nullptr, 1, &barrier);
|
||||||
|
}
|
||||||
|
|
||||||
MaybeError Texture::ExportExternalTexture(VkImageLayout desiredLayout,
|
MaybeError Texture::ExportExternalTexture(VkImageLayout desiredLayout,
|
||||||
VkSemaphore* signalSemaphore,
|
ExternalSemaphoreHandle* handle,
|
||||||
VkImageLayout* releasedOldLayout,
|
VkImageLayout* releasedOldLayout,
|
||||||
VkImageLayout* releasedNewLayout) {
|
VkImageLayout* releasedNewLayout) {
|
||||||
Device* device = ToBackend(GetDevice());
|
|
||||||
|
|
||||||
DAWN_INVALID_IF(mExternalState == ExternalState::Released,
|
DAWN_INVALID_IF(mExternalState == ExternalState::Released,
|
||||||
"Can't export a signal semaphore from signaled texture %s.", this);
|
"Can't export a signal semaphore from signaled texture %s.", this);
|
||||||
|
|
||||||
|
@ -816,8 +851,6 @@ MaybeError Texture::ExportExternalTexture(VkImageLayout desiredLayout,
|
||||||
"Can't export a signal semaphore from destroyed or non-external texture %s.",
|
"Can't export a signal semaphore from destroyed or non-external texture %s.",
|
||||||
this);
|
this);
|
||||||
|
|
||||||
ASSERT(mSignalSemaphore != VK_NULL_HANDLE);
|
|
||||||
|
|
||||||
// Release the texture
|
// Release the texture
|
||||||
mExternalState = ExternalState::Released;
|
mExternalState = ExternalState::Released;
|
||||||
|
|
||||||
|
@ -825,54 +858,28 @@ MaybeError Texture::ExportExternalTexture(VkImageLayout desiredLayout,
|
||||||
ASSERT(GetNumMipLevels() == 1 && GetArrayLayers() == 1);
|
ASSERT(GetNumMipLevels() == 1 && GetArrayLayers() == 1);
|
||||||
wgpu::TextureUsage usage = mSubresourceLastUsages->Get(aspects, 0, 0);
|
wgpu::TextureUsage usage = mSubresourceLastUsages->Get(aspects, 0, 0);
|
||||||
|
|
||||||
VkImageMemoryBarrier barrier;
|
VkImageLayout layout = VulkanImageLayout(this, usage);
|
||||||
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
|
||||||
barrier.pNext = nullptr;
|
|
||||||
barrier.image = GetHandle();
|
|
||||||
barrier.subresourceRange.aspectMask = VulkanAspectMask(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(this, usage);
|
|
||||||
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
|
|
||||||
recordingContext->signalSemaphores.push_back(mSignalSemaphore);
|
|
||||||
DAWN_TRY(device->SubmitPendingCommands());
|
|
||||||
|
|
||||||
// Write out the layouts and signal semaphore
|
// Write out the layouts and signal semaphore
|
||||||
*releasedOldLayout = barrier.oldLayout;
|
*releasedOldLayout = layout;
|
||||||
*releasedNewLayout = barrier.newLayout;
|
*releasedNewLayout = (desiredLayout == VK_IMAGE_LAYOUT_UNDEFINED ? layout : desiredLayout);
|
||||||
*signalSemaphore = mSignalSemaphore;
|
|
||||||
|
|
||||||
mSignalSemaphore = VK_NULL_HANDLE;
|
mDesiredExportLayout = desiredLayout;
|
||||||
|
|
||||||
|
// We have to manually trigger a transition if the texture hasn't been actually used, or the
|
||||||
|
// desired layout is not VK_IMAGE_LAYOUT_UNDEFINED.
|
||||||
|
// TODO(dawn:1509): Avoid the empty submit.
|
||||||
|
if (mExternalSemaphoreHandle == kNullExternalSemaphoreHandle ||
|
||||||
|
desiredLayout != VK_IMAGE_LAYOUT_UNDEFINED) {
|
||||||
|
Device* device = ToBackend(GetDevice());
|
||||||
|
CommandRecordingContext* recordingContext = device->GetPendingRecordingContext();
|
||||||
|
recordingContext->externalTexturesForEagerTransition.insert(this);
|
||||||
|
DAWN_TRY(device->SubmitPendingCommands());
|
||||||
|
}
|
||||||
|
ASSERT(mExternalSemaphoreHandle != kNullExternalSemaphoreHandle);
|
||||||
|
|
||||||
|
*handle = mExternalSemaphoreHandle;
|
||||||
|
mExternalSemaphoreHandle = kNullExternalSemaphoreHandle;
|
||||||
|
|
||||||
// Destroy the texture so it can't be used again
|
// Destroy the texture so it can't be used again
|
||||||
Destroy();
|
Destroy();
|
||||||
|
@ -907,8 +914,11 @@ void Texture::DestroyImpl() {
|
||||||
|
|
||||||
mHandle = VK_NULL_HANDLE;
|
mHandle = VK_NULL_HANDLE;
|
||||||
mExternalAllocation = VK_NULL_HANDLE;
|
mExternalAllocation = VK_NULL_HANDLE;
|
||||||
// If a signal semaphore exists it should be requested before we delete the texture
|
|
||||||
ASSERT(mSignalSemaphore == VK_NULL_HANDLE);
|
if (mExternalSemaphoreHandle != kNullExternalSemaphoreHandle) {
|
||||||
|
device->GetExternalSemaphoreService()->CloseHandle(mExternalSemaphoreHandle);
|
||||||
|
}
|
||||||
|
mExternalSemaphoreHandle = kNullExternalSemaphoreHandle;
|
||||||
}
|
}
|
||||||
// For Vulkan, we currently run the base destruction code after the internal changes because
|
// For Vulkan, we currently run the base destruction code after the internal changes because
|
||||||
// of the dependency on the texture state which the base code overwrites too early.
|
// of the dependency on the texture state which the base code overwrites too early.
|
||||||
|
@ -929,7 +939,9 @@ void Texture::TweakTransitionForExternalUsage(CommandRecordingContext* recording
|
||||||
// have already added into the vector during current transition.
|
// have already added into the vector during current transition.
|
||||||
ASSERT(barriers->size() - transitionBarrierStart <= 1);
|
ASSERT(barriers->size() - transitionBarrierStart <= 1);
|
||||||
|
|
||||||
if (mExternalState == ExternalState::PendingAcquire) {
|
if (mExternalState == ExternalState::PendingAcquire ||
|
||||||
|
mExternalState == ExternalState::EagerlyTransitioned) {
|
||||||
|
recordingContext->externalTexturesForEagerTransition.insert(this);
|
||||||
if (barriers->size() == transitionBarrierStart) {
|
if (barriers->size() == transitionBarrierStart) {
|
||||||
barriers->push_back(BuildMemoryBarrier(
|
barriers->push_back(BuildMemoryBarrier(
|
||||||
this, wgpu::TextureUsage::None, wgpu::TextureUsage::None,
|
this, wgpu::TextureUsage::None, wgpu::TextureUsage::None,
|
||||||
|
@ -946,27 +958,35 @@ void Texture::TweakTransitionForExternalUsage(CommandRecordingContext* recording
|
||||||
// this.
|
// this.
|
||||||
barrier->srcAccessMask = 0;
|
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
|
// Save the desired layout. We may need to transition through an intermediate
|
||||||
// |mPendingAcquireLayout| first.
|
// |mPendingAcquireLayout| first.
|
||||||
VkImageLayout desiredLayout = barrier->newLayout;
|
VkImageLayout desiredLayout = barrier->newLayout;
|
||||||
|
|
||||||
bool isInitialized = IsSubresourceContentInitialized(GetAllSubresources());
|
if (mExternalState == ExternalState::PendingAcquire) {
|
||||||
|
bool isInitialized = IsSubresourceContentInitialized(GetAllSubresources());
|
||||||
|
|
||||||
// We don't care about the pending old layout if the texture is uninitialized. The
|
// We don't care about the pending old layout if the texture is uninitialized. The
|
||||||
// driver is free to discard it. Also it is invalid to transition to layout UNDEFINED or
|
// driver is free to discard it. Also it is invalid to transition to layout UNDEFINED or
|
||||||
// PREINITIALIZED. If the embedder provided no new layout, or we don't care about the
|
// PREINITIALIZED. If the embedder provided no new layout, or we don't care about the
|
||||||
// previous contents, we can skip the layout transition.
|
// previous contents, we can skip the layout transition.
|
||||||
// https://www.khronos.org/registry/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-VkImageMemoryBarrier-newLayout-01198
|
// https://www.khronos.org/registry/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-VkImageMemoryBarrier-newLayout-01198
|
||||||
if (!isInitialized || mPendingAcquireNewLayout == VK_IMAGE_LAYOUT_UNDEFINED ||
|
if (!isInitialized || mPendingAcquireNewLayout == VK_IMAGE_LAYOUT_UNDEFINED ||
|
||||||
mPendingAcquireNewLayout == VK_IMAGE_LAYOUT_PREINITIALIZED) {
|
mPendingAcquireNewLayout == VK_IMAGE_LAYOUT_PREINITIALIZED) {
|
||||||
barrier->oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
barrier->oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||||
barrier->newLayout = desiredLayout;
|
barrier->newLayout = desiredLayout;
|
||||||
|
} else {
|
||||||
|
barrier->oldLayout = mPendingAcquireOldLayout;
|
||||||
|
barrier->newLayout = mPendingAcquireNewLayout;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
barrier->oldLayout = mPendingAcquireOldLayout;
|
// In case of ExternalState::EagerlyTransitioned, the layouts of the texture's queue
|
||||||
barrier->newLayout = mPendingAcquireNewLayout;
|
// release were always same. So we exactly match that here for the queue acquire.
|
||||||
|
// The spec text:
|
||||||
|
// If the transfer is via an image memory barrier, and an image layout transition is
|
||||||
|
// desired, then the values of oldLayout and newLayout in the release operation's memory
|
||||||
|
// barrier must be equal to values of oldLayout and newLayout in the acquire operation's
|
||||||
|
// memory barrier.
|
||||||
|
barrier->newLayout = barrier->oldLayout;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If these are unequal, we need an another barrier to transition the layout.
|
// If these are unequal, we need an another barrier to transition the layout.
|
||||||
|
@ -981,9 +1001,8 @@ void Texture::TweakTransitionForExternalUsage(CommandRecordingContext* recording
|
||||||
layoutBarrier.oldLayout = barrier->newLayout;
|
layoutBarrier.oldLayout = barrier->newLayout;
|
||||||
layoutBarrier.newLayout = desiredLayout;
|
layoutBarrier.newLayout = desiredLayout;
|
||||||
|
|
||||||
// We already transitioned these.
|
|
||||||
layoutBarrier.srcAccessMask = 0;
|
layoutBarrier.srcAccessMask = 0;
|
||||||
layoutBarrier.dstAccessMask = 0;
|
layoutBarrier.dstAccessMask = barrier->dstAccessMask;
|
||||||
layoutBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
layoutBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||||
layoutBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
layoutBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||||
|
|
||||||
|
@ -1322,6 +1341,14 @@ void Texture::EnsureSubresourceContentInitialized(CommandRecordingContext* recor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Texture::UpdateExternalSemaphoreHandle(ExternalSemaphoreHandle handle) {
|
||||||
|
if (mExternalSemaphoreHandle != kNullExternalSemaphoreHandle) {
|
||||||
|
Device* device = ToBackend(GetDevice());
|
||||||
|
device->GetExternalSemaphoreService()->CloseHandle(mExternalSemaphoreHandle);
|
||||||
|
}
|
||||||
|
mExternalSemaphoreHandle = handle;
|
||||||
|
}
|
||||||
|
|
||||||
VkImageLayout Texture::GetCurrentLayoutForSwapChain() const {
|
VkImageLayout Texture::GetCurrentLayoutForSwapChain() const {
|
||||||
ASSERT(GetFormat().aspects == Aspect::Color);
|
ASSERT(GetFormat().aspects == Aspect::Color);
|
||||||
return VulkanImageLayout(this, mSubresourceLastUsages->Get(Aspect::Color, 0, 0));
|
return VulkanImageLayout(this, mSubresourceLastUsages->Get(Aspect::Color, 0, 0));
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
#include "dawn/native/Texture.h"
|
#include "dawn/native/Texture.h"
|
||||||
#include "dawn/native/vulkan/ExternalHandle.h"
|
#include "dawn/native/vulkan/ExternalHandle.h"
|
||||||
#include "dawn/native/vulkan/external_memory/MemoryService.h"
|
#include "dawn/native/vulkan/external_memory/MemoryService.h"
|
||||||
|
#include "dawn/native/vulkan/external_semaphore/SemaphoreService.h"
|
||||||
|
|
||||||
namespace dawn::native::vulkan {
|
namespace dawn::native::vulkan {
|
||||||
|
|
||||||
|
@ -77,6 +78,9 @@ class Texture final : public TextureBase {
|
||||||
VkPipelineStageFlags* srcStages,
|
VkPipelineStageFlags* srcStages,
|
||||||
VkPipelineStageFlags* dstStages);
|
VkPipelineStageFlags* dstStages);
|
||||||
|
|
||||||
|
// Eagerly transition the texture for export.
|
||||||
|
void TransitionEagerlyForExport(CommandRecordingContext* recordingContext);
|
||||||
|
|
||||||
void EnsureSubresourceContentInitialized(CommandRecordingContext* recordingContext,
|
void EnsureSubresourceContentInitialized(CommandRecordingContext* recordingContext,
|
||||||
const SubresourceRange& range);
|
const SubresourceRange& range);
|
||||||
|
|
||||||
|
@ -85,12 +89,12 @@ class Texture final : public TextureBase {
|
||||||
// Binds externally allocated memory to the VkImage and on success, takes ownership of
|
// Binds externally allocated memory to the VkImage and on success, takes ownership of
|
||||||
// semaphores.
|
// semaphores.
|
||||||
MaybeError BindExternalMemory(const ExternalImageDescriptorVk* descriptor,
|
MaybeError BindExternalMemory(const ExternalImageDescriptorVk* descriptor,
|
||||||
VkSemaphore signalSemaphore,
|
|
||||||
VkDeviceMemory externalMemoryAllocation,
|
VkDeviceMemory externalMemoryAllocation,
|
||||||
std::vector<VkSemaphore> waitSemaphores);
|
std::vector<VkSemaphore> waitSemaphores);
|
||||||
|
// Update the 'ExternalSemaphoreHandle' to be used for export with the newly submitted one.
|
||||||
|
void UpdateExternalSemaphoreHandle(ExternalSemaphoreHandle handle);
|
||||||
MaybeError ExportExternalTexture(VkImageLayout desiredLayout,
|
MaybeError ExportExternalTexture(VkImageLayout desiredLayout,
|
||||||
VkSemaphore* signalSemaphore,
|
ExternalSemaphoreHandle* handle,
|
||||||
VkImageLayout* releasedOldLayout,
|
VkImageLayout* releasedOldLayout,
|
||||||
VkImageLayout* releasedNewLayout);
|
VkImageLayout* releasedNewLayout);
|
||||||
|
|
||||||
|
@ -156,14 +160,30 @@ class Texture final : public TextureBase {
|
||||||
ResourceMemoryAllocation mMemoryAllocation;
|
ResourceMemoryAllocation mMemoryAllocation;
|
||||||
VkDeviceMemory mExternalAllocation = VK_NULL_HANDLE;
|
VkDeviceMemory mExternalAllocation = VK_NULL_HANDLE;
|
||||||
|
|
||||||
enum class ExternalState { InternalOnly, PendingAcquire, Acquired, Released };
|
// The states of an external texture:
|
||||||
|
// InternalOnly: Not initialized as an external texture yet.
|
||||||
|
// PendingAcquire: Intialized as an external texture already, but unavailable for access yet.
|
||||||
|
// Acquired: Ready for access.
|
||||||
|
// EagerlyTransitioned: The texture has ever been used, and eagerly transitioned for export.
|
||||||
|
// Now it can be acquired for access again, or directly exported. Released: The texture has
|
||||||
|
// been destoried, and should no longer be used.
|
||||||
|
enum class ExternalState {
|
||||||
|
InternalOnly,
|
||||||
|
PendingAcquire,
|
||||||
|
Acquired,
|
||||||
|
EagerlyTransitioned,
|
||||||
|
Released
|
||||||
|
};
|
||||||
ExternalState mExternalState = ExternalState::InternalOnly;
|
ExternalState mExternalState = ExternalState::InternalOnly;
|
||||||
ExternalState mLastExternalState = ExternalState::InternalOnly;
|
ExternalState mLastExternalState = ExternalState::InternalOnly;
|
||||||
|
|
||||||
VkImageLayout mPendingAcquireOldLayout;
|
VkImageLayout mPendingAcquireOldLayout;
|
||||||
VkImageLayout mPendingAcquireNewLayout;
|
VkImageLayout mPendingAcquireNewLayout;
|
||||||
|
|
||||||
VkSemaphore mSignalSemaphore = VK_NULL_HANDLE;
|
VkImageLayout mDesiredExportLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||||
|
|
||||||
|
ExternalSemaphoreHandle mExternalSemaphoreHandle = kNullExternalSemaphoreHandle;
|
||||||
|
|
||||||
std::vector<VkSemaphore> mWaitRequirements;
|
std::vector<VkSemaphore> mWaitRequirements;
|
||||||
|
|
||||||
// Note that in early Vulkan versions it is not possible to transition depth and stencil
|
// Note that in early Vulkan versions it is not possible to transition depth and stencil
|
||||||
|
|
|
@ -48,6 +48,12 @@ class Service {
|
||||||
// Export a VkSemaphore into an external handle
|
// Export a VkSemaphore into an external handle
|
||||||
ResultOrError<ExternalSemaphoreHandle> ExportSemaphore(VkSemaphore semaphore);
|
ResultOrError<ExternalSemaphoreHandle> ExportSemaphore(VkSemaphore semaphore);
|
||||||
|
|
||||||
|
// Duplicate a new external handle from the given one.
|
||||||
|
ExternalSemaphoreHandle DuplicateHandle(ExternalSemaphoreHandle handle);
|
||||||
|
|
||||||
|
// Close an external handle.
|
||||||
|
void CloseHandle(ExternalSemaphoreHandle handle);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Device* mDevice = nullptr;
|
Device* mDevice = nullptr;
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
#include "dawn/native/vulkan/AdapterVk.h"
|
#include "dawn/native/vulkan/AdapterVk.h"
|
||||||
|
@ -135,4 +136,15 @@ ResultOrError<ExternalSemaphoreHandle> Service::ExportSemaphore(VkSemaphore sema
|
||||||
return fd;
|
return fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ExternalSemaphoreHandle Service::DuplicateHandle(ExternalSemaphoreHandle handle) {
|
||||||
|
int fd = dup(handle);
|
||||||
|
ASSERT(fd >= 0);
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Service::CloseHandle(ExternalSemaphoreHandle handle) {
|
||||||
|
int ret = close(handle);
|
||||||
|
ASSERT(ret == 0);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace dawn::native::vulkan::external_semaphore
|
} // namespace dawn::native::vulkan::external_semaphore
|
||||||
|
|
|
@ -47,4 +47,10 @@ ResultOrError<ExternalSemaphoreHandle> Service::ExportSemaphore(VkSemaphore sema
|
||||||
return DAWN_UNIMPLEMENTED_ERROR("Using null semaphore service to interop inside Vulkan");
|
return DAWN_UNIMPLEMENTED_ERROR("Using null semaphore service to interop inside Vulkan");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ExternalSemaphoreHandle Service::DuplicateHandle(ExternalSemaphoreHandle handle) {
|
||||||
|
return kNullExternalSemaphoreHandle;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Service::CloseHandle(ExternalSemaphoreHandle handle) {}
|
||||||
|
|
||||||
} // namespace dawn::native::vulkan::external_semaphore
|
} // namespace dawn::native::vulkan::external_semaphore
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include <zircon/syscalls.h>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
#include "dawn/native/vulkan/AdapterVk.h"
|
#include "dawn/native/vulkan/AdapterVk.h"
|
||||||
|
@ -129,4 +130,16 @@ ResultOrError<ExternalSemaphoreHandle> Service::ExportSemaphore(VkSemaphore sema
|
||||||
return handle;
|
return handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ExternalSemaphoreHandle Service::DuplicateHandle(ExternalSemaphoreHandle handle) {
|
||||||
|
zx_handle_t out_handle = ZX_HANDLE_INVALID;
|
||||||
|
zx_status_t status = zx_handle_duplicate(handle, ZX_RIGHT_SAME_RIGHTS, &out_handle);
|
||||||
|
ASSERT(status == ZX_OK);
|
||||||
|
return out_handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Service::CloseHandle(ExternalSemaphoreHandle handle) {
|
||||||
|
zx_status_t status = zx_handle_close(handle);
|
||||||
|
ASSERT(status == ZX_OK);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace dawn::native::vulkan::external_semaphore
|
} // namespace dawn::native::vulkan::external_semaphore
|
||||||
|
|
|
@ -110,7 +110,7 @@ class VulkanImageWrappingTestBase : public DawnTest {
|
||||||
// assertion failure
|
// assertion failure
|
||||||
void IgnoreSignalSemaphore(wgpu::Texture wrappedTexture) {
|
void IgnoreSignalSemaphore(wgpu::Texture wrappedTexture) {
|
||||||
ExternalImageExportInfoVkForTesting exportInfo;
|
ExternalImageExportInfoVkForTesting exportInfo;
|
||||||
bool result = mBackend->ExportImage(wrappedTexture, VK_IMAGE_LAYOUT_GENERAL, &exportInfo);
|
bool result = mBackend->ExportImage(wrappedTexture, VK_IMAGE_LAYOUT_UNDEFINED, &exportInfo);
|
||||||
ASSERT(result);
|
ASSERT(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -202,7 +202,7 @@ TEST_P(VulkanImageWrappingValidationTests, DoubleSignalSemaphoreExport) {
|
||||||
|
|
||||||
ExternalImageExportInfoVkForTesting exportInfo;
|
ExternalImageExportInfoVkForTesting exportInfo;
|
||||||
ASSERT_DEVICE_ERROR(bool success =
|
ASSERT_DEVICE_ERROR(bool success =
|
||||||
mBackend->ExportImage(texture, VK_IMAGE_LAYOUT_GENERAL, &exportInfo));
|
mBackend->ExportImage(texture, VK_IMAGE_LAYOUT_UNDEFINED, &exportInfo));
|
||||||
ASSERT_FALSE(success);
|
ASSERT_FALSE(success);
|
||||||
ASSERT_EQ(exportInfo.semaphores.size(), 0u);
|
ASSERT_EQ(exportInfo.semaphores.size(), 0u);
|
||||||
}
|
}
|
||||||
|
@ -214,7 +214,7 @@ TEST_P(VulkanImageWrappingValidationTests, NormalTextureSignalSemaphoreExport) {
|
||||||
|
|
||||||
ExternalImageExportInfoVkForTesting exportInfo;
|
ExternalImageExportInfoVkForTesting exportInfo;
|
||||||
ASSERT_DEVICE_ERROR(bool success =
|
ASSERT_DEVICE_ERROR(bool success =
|
||||||
mBackend->ExportImage(texture, VK_IMAGE_LAYOUT_GENERAL, &exportInfo));
|
mBackend->ExportImage(texture, VK_IMAGE_LAYOUT_UNDEFINED, &exportInfo));
|
||||||
ASSERT_FALSE(success);
|
ASSERT_FALSE(success);
|
||||||
ASSERT_EQ(exportInfo.semaphores.size(), 0u);
|
ASSERT_EQ(exportInfo.semaphores.size(), 0u);
|
||||||
}
|
}
|
||||||
|
@ -227,7 +227,7 @@ TEST_P(VulkanImageWrappingValidationTests, DestroyedTextureSignalSemaphoreExport
|
||||||
|
|
||||||
ExternalImageExportInfoVkForTesting exportInfo;
|
ExternalImageExportInfoVkForTesting exportInfo;
|
||||||
ASSERT_DEVICE_ERROR(bool success =
|
ASSERT_DEVICE_ERROR(bool success =
|
||||||
mBackend->ExportImage(texture, VK_IMAGE_LAYOUT_GENERAL, &exportInfo));
|
mBackend->ExportImage(texture, VK_IMAGE_LAYOUT_UNDEFINED, &exportInfo));
|
||||||
ASSERT_FALSE(success);
|
ASSERT_FALSE(success);
|
||||||
ASSERT_EQ(exportInfo.semaphores.size(), 0u);
|
ASSERT_EQ(exportInfo.semaphores.size(), 0u);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue