Revert "Remove VK_DEFINE_NON_DISPATCHABLE_HANDLE magic, use explicit VkHandle wrapper"
This reverts commit 4e17d5c2483b63d4863162d692a1a961d1dcb958.
Reason for revert: broken on chromeos
Original change's description:
> Remove VK_DEFINE_NON_DISPATCHABLE_HANDLE magic, use explicit VkHandle wrapper
>
> Overriding VK_DEFINE_NON_DISPATCHABLE_HANDLE changes the function
> signatures of Vulkan functions, changing their ABI and making us
> incompatible with real drivers. This removes that magic, and replaces it
> with an explicit wrapper, VkHandle, which has much of the same
> functionality as the original VkNonDispatchableHandle.
>
> It adds definitions for dawn_native::vulkan::VkBuffer et al, which
> shadow the native ::VkBuffer et al. This retains type safety throughout
> the Vulkan backend without changing every single usage.
>
> Notably, the following things had to change:
> - An explicit conversion from VkBuffer* to ::VkBuffer* is needed for
> arrays. This is implemented as a reinterpret_cast, which is still
> safe as the new VkHandle still has the same memory layout properties
> as VkNonDispatchableHandle did.
> - When pointing to a VkHandle as an output pointer, it's now necessary
> to explicitly get the native ::VkBuffer (via operator*) and point to it.
>
> Bug: chromium:1046362
> Change-Id: I9c5691b6e295aca1b46d4e3d0203956e4d570285
> Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/15580
> Reviewed-by: Austin Eng <enga@chromium.org>
> Reviewed-by: Kai Ninomiya <kainino@chromium.org>
> Commit-Queue: Kai Ninomiya <kainino@chromium.org>
TBR=cwallez@chromium.org,kainino@chromium.org,enga@chromium.org
Change-Id: I500df2e34fd0f245ad04c517ff028ddd7bb5a2bf
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Bug: chromium:1046362
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/15620
Reviewed-by: Kai Ninomiya <kainino@chromium.org>
Commit-Queue: Kai Ninomiya <kainino@chromium.org>
diff --git a/src/common/vulkan_platform.h b/src/common/vulkan_platform.h
index 913f011..35742a7 100644
--- a/src/common/vulkan_platform.h
+++ b/src/common/vulkan_platform.h
@@ -18,9 +18,6 @@
#if !defined(DAWN_ENABLE_BACKEND_VULKAN)
# error "vulkan_platform.h included without the Vulkan backend enabled"
#endif
-#if defined(VULKAN_CORE_H_)
-# error "vulkan.h included before vulkan_platform.h"
-#endif
#include "common/Platform.h"
@@ -36,9 +33,10 @@
// (like vulkan.h on 64 bit) but makes sure the types are different on 32 bit architectures.
#if defined(DAWN_PLATFORM_64_BIT)
-# define DAWN_DEFINE_NATIVE_NON_DISPATCHABLE_HANDLE(object) using object = struct object##_T*;
+# define DAWN_DEFINE_NATIVE_NON_DISPATCHABLE_HANDLE(object) \
+ using object##Native = struct object##_T*;
#elif defined(DAWN_PLATFORM_32_BIT)
-# define DAWN_DEFINE_NATIVE_NON_DISPATCHABLE_HANDLE(object) using object = uint64_t;
+# define DAWN_DEFINE_NATIVE_NON_DISPATCHABLE_HANDLE(object) using object##Native = uint64_t;
#else
# error "Unsupported platform"
#endif
@@ -55,106 +53,105 @@
// One way to get the alignment inside structures of a type is to look at the alignment of it
// wrapped in a structure. Hence VkSameHandleNativeWrappe
-namespace dawn_native { namespace vulkan {
+template <typename T>
+struct WrapperStruct {
+ T member;
+};
- namespace detail {
- template <typename T>
- struct WrapperStruct {
- T member;
- };
+template <typename T>
+static constexpr size_t AlignOfInStruct = alignof(WrapperStruct<T>);
- template <typename T>
- static constexpr size_t AlignOfInStruct = alignof(WrapperStruct<T>);
+static constexpr size_t kNativeVkHandleAlignment = AlignOfInStruct<VkSomeHandleNative>;
+static constexpr size_t kUint64Alignment = AlignOfInStruct<VkSomeHandleNative>;
- static constexpr size_t kNativeVkHandleAlignment = AlignOfInStruct<VkSomeHandle>;
- static constexpr size_t kUint64Alignment = AlignOfInStruct<uint64_t>;
-
- // Simple handle types that supports "nullptr_t" as a 0 value.
- template <typename Tag, typename HandleType>
- class alignas(detail::kNativeVkHandleAlignment) VkHandle {
- public:
- // Default constructor and assigning of VK_NULL_HANDLE
- VkHandle() = default;
- VkHandle(std::nullptr_t) {
- }
-
- // Use default copy constructor/assignment
- VkHandle(const VkHandle<Tag, HandleType>& other) = default;
- VkHandle& operator=(const VkHandle<Tag, HandleType>&) = default;
-
- // Comparisons between handles
- bool operator==(VkHandle<Tag, HandleType> other) const {
- return mHandle == other.mHandle;
- }
- bool operator!=(VkHandle<Tag, HandleType> other) const {
- return mHandle != other.mHandle;
- }
-
- // Comparisons between handles and VK_NULL_HANDLE
- bool operator==(std::nullptr_t) const {
- return mHandle == 0;
- }
- bool operator!=(std::nullptr_t) const {
- return mHandle != 0;
- }
-
- // Implicit conversion to real Vulkan types.
- operator HandleType() const {
- return GetHandle();
- }
-
- HandleType GetHandle() const {
- return mHandle;
- }
-
- HandleType& operator*() {
- return mHandle;
- }
-
- static VkHandle<Tag, HandleType> CreateFromHandle(HandleType handle) {
- return VkHandle{handle};
- }
-
- private:
- explicit VkHandle(HandleType handle) : mHandle(handle) {
- }
-
- HandleType mHandle = 0;
- };
- } // namespace detail
-
- static constexpr std::nullptr_t VK_NULL_HANDLE = nullptr;
-
- template <typename Tag, typename HandleType>
- HandleType* AsVkArray(detail::VkHandle<Tag, HandleType>* handle) {
- return reinterpret_cast<HandleType*>(handle);
+// Simple handle types that supports "nullptr_t" as a 0 value.
+template <typename Tag, typename HandleType>
+class alignas(kNativeVkHandleAlignment) VkNonDispatchableHandle {
+ public:
+ // Default constructor and assigning of VK_NULL_HANDLE
+ VkNonDispatchableHandle() = default;
+ VkNonDispatchableHandle(std::nullptr_t) : mHandle(0) {
}
-}} // namespace dawn_native::vulkan
+ // Use default copy constructor/assignment
+ VkNonDispatchableHandle(const VkNonDispatchableHandle<Tag, HandleType>& other) = default;
+ VkNonDispatchableHandle& operator=(const VkNonDispatchableHandle<Tag, HandleType>&) = default;
-#define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) \
- DAWN_DEFINE_NATIVE_NON_DISPATCHABLE_HANDLE(object) \
- namespace dawn_native { namespace vulkan { \
- using object = detail::VkHandle<struct VkTag##object, ::object>; \
- static_assert(sizeof(object) == sizeof(uint64_t), ""); \
- static_assert(alignof(object) == detail::kUint64Alignment, ""); \
- static_assert(sizeof(object) == sizeof(::object), ""); \
- static_assert(alignof(object) == detail::kNativeVkHandleAlignment, ""); \
- } \
- } // namespace dawn_native::vulkan
+ // Comparisons between handles
+ bool operator==(VkNonDispatchableHandle<Tag, HandleType> other) const {
+ return mHandle == other.mHandle;
+ }
+ bool operator!=(VkNonDispatchableHandle<Tag, HandleType> other) const {
+ return mHandle != other.mHandle;
+ }
-#include <vulkan/vulkan.h>
+ // Comparisons between handles and VK_NULL_HANDLE
+ bool operator==(std::nullptr_t) const {
+ return mHandle == 0;
+ }
+ bool operator!=(std::nullptr_t) const {
+ return mHandle != 0;
+ }
-// Redefine VK_NULL_HANDLE for better type safety where possible.
-#undef VK_NULL_HANDLE
+ // The regular Vulkan handle type depends on the pointer width but is always 64 bits wide.
+ // - On 64bit it is an opaque pointer type, probably to help with type safety
+ // - On 32bit it is a uint64_t because pointers aren't wide enough (and non dispatchable
+ // handles can be optimized to not be pointer but contain GPU virtual addresses or the
+ // data in a packed form).
+ // Because of this we need two types of conversions from our handle type: to uint64_t and to
+ // the "native" Vulkan type that may not be an uint64_t
+
+ static VkNonDispatchableHandle<Tag, HandleType> CreateFromU64(uint64_t handle) {
+ return {handle};
+ }
+
+ uint64_t GetU64() const {
+ return mHandle;
+ }
+
#if defined(DAWN_PLATFORM_64_BIT)
-static constexpr nullptr_t VK_NULL_HANDLE = nullptr;
+ static VkNonDispatchableHandle<Tag, HandleType> CreateFromHandle(HandleType handle) {
+ return CreateFromU64(static_cast<uint64_t>(reinterpret_cast<intptr_t>(handle)));
+ }
+
+ HandleType GetHandle() const {
+ return mHandle;
+ }
#elif defined(DAWN_PLATFORM_32_BIT)
-static constexpr uint64_t VK_NULL_HANDLE = 0;
+ static VkNonDispatchableHandle<Tag, HandleType> CreateFromHandle(HandleType handle) {
+ return {handle};
+ }
+
+ HandleType GetHandle() const {
+ return mHandle;
+ }
#else
# error "Unsupported platform"
#endif
+ private:
+ VkNonDispatchableHandle(uint64_t handle) : mHandle(handle) {
+ }
+
+ uint64_t mHandle = 0;
+};
+
+#define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) \
+ struct VkTag##object; \
+ DAWN_DEFINE_NATIVE_NON_DISPATCHABLE_HANDLE(object) \
+ using object = VkNonDispatchableHandle<VkTag##object, object##Native>; \
+ static_assert(sizeof(object) == sizeof(uint64_t), ""); \
+ static_assert(alignof(object) == kUint64Alignment, ""); \
+ static_assert(sizeof(object) == sizeof(object##Native), ""); \
+ static_assert(alignof(object) == kNativeVkHandleAlignment, "");
+
+# include <vulkan/vulkan.h>
+
+ // VK_NULL_HANDLE is defined to 0 but we don't want our handle type to compare to arbitrary
+ // integers. Redefine VK_NULL_HANDLE to nullptr that has its own type.
+# undef VK_NULL_HANDLE
+# define VK_NULL_HANDLE nullptr
+
// Remove windows.h macros after vulkan_platform's include of windows.h
#if defined(DAWN_PLATFORM_WINDOWS)
# include "common/windows_with_undefs.h"
diff --git a/src/dawn_native/vulkan/BackendVk.cpp b/src/dawn_native/vulkan/BackendVk.cpp
index d2745cb..d2aaa76 100644
--- a/src/dawn_native/vulkan/BackendVk.cpp
+++ b/src/dawn_native/vulkan/BackendVk.cpp
@@ -272,7 +272,7 @@
createInfo.pUserData = this;
return CheckVkSuccess(mFunctions.CreateDebugReportCallbackEXT(
- mInstance, &createInfo, nullptr, &*mDebugReportCallback),
+ mInstance, &createInfo, nullptr, &mDebugReportCallback),
"vkCreateDebugReportcallback");
}
diff --git a/src/dawn_native/vulkan/BindGroupLayoutVk.cpp b/src/dawn_native/vulkan/BindGroupLayoutVk.cpp
index 90c8366..89ce53d 100644
--- a/src/dawn_native/vulkan/BindGroupLayoutVk.cpp
+++ b/src/dawn_native/vulkan/BindGroupLayoutVk.cpp
@@ -105,7 +105,7 @@
Device* device = ToBackend(GetDevice());
DAWN_TRY(CheckVkSuccess(device->fn.CreateDescriptorSetLayout(
- device->GetVkDevice(), &createInfo, nullptr, &*mHandle),
+ device->GetVkDevice(), &createInfo, nullptr, &mHandle),
"CreateDescriptorSetLayout"));
// Compute the size of descriptor pools used for this layout.
@@ -171,7 +171,7 @@
VkDescriptorPool descriptorPool;
DAWN_TRY(CheckVkSuccess(device->fn.CreateDescriptorPool(device->GetVkDevice(), &createInfo,
- nullptr, &*descriptorPool),
+ nullptr, &descriptorPool),
"CreateDescriptorPool"));
// Allocate our single set.
@@ -180,13 +180,12 @@
allocateInfo.pNext = nullptr;
allocateInfo.descriptorPool = descriptorPool;
allocateInfo.descriptorSetCount = 1;
- allocateInfo.pSetLayouts = &*mHandle;
+ allocateInfo.pSetLayouts = &mHandle;
VkDescriptorSet descriptorSet;
- MaybeError result =
- CheckVkSuccess(device->fn.AllocateDescriptorSets(device->GetVkDevice(), &allocateInfo,
- &*descriptorSet),
- "AllocateDescriptorSets");
+ MaybeError result = CheckVkSuccess(
+ device->fn.AllocateDescriptorSets(device->GetVkDevice(), &allocateInfo, &descriptorSet),
+ "AllocateDescriptorSets");
if (result.IsError()) {
// On an error we can destroy the pool immediately because no command references it.
diff --git a/src/dawn_native/vulkan/BindGroupVk.h b/src/dawn_native/vulkan/BindGroupVk.h
index 9fa857b..4dd4c21 100644
--- a/src/dawn_native/vulkan/BindGroupVk.h
+++ b/src/dawn_native/vulkan/BindGroupVk.h
@@ -17,7 +17,6 @@
#include "dawn_native/BindGroup.h"
-#include "common/vulkan_platform.h"
#include "dawn_native/vulkan/BindGroupLayoutVk.h"
namespace dawn_native { namespace vulkan {
diff --git a/src/dawn_native/vulkan/BufferVk.cpp b/src/dawn_native/vulkan/BufferVk.cpp
index 4a1af60..8f8b3aa 100644
--- a/src/dawn_native/vulkan/BufferVk.cpp
+++ b/src/dawn_native/vulkan/BufferVk.cpp
@@ -147,7 +147,7 @@
Device* device = ToBackend(GetDevice());
DAWN_TRY(CheckVkSuccess(
- device->fn.CreateBuffer(device->GetVkDevice(), &createInfo, nullptr, &*mHandle),
+ device->fn.CreateBuffer(device->GetVkDevice(), &createInfo, nullptr, &mHandle),
"vkCreateBuffer"));
VkMemoryRequirements requirements;
diff --git a/src/dawn_native/vulkan/CommandBufferVk.cpp b/src/dawn_native/vulkan/CommandBufferVk.cpp
index 7e12806..b845e3b 100644
--- a/src/dawn_native/vulkan/CommandBufferVk.cpp
+++ b/src/dawn_native/vulkan/CommandBufferVk.cpp
@@ -106,7 +106,7 @@
? dynamicOffsets[dirtyIndex].data()
: nullptr;
device->fn.CmdBindDescriptorSets(commands, bindPoint, pipelineLayout, dirtyIndex, 1,
- &*set, dynamicOffsetCounts[dirtyIndex],
+ &set, dynamicOffsetCounts[dirtyIndex],
dynamicOffset);
}
}
@@ -255,14 +255,14 @@
createInfo.flags = 0;
createInfo.renderPass = renderPassVK;
createInfo.attachmentCount = attachmentCount;
- createInfo.pAttachments = AsVkArray(attachments.data());
+ createInfo.pAttachments = attachments.data();
createInfo.width = renderPass->width;
createInfo.height = renderPass->height;
createInfo.layers = 1;
DAWN_TRY(
CheckVkSuccess(device->fn.CreateFramebuffer(device->GetVkDevice(), &createInfo,
- nullptr, &*framebuffer),
+ nullptr, &framebuffer),
"CreateFramebuffer"));
// We don't reuse VkFramebuffers so mark the framebuffer for deletion as soon as the
@@ -827,7 +827,7 @@
VkBuffer buffer = ToBackend(cmd->buffer)->GetHandle();
VkDeviceSize offset = static_cast<VkDeviceSize>(cmd->offset);
- device->fn.CmdBindVertexBuffers(commands, cmd->slot, 1, &*buffer, &offset);
+ device->fn.CmdBindVertexBuffers(commands, cmd->slot, 1, &buffer, &offset);
} break;
default:
diff --git a/src/dawn_native/vulkan/ComputePipelineVk.cpp b/src/dawn_native/vulkan/ComputePipelineVk.cpp
index 16dd8e7..2f37620 100644
--- a/src/dawn_native/vulkan/ComputePipelineVk.cpp
+++ b/src/dawn_native/vulkan/ComputePipelineVk.cpp
@@ -38,7 +38,7 @@
createInfo.pNext = nullptr;
createInfo.flags = 0;
createInfo.layout = ToBackend(descriptor->layout)->GetHandle();
- createInfo.basePipelineHandle = ::VK_NULL_HANDLE;
+ createInfo.basePipelineHandle = VK_NULL_HANDLE;
createInfo.basePipelineIndex = -1;
createInfo.stage.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
@@ -51,8 +51,8 @@
Device* device = ToBackend(GetDevice());
return CheckVkSuccess(
- device->fn.CreateComputePipelines(device->GetVkDevice(), ::VK_NULL_HANDLE, 1,
- &createInfo, nullptr, &*mHandle),
+ device->fn.CreateComputePipelines(device->GetVkDevice(), VK_NULL_HANDLE, 1, &createInfo,
+ nullptr, &mHandle),
"CreateComputePipeline");
}
diff --git a/src/dawn_native/vulkan/DeviceVk.cpp b/src/dawn_native/vulkan/DeviceVk.cpp
index e78718e..bc4179a 100644
--- a/src/dawn_native/vulkan/DeviceVk.cpp
+++ b/src/dawn_native/vulkan/DeviceVk.cpp
@@ -272,13 +272,13 @@
submitInfo.pNext = nullptr;
submitInfo.waitSemaphoreCount =
static_cast<uint32_t>(mRecordingContext.waitSemaphores.size());
- submitInfo.pWaitSemaphores = AsVkArray(mRecordingContext.waitSemaphores.data());
+ submitInfo.pWaitSemaphores = mRecordingContext.waitSemaphores.data();
submitInfo.pWaitDstStageMask = dstStageMasks.data();
submitInfo.commandBufferCount = 1;
submitInfo.pCommandBuffers = &mRecordingContext.commandBuffer;
submitInfo.signalSemaphoreCount =
static_cast<uint32_t>(mRecordingContext.signalSemaphores.size());
- submitInfo.pSignalSemaphores = AsVkArray(mRecordingContext.signalSemaphores.data());
+ submitInfo.pSignalSemaphores = mRecordingContext.signalSemaphores.data();
VkFence fence = VK_NULL_HANDLE;
DAWN_TRY_ASSIGN(fence, GetUnusedFence());
@@ -474,7 +474,7 @@
ResultOrError<VkFence> Device::GetUnusedFence() {
if (!mUnusedFences.empty()) {
VkFence fence = mUnusedFences.back();
- DAWN_TRY(CheckVkSuccess(fn.ResetFences(mVkDevice, 1, &*fence), "vkResetFences"));
+ DAWN_TRY(CheckVkSuccess(fn.ResetFences(mVkDevice, 1, &fence), "vkResetFences"));
mUnusedFences.pop_back();
return fence;
@@ -486,7 +486,7 @@
createInfo.flags = 0;
VkFence fence = VK_NULL_HANDLE;
- DAWN_TRY(CheckVkSuccess(fn.CreateFence(mVkDevice, &createInfo, nullptr, &*fence),
+ DAWN_TRY(CheckVkSuccess(fn.CreateFence(mVkDevice, &createInfo, nullptr, &fence),
"vkCreateFence"));
return fence;
@@ -539,7 +539,7 @@
createInfo.queueFamilyIndex = mQueueFamily;
DAWN_TRY(CheckVkSuccess(fn.CreateCommandPool(mVkDevice, &createInfo, nullptr,
- &*mRecordingContext.commandPool),
+ &mRecordingContext.commandPool),
"vkCreateCommandPool"));
VkCommandBufferAllocateInfo allocateInfo;
@@ -756,7 +756,7 @@
VkResult result = VkResult::WrapUnsafe(VK_TIMEOUT);
do {
result = VkResult::WrapUnsafe(
- INJECT_ERROR_OR_RUN(fn.WaitForFences(mVkDevice, 1, &*fence, true, UINT64_MAX),
+ INJECT_ERROR_OR_RUN(fn.WaitForFences(mVkDevice, 1, &fence, true, UINT64_MAX),
VK_ERROR_DEVICE_LOST));
} while (result == VK_TIMEOUT);
diff --git a/src/dawn_native/vulkan/NativeSwapChainImplVk.cpp b/src/dawn_native/vulkan/NativeSwapChainImplVk.cpp
index ada090f..a330d71 100644
--- a/src/dawn_native/vulkan/NativeSwapChainImplVk.cpp
+++ b/src/dawn_native/vulkan/NativeSwapChainImplVk.cpp
@@ -136,7 +136,7 @@
createInfo.oldSwapchain = oldSwapchain;
if (mDevice->fn.CreateSwapchainKHR(mDevice->GetVkDevice(), &createInfo, nullptr,
- &*mSwapChain) != VK_SUCCESS) {
+ &mSwapChain) != VK_SUCCESS) {
ASSERT(false);
}
@@ -151,7 +151,7 @@
ASSERT(count >= mConfig.minImageCount);
mSwapChainImages.resize(count);
if (mDevice->fn.GetSwapchainImagesKHR(mDevice->GetVkDevice(), mSwapChain, &count,
- AsVkArray(mSwapChainImages.data())) != VK_SUCCESS) {
+ mSwapChainImages.data()) != VK_SUCCESS) {
ASSERT(false);
}
@@ -168,7 +168,7 @@
barrier.newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
barrier.srcQueueFamilyIndex = 0;
barrier.dstQueueFamilyIndex = 0;
- barrier.image = *image;
+ barrier.image = image;
barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
barrier.subresourceRange.baseMipLevel = 0;
barrier.subresourceRange.levelCount = 1;
@@ -197,22 +197,18 @@
createInfo.pNext = nullptr;
createInfo.flags = 0;
if (mDevice->fn.CreateSemaphore(mDevice->GetVkDevice(), &createInfo, nullptr,
- &*semaphore) != VK_SUCCESS) {
+ &semaphore) != VK_SUCCESS) {
ASSERT(false);
}
}
if (mDevice->fn.AcquireNextImageKHR(mDevice->GetVkDevice(), mSwapChain,
std::numeric_limits<uint64_t>::max(), semaphore,
- VkFence{}, &mLastImageIndex) != VK_SUCCESS) {
+ VK_NULL_HANDLE, &mLastImageIndex) != VK_SUCCESS) {
ASSERT(false);
}
- nextTexture->texture.u64 =
-#if defined(DAWN_PLATFORM_64_BIT)
- reinterpret_cast<uint64_t>
-#endif
- (*mSwapChainImages[mLastImageIndex]);
+ nextTexture->texture.u64 = mSwapChainImages[mLastImageIndex].GetU64();
mDevice->GetPendingRecordingContext()->waitSemaphores.push_back(semaphore);
return DAWN_SWAP_CHAIN_NO_ERROR;
@@ -231,7 +227,7 @@
presentInfo.waitSemaphoreCount = 0;
presentInfo.pWaitSemaphores = nullptr;
presentInfo.swapchainCount = 1;
- presentInfo.pSwapchains = &*mSwapChain;
+ presentInfo.pSwapchains = &mSwapChain;
presentInfo.pImageIndices = &mLastImageIndex;
presentInfo.pResults = nullptr;
diff --git a/src/dawn_native/vulkan/PipelineLayoutVk.cpp b/src/dawn_native/vulkan/PipelineLayoutVk.cpp
index 847ba60..dd123af 100644
--- a/src/dawn_native/vulkan/PipelineLayoutVk.cpp
+++ b/src/dawn_native/vulkan/PipelineLayoutVk.cpp
@@ -48,13 +48,13 @@
createInfo.pNext = nullptr;
createInfo.flags = 0;
createInfo.setLayoutCount = numSetLayouts;
- createInfo.pSetLayouts = AsVkArray(setLayouts.data());
+ createInfo.pSetLayouts = setLayouts.data();
createInfo.pushConstantRangeCount = 0;
createInfo.pPushConstantRanges = nullptr;
Device* device = ToBackend(GetDevice());
return CheckVkSuccess(
- device->fn.CreatePipelineLayout(device->GetVkDevice(), &createInfo, nullptr, &*mHandle),
+ device->fn.CreatePipelineLayout(device->GetVkDevice(), &createInfo, nullptr, &mHandle),
"CreatePipelineLayout");
}
diff --git a/src/dawn_native/vulkan/RenderPassCache.cpp b/src/dawn_native/vulkan/RenderPassCache.cpp
index 47330f1..8742458 100644
--- a/src/dawn_native/vulkan/RenderPassCache.cpp
+++ b/src/dawn_native/vulkan/RenderPassCache.cpp
@@ -191,9 +191,9 @@
// Create the render pass from the zillion parameters
VkRenderPass renderPass;
- DAWN_TRY(CheckVkSuccess(mDevice->fn.CreateRenderPass(mDevice->GetVkDevice(), &createInfo,
- nullptr, &*renderPass),
- "CreateRenderPass"));
+ DAWN_TRY(CheckVkSuccess(
+ mDevice->fn.CreateRenderPass(mDevice->GetVkDevice(), &createInfo, nullptr, &renderPass),
+ "CreateRenderPass"));
return renderPass;
}
diff --git a/src/dawn_native/vulkan/RenderPipelineVk.cpp b/src/dawn_native/vulkan/RenderPipelineVk.cpp
index b0ba4fd..4b770a5 100644
--- a/src/dawn_native/vulkan/RenderPipelineVk.cpp
+++ b/src/dawn_native/vulkan/RenderPipelineVk.cpp
@@ -495,12 +495,12 @@
createInfo.layout = ToBackend(GetLayout())->GetHandle();
createInfo.renderPass = renderPass;
createInfo.subpass = 0;
- createInfo.basePipelineHandle = VkPipeline{};
+ createInfo.basePipelineHandle = VK_NULL_HANDLE;
createInfo.basePipelineIndex = -1;
return CheckVkSuccess(
- device->fn.CreateGraphicsPipelines(device->GetVkDevice(), VkPipelineCache{}, 1,
- &createInfo, nullptr, &*mHandle),
+ device->fn.CreateGraphicsPipelines(device->GetVkDevice(), VK_NULL_HANDLE, 1,
+ &createInfo, nullptr, &mHandle),
"CreateGraphicsPipeline");
}
diff --git a/src/dawn_native/vulkan/ResourceMemoryAllocatorVk.cpp b/src/dawn_native/vulkan/ResourceMemoryAllocatorVk.cpp
index 3d8ded5..25fa5ee 100644
--- a/src/dawn_native/vulkan/ResourceMemoryAllocatorVk.cpp
+++ b/src/dawn_native/vulkan/ResourceMemoryAllocatorVk.cpp
@@ -73,7 +73,7 @@
// First check OOM that we want to surface to the application.
DAWN_TRY(CheckVkOOMThenSuccess(
mDevice->fn.AllocateMemory(mDevice->GetVkDevice(), &allocateInfo, nullptr,
- &*allocatedMemory),
+ &allocatedMemory),
"vkAllocateMemory"));
ASSERT(allocatedMemory != VK_NULL_HANDLE);
diff --git a/src/dawn_native/vulkan/SamplerVk.cpp b/src/dawn_native/vulkan/SamplerVk.cpp
index 67d70f8..05baf71 100644
--- a/src/dawn_native/vulkan/SamplerVk.cpp
+++ b/src/dawn_native/vulkan/SamplerVk.cpp
@@ -87,7 +87,7 @@
Device* device = ToBackend(GetDevice());
return CheckVkSuccess(
- device->fn.CreateSampler(device->GetVkDevice(), &createInfo, nullptr, &*mHandle),
+ device->fn.CreateSampler(device->GetVkDevice(), &createInfo, nullptr, &mHandle),
"CreateSampler");
}
diff --git a/src/dawn_native/vulkan/ShaderModuleVk.cpp b/src/dawn_native/vulkan/ShaderModuleVk.cpp
index a9e717c..140abba 100644
--- a/src/dawn_native/vulkan/ShaderModuleVk.cpp
+++ b/src/dawn_native/vulkan/ShaderModuleVk.cpp
@@ -74,7 +74,7 @@
Device* device = ToBackend(GetDevice());
return CheckVkSuccess(
- device->fn.CreateShaderModule(device->GetVkDevice(), &createInfo, nullptr, &*mHandle),
+ device->fn.CreateShaderModule(device->GetVkDevice(), &createInfo, nullptr, &mHandle),
"CreateShaderModule");
}
diff --git a/src/dawn_native/vulkan/StagingBufferVk.cpp b/src/dawn_native/vulkan/StagingBufferVk.cpp
index 4fa3b7b..4262318 100644
--- a/src/dawn_native/vulkan/StagingBufferVk.cpp
+++ b/src/dawn_native/vulkan/StagingBufferVk.cpp
@@ -36,7 +36,7 @@
createInfo.pQueueFamilyIndices = 0;
DAWN_TRY(CheckVkSuccess(
- mDevice->fn.CreateBuffer(mDevice->GetVkDevice(), &createInfo, nullptr, &*mBuffer),
+ mDevice->fn.CreateBuffer(mDevice->GetVkDevice(), &createInfo, nullptr, &mBuffer),
"vkCreateBuffer"));
VkMemoryRequirements requirements;
diff --git a/src/dawn_native/vulkan/SwapChainVk.cpp b/src/dawn_native/vulkan/SwapChainVk.cpp
index e64f5e5..876af8e 100644
--- a/src/dawn_native/vulkan/SwapChainVk.cpp
+++ b/src/dawn_native/vulkan/SwapChainVk.cpp
@@ -47,8 +47,7 @@
return nullptr;
}
- VkImage nativeTexture =
- VkImage::CreateFromHandle(reinterpret_cast<::VkImage>(next.texture.u64));
+ VkImage nativeTexture = VkImage::CreateFromU64(next.texture.u64);
return new Texture(ToBackend(GetDevice()), descriptor, nativeTexture);
}
diff --git a/src/dawn_native/vulkan/TextureVk.cpp b/src/dawn_native/vulkan/TextureVk.cpp
index 6f2fc9e..72a7653 100644
--- a/src/dawn_native/vulkan/TextureVk.cpp
+++ b/src/dawn_native/vulkan/TextureVk.cpp
@@ -460,7 +460,7 @@
createInfo.usage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT;
DAWN_TRY(CheckVkSuccess(
- device->fn.CreateImage(device->GetVkDevice(), &createInfo, nullptr, &*mHandle),
+ device->fn.CreateImage(device->GetVkDevice(), &createInfo, nullptr, &mHandle),
"CreateImage"));
// Create the image memory and associate it with the container
@@ -806,7 +806,7 @@
createInfo.subresourceRange.layerCount = descriptor->arrayLayerCount;
return CheckVkSuccess(
- device->fn.CreateImageView(device->GetVkDevice(), &createInfo, nullptr, &*mHandle),
+ device->fn.CreateImageView(device->GetVkDevice(), &createInfo, nullptr, &mHandle),
"CreateImageView");
}
diff --git a/src/dawn_native/vulkan/VulkanBackend.cpp b/src/dawn_native/vulkan/VulkanBackend.cpp
index 2a9361f..ad99a27 100644
--- a/src/dawn_native/vulkan/VulkanBackend.cpp
+++ b/src/dawn_native/vulkan/VulkanBackend.cpp
@@ -42,7 +42,7 @@
// Explicitly export this function because it uses the "native" type for surfaces while the
// header as seen in this file uses the wrapped type.
DAWN_NATIVE_EXPORT DawnSwapChainImplementation
- CreateNativeSwapChainImpl(WGPUDevice device, ::VkSurfaceKHR surfaceNative) {
+ CreateNativeSwapChainImpl(WGPUDevice device, VkSurfaceKHRNative surfaceNative) {
Device* backendDevice = reinterpret_cast<Device*>(device);
VkSurfaceKHR surface = VkSurfaceKHR::CreateFromHandle(surfaceNative);
diff --git a/src/dawn_native/vulkan/external_memory/MemoryServiceOpaqueFD.cpp b/src/dawn_native/vulkan/external_memory/MemoryServiceOpaqueFD.cpp
index a8bc181..a6bb2fa 100644
--- a/src/dawn_native/vulkan/external_memory/MemoryServiceOpaqueFD.cpp
+++ b/src/dawn_native/vulkan/external_memory/MemoryServiceOpaqueFD.cpp
@@ -130,7 +130,7 @@
VkDeviceMemory allocatedMemory = VK_NULL_HANDLE;
DAWN_TRY(CheckVkSuccess(mDevice->fn.AllocateMemory(mDevice->GetVkDevice(), &allocateInfo,
- nullptr, &*allocatedMemory),
+ nullptr, &allocatedMemory),
"vkAllocateMemory"));
return allocatedMemory;
}
@@ -146,7 +146,7 @@
VkImage image;
DAWN_TRY(CheckVkSuccess(
- mDevice->fn.CreateImage(mDevice->GetVkDevice(), &createInfo, nullptr, &*image),
+ mDevice->fn.CreateImage(mDevice->GetVkDevice(), &createInfo, nullptr, &image),
"CreateImage"));
return image;
}
diff --git a/src/dawn_native/vulkan/external_semaphore/SemaphoreServiceOpaqueFD.cpp b/src/dawn_native/vulkan/external_semaphore/SemaphoreServiceOpaqueFD.cpp
index 3e1d3f0..ea7bf47 100644
--- a/src/dawn_native/vulkan/external_semaphore/SemaphoreServiceOpaqueFD.cpp
+++ b/src/dawn_native/vulkan/external_semaphore/SemaphoreServiceOpaqueFD.cpp
@@ -72,7 +72,7 @@
info.flags = 0;
DAWN_TRY(CheckVkSuccess(
- mDevice->fn.CreateSemaphore(mDevice->GetVkDevice(), &info, nullptr, &*semaphore),
+ mDevice->fn.CreateSemaphore(mDevice->GetVkDevice(), &info, nullptr, &semaphore),
"vkCreateSemaphore"));
VkImportSemaphoreFdInfoKHR importSemaphoreFdInfo;
@@ -109,7 +109,7 @@
VkSemaphore signalSemaphore;
DAWN_TRY(
CheckVkSuccess(mDevice->fn.CreateSemaphore(mDevice->GetVkDevice(), &semaphoreCreateInfo,
- nullptr, &*signalSemaphore),
+ nullptr, &signalSemaphore),
"vkCreateSemaphore"));
return signalSemaphore;
}
diff --git a/src/include/dawn_native/VulkanBackend.h b/src/include/dawn_native/VulkanBackend.h
index 005a655..30dbb05 100644
--- a/src/include/dawn_native/VulkanBackend.h
+++ b/src/include/dawn_native/VulkanBackend.h
@@ -47,8 +47,8 @@
DAWN_NATIVE_EXPORT PFN_vkVoidFunction GetInstanceProcAddr(WGPUDevice device, const char* pName);
- DAWN_NATIVE_EXPORT DawnSwapChainImplementation
- CreateNativeSwapChainImpl(WGPUDevice device, ::VkSurfaceKHR surface);
+ DAWN_NATIVE_EXPORT DawnSwapChainImplementation CreateNativeSwapChainImpl(WGPUDevice device,
+ VkSurfaceKHR surface);
DAWN_NATIVE_EXPORT WGPUTextureFormat
GetNativeSwapChainPreferredFormat(const DawnSwapChainImplementation* swapChain);
diff --git a/src/tests/DawnTest.h b/src/tests/DawnTest.h
index 9cdfd3e..677f670 100644
--- a/src/tests/DawnTest.h
+++ b/src/tests/DawnTest.h
@@ -32,30 +32,30 @@
// them.
#define EXPECT_BUFFER_U32_EQ(expected, buffer, offset) \
AddBufferExpectation(__FILE__, __LINE__, buffer, offset, sizeof(uint32_t), \
- new ::detail::ExpectEq<uint32_t>(expected))
+ new detail::ExpectEq<uint32_t>(expected))
#define EXPECT_BUFFER_U32_RANGE_EQ(expected, buffer, offset, count) \
AddBufferExpectation(__FILE__, __LINE__, buffer, offset, sizeof(uint32_t) * count, \
- new ::detail::ExpectEq<uint32_t>(expected, count))
+ new detail::ExpectEq<uint32_t>(expected, count))
// Test a pixel of the mip level 0 of a 2D texture.
#define EXPECT_PIXEL_RGBA8_EQ(expected, texture, x, y) \
AddTextureExpectation(__FILE__, __LINE__, texture, x, y, 1, 1, 0, 0, sizeof(RGBA8), \
- new ::detail::ExpectEq<RGBA8>(expected))
+ new detail::ExpectEq<RGBA8>(expected))
#define EXPECT_TEXTURE_RGBA8_EQ(expected, texture, x, y, width, height, level, slice) \
AddTextureExpectation(__FILE__, __LINE__, texture, x, y, width, height, level, slice, \
sizeof(RGBA8), \
- new ::detail::ExpectEq<RGBA8>(expected, (width) * (height)))
+ new detail::ExpectEq<RGBA8>(expected, (width) * (height)))
#define EXPECT_PIXEL_FLOAT_EQ(expected, texture, x, y) \
AddTextureExpectation(__FILE__, __LINE__, texture, x, y, 1, 1, 0, 0, sizeof(float), \
- new ::detail::ExpectEq<float>(expected))
+ new detail::ExpectEq<float>(expected))
#define EXPECT_TEXTURE_FLOAT_EQ(expected, texture, x, y, width, height, level, slice) \
AddTextureExpectation(__FILE__, __LINE__, texture, x, y, width, height, level, slice, \
sizeof(float), \
- new ::detail::ExpectEq<float>(expected, (width) * (height)))
+ new detail::ExpectEq<float>(expected, (width) * (height)))
// Should only be used to test validation of function that can't be tested by regular validation
// tests;
diff --git a/src/tests/white_box/VulkanImageWrappingTests.cpp b/src/tests/white_box/VulkanImageWrappingTests.cpp
index 1db96439..de7d8fe 100644
--- a/src/tests/white_box/VulkanImageWrappingTests.cpp
+++ b/src/tests/white_box/VulkanImageWrappingTests.cpp
@@ -25,1008 +25,993 @@
#include "utils/SystemUtils.h"
#include "utils/WGPUHelpers.h"
-namespace dawn_native { namespace vulkan {
+namespace {
- namespace {
-
- class VulkanImageWrappingTestBase : public DawnTest {
- public:
- void TestSetUp() override {
- if (UsesWire()) {
- return;
- }
-
- deviceVk = reinterpret_cast<dawn_native::vulkan::Device*>(device.Get());
+ class VulkanImageWrappingTestBase : public DawnTest {
+ public:
+ void TestSetUp() override {
+ if (UsesWire()) {
+ return;
}
- // Creates a VkImage with external memory
- ::VkResult CreateImage(dawn_native::vulkan::Device* deviceVk,
+ deviceVk = reinterpret_cast<dawn_native::vulkan::Device*>(device.Get());
+ }
+
+ // Creates a VkImage with external memory
+ VkResult CreateImage(dawn_native::vulkan::Device* deviceVk,
+ uint32_t width,
+ uint32_t height,
+ VkFormat format,
+ VkImage* image) {
+ VkExternalMemoryImageCreateInfoKHR externalInfo;
+ externalInfo.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO_KHR;
+ externalInfo.pNext = nullptr;
+ externalInfo.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR;
+
+ auto usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
+ VK_IMAGE_USAGE_TRANSFER_DST_BIT;
+
+ VkImageCreateInfo createInfo;
+ createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
+ createInfo.pNext = &externalInfo;
+ createInfo.flags = VK_IMAGE_CREATE_ALIAS_BIT_KHR;
+ createInfo.imageType = VK_IMAGE_TYPE_2D;
+ createInfo.format = format;
+ createInfo.extent = {width, height, 1};
+ createInfo.mipLevels = 1;
+ createInfo.arrayLayers = 1;
+ createInfo.samples = VK_SAMPLE_COUNT_1_BIT;
+ createInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
+ createInfo.usage = usage;
+ createInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
+ createInfo.queueFamilyIndexCount = 0;
+ createInfo.pQueueFamilyIndices = nullptr;
+ createInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+
+ return deviceVk->fn.CreateImage(deviceVk->GetVkDevice(), &createInfo, nullptr, image);
+ }
+
+ // Allocates memory for an image
+ VkResult AllocateMemory(dawn_native::vulkan::Device* deviceVk,
+ VkImage handle,
+ VkDeviceMemory* allocation,
+ VkDeviceSize* allocationSize,
+ uint32_t* memoryTypeIndex) {
+ // Create the image memory and associate it with the container
+ VkMemoryRequirements requirements;
+ deviceVk->fn.GetImageMemoryRequirements(deviceVk->GetVkDevice(), handle, &requirements);
+
+ // Import memory from file descriptor
+ VkExportMemoryAllocateInfoKHR externalInfo;
+ externalInfo.sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_KHR;
+ externalInfo.pNext = nullptr;
+ externalInfo.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR;
+
+ int bestType = deviceVk->GetResourceMemoryAllocatorForTesting()->FindBestTypeIndex(
+ requirements, false);
+ VkMemoryAllocateInfo allocateInfo;
+ allocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
+ allocateInfo.pNext = &externalInfo;
+ allocateInfo.allocationSize = requirements.size;
+ allocateInfo.memoryTypeIndex = static_cast<uint32_t>(bestType);
+
+ *allocationSize = allocateInfo.allocationSize;
+ *memoryTypeIndex = allocateInfo.memoryTypeIndex;
+
+ return deviceVk->fn.AllocateMemory(deviceVk->GetVkDevice(), &allocateInfo, nullptr,
+ allocation);
+ }
+
+ // Binds memory to an image
+ VkResult BindMemory(dawn_native::vulkan::Device* deviceVk,
+ VkImage handle,
+ VkDeviceMemory* memory) {
+ return deviceVk->fn.BindImageMemory(deviceVk->GetVkDevice(), handle, *memory, 0);
+ }
+
+ // Extracts a file descriptor representing memory on a device
+ int GetMemoryFd(dawn_native::vulkan::Device* deviceVk, VkDeviceMemory memory) {
+ VkMemoryGetFdInfoKHR getFdInfo;
+ getFdInfo.sType = VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR;
+ getFdInfo.pNext = nullptr;
+ getFdInfo.memory = memory;
+ getFdInfo.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR;
+
+ int memoryFd = -1;
+ deviceVk->fn.GetMemoryFdKHR(deviceVk->GetVkDevice(), &getFdInfo, &memoryFd);
+
+ EXPECT_GE(memoryFd, 0) << "Failed to get file descriptor for external memory";
+ return memoryFd;
+ }
+
+ // Prepares and exports memory for an image on a given device
+ void CreateBindExportImage(dawn_native::vulkan::Device* deviceVk,
uint32_t width,
uint32_t height,
VkFormat format,
- VkImage* image) {
- VkExternalMemoryImageCreateInfoKHR externalInfo;
- externalInfo.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO_KHR;
- externalInfo.pNext = nullptr;
- externalInfo.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR;
+ VkImage* handle,
+ VkDeviceMemory* allocation,
+ VkDeviceSize* allocationSize,
+ uint32_t* memoryTypeIndex,
+ int* memoryFd) {
+ VkResult result = CreateImage(deviceVk, width, height, format, handle);
+ EXPECT_EQ(result, VK_SUCCESS) << "Failed to create external image";
- auto usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
- VK_IMAGE_USAGE_TRANSFER_DST_BIT;
+ VkResult resultBool =
+ AllocateMemory(deviceVk, *handle, allocation, allocationSize, memoryTypeIndex);
+ EXPECT_EQ(resultBool, VK_SUCCESS) << "Failed to allocate external memory";
- VkImageCreateInfo createInfo;
- createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
- createInfo.pNext = &externalInfo;
- createInfo.flags = VK_IMAGE_CREATE_ALIAS_BIT_KHR;
- createInfo.imageType = VK_IMAGE_TYPE_2D;
- createInfo.format = format;
- createInfo.extent = {width, height, 1};
- createInfo.mipLevels = 1;
- createInfo.arrayLayers = 1;
- createInfo.samples = VK_SAMPLE_COUNT_1_BIT;
- createInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
- createInfo.usage = usage;
- createInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
- createInfo.queueFamilyIndexCount = 0;
- createInfo.pQueueFamilyIndices = nullptr;
- createInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+ result = BindMemory(deviceVk, *handle, allocation);
+ EXPECT_EQ(result, VK_SUCCESS) << "Failed to bind image memory";
- return deviceVk->fn.CreateImage(deviceVk->GetVkDevice(), &createInfo, nullptr,
- &**image);
- }
-
- // Allocates memory for an image
- ::VkResult AllocateMemory(dawn_native::vulkan::Device* deviceVk,
- VkImage handle,
- VkDeviceMemory* allocation,
- VkDeviceSize* allocationSize,
- uint32_t* memoryTypeIndex) {
- // Create the image memory and associate it with the container
- VkMemoryRequirements requirements;
- deviceVk->fn.GetImageMemoryRequirements(deviceVk->GetVkDevice(), handle,
- &requirements);
-
- // Import memory from file descriptor
- VkExportMemoryAllocateInfoKHR externalInfo;
- externalInfo.sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_KHR;
- externalInfo.pNext = nullptr;
- externalInfo.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR;
-
- int bestType = deviceVk->GetResourceMemoryAllocatorForTesting()->FindBestTypeIndex(
- requirements, false);
- VkMemoryAllocateInfo allocateInfo;
- allocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
- allocateInfo.pNext = &externalInfo;
- allocateInfo.allocationSize = requirements.size;
- allocateInfo.memoryTypeIndex = static_cast<uint32_t>(bestType);
-
- *allocationSize = allocateInfo.allocationSize;
- *memoryTypeIndex = allocateInfo.memoryTypeIndex;
-
- return deviceVk->fn.AllocateMemory(deviceVk->GetVkDevice(), &allocateInfo, nullptr,
- &**allocation);
- }
-
- // Binds memory to an image
- ::VkResult BindMemory(dawn_native::vulkan::Device* deviceVk,
- VkImage handle,
- VkDeviceMemory* memory) {
- return deviceVk->fn.BindImageMemory(deviceVk->GetVkDevice(), handle, *memory, 0);
- }
-
- // Extracts a file descriptor representing memory on a device
- int GetMemoryFd(dawn_native::vulkan::Device* deviceVk, VkDeviceMemory memory) {
- VkMemoryGetFdInfoKHR getFdInfo;
- getFdInfo.sType = VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR;
- getFdInfo.pNext = nullptr;
- getFdInfo.memory = memory;
- getFdInfo.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR;
-
- int memoryFd = -1;
- deviceVk->fn.GetMemoryFdKHR(deviceVk->GetVkDevice(), &getFdInfo, &memoryFd);
-
- EXPECT_GE(memoryFd, 0) << "Failed to get file descriptor for external memory";
- return memoryFd;
- }
-
- // Prepares and exports memory for an image on a given device
- void CreateBindExportImage(dawn_native::vulkan::Device* deviceVk,
- uint32_t width,
- uint32_t height,
- VkFormat format,
- VkImage* handle,
- VkDeviceMemory* allocation,
- VkDeviceSize* allocationSize,
- uint32_t* memoryTypeIndex,
- int* memoryFd) {
- ::VkResult result = CreateImage(deviceVk, width, height, format, handle);
- EXPECT_EQ(result, VK_SUCCESS) << "Failed to create external image";
-
- ::VkResult resultBool =
- AllocateMemory(deviceVk, *handle, allocation, allocationSize, memoryTypeIndex);
- EXPECT_EQ(resultBool, VK_SUCCESS) << "Failed to allocate external memory";
-
- result = BindMemory(deviceVk, *handle, allocation);
- EXPECT_EQ(result, VK_SUCCESS) << "Failed to bind image memory";
-
- *memoryFd = GetMemoryFd(deviceVk, *allocation);
- }
-
- // Wraps a vulkan image from external memory
- wgpu::Texture WrapVulkanImage(wgpu::Device device,
- const wgpu::TextureDescriptor* textureDescriptor,
- int memoryFd,
- VkDeviceSize allocationSize,
- uint32_t memoryTypeIndex,
- std::vector<int> waitFDs,
- bool isCleared = true,
- bool expectValid = true) {
- dawn_native::vulkan::ExternalImageDescriptorOpaqueFD descriptor;
- descriptor.cTextureDescriptor =
- reinterpret_cast<const WGPUTextureDescriptor*>(textureDescriptor);
- descriptor.isCleared = isCleared;
- descriptor.allocationSize = allocationSize;
- descriptor.memoryTypeIndex = memoryTypeIndex;
- descriptor.memoryFD = memoryFd;
- descriptor.waitFDs = waitFDs;
-
- WGPUTexture texture =
- dawn_native::vulkan::WrapVulkanImage(device.Get(), &descriptor);
-
- if (expectValid) {
- EXPECT_NE(texture, nullptr) << "Failed to wrap image, are external memory / "
- "semaphore extensions supported?";
- } else {
- EXPECT_EQ(texture, nullptr);
- }
-
- return wgpu::Texture::Acquire(texture);
- }
-
- // 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 device, wgpu::Texture wrappedTexture) {
- int fd = dawn_native::vulkan::ExportSignalSemaphoreOpaqueFD(device.Get(),
- wrappedTexture.Get());
- ASSERT_NE(fd, -1);
- close(fd);
- }
-
- protected:
- dawn_native::vulkan::Device* deviceVk;
- };
-
- } // anonymous namespace
-
- class VulkanImageWrappingValidationTests : public VulkanImageWrappingTestBase {
- public:
- void TestSetUp() override {
- VulkanImageWrappingTestBase::TestSetUp();
- if (UsesWire()) {
- return;
- }
-
- CreateBindExportImage(deviceVk, 1, 1, VK_FORMAT_R8G8B8A8_UNORM, &defaultImage,
- &defaultAllocation, &defaultAllocationSize,
- &defaultMemoryTypeIndex, &defaultFd);
- defaultDescriptor.dimension = wgpu::TextureDimension::e2D;
- defaultDescriptor.format = wgpu::TextureFormat::RGBA8Unorm;
- defaultDescriptor.size = {1, 1, 1};
- defaultDescriptor.sampleCount = 1;
- defaultDescriptor.arrayLayerCount = 1;
- defaultDescriptor.mipLevelCount = 1;
- defaultDescriptor.usage = wgpu::TextureUsage::OutputAttachment |
- wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::CopyDst;
+ *memoryFd = GetMemoryFd(deviceVk, *allocation);
}
- void TearDown() override {
- if (UsesWire()) {
- VulkanImageWrappingTestBase::TearDown();
- return;
+ // Wraps a vulkan image from external memory
+ wgpu::Texture WrapVulkanImage(wgpu::Device device,
+ const wgpu::TextureDescriptor* textureDescriptor,
+ int memoryFd,
+ VkDeviceSize allocationSize,
+ uint32_t memoryTypeIndex,
+ std::vector<int> waitFDs,
+ bool isCleared = true,
+ bool expectValid = true) {
+ dawn_native::vulkan::ExternalImageDescriptorOpaqueFD descriptor;
+ descriptor.cTextureDescriptor =
+ reinterpret_cast<const WGPUTextureDescriptor*>(textureDescriptor);
+ descriptor.isCleared = isCleared;
+ descriptor.allocationSize = allocationSize;
+ descriptor.memoryTypeIndex = memoryTypeIndex;
+ descriptor.memoryFD = memoryFd;
+ descriptor.waitFDs = waitFDs;
+
+ WGPUTexture texture = dawn_native::vulkan::WrapVulkanImage(device.Get(), &descriptor);
+
+ if (expectValid) {
+ EXPECT_NE(texture, nullptr) << "Failed to wrap image, are external memory / "
+ "semaphore extensions supported?";
+ } else {
+ EXPECT_EQ(texture, nullptr);
}
- deviceVk->GetFencedDeleter()->DeleteWhenUnused(defaultImage);
- deviceVk->GetFencedDeleter()->DeleteWhenUnused(defaultAllocation);
- VulkanImageWrappingTestBase::TearDown();
+ return wgpu::Texture::Acquire(texture);
+ }
+
+ // 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 device, wgpu::Texture wrappedTexture) {
+ int fd = dawn_native::vulkan::ExportSignalSemaphoreOpaqueFD(device.Get(),
+ wrappedTexture.Get());
+ ASSERT_NE(fd, -1);
+ close(fd);
}
protected:
- wgpu::TextureDescriptor defaultDescriptor;
- VkImage defaultImage;
- VkDeviceMemory defaultAllocation;
- VkDeviceSize defaultAllocationSize;
- uint32_t defaultMemoryTypeIndex;
- int defaultFd;
+ dawn_native::vulkan::Device* deviceVk;
};
- // Test no error occurs if the import is valid
- TEST_P(VulkanImageWrappingValidationTests, SuccessfulImport) {
- DAWN_SKIP_TEST_IF(UsesWire());
- wgpu::Texture texture =
- WrapVulkanImage(device, &defaultDescriptor, defaultFd, defaultAllocationSize,
- defaultMemoryTypeIndex, {}, true, true);
- EXPECT_NE(texture.Get(), nullptr);
- IgnoreSignalSemaphore(device, texture);
- }
+} // anonymous namespace
- // Test an error occurs if the texture descriptor is missing
- TEST_P(VulkanImageWrappingValidationTests, MissingTextureDescriptor) {
- DAWN_SKIP_TEST_IF(UsesWire());
- ASSERT_DEVICE_ERROR(wgpu::Texture texture =
- WrapVulkanImage(device, nullptr, defaultFd, defaultAllocationSize,
- defaultMemoryTypeIndex, {}, true, false));
- EXPECT_EQ(texture.Get(), nullptr);
- }
-
- // Test an error occurs if the texture descriptor is invalid
- TEST_P(VulkanImageWrappingValidationTests, InvalidTextureDescriptor) {
- DAWN_SKIP_TEST_IF(UsesWire());
- wgpu::ChainedStruct chainedDescriptor;
- defaultDescriptor.nextInChain = &chainedDescriptor;
-
- ASSERT_DEVICE_ERROR(wgpu::Texture texture = WrapVulkanImage(
- device, &defaultDescriptor, defaultFd, defaultAllocationSize,
- defaultMemoryTypeIndex, {}, true, false));
- EXPECT_EQ(texture.Get(), nullptr);
- }
-
- // Test an error occurs if the descriptor dimension isn't 2D
- TEST_P(VulkanImageWrappingValidationTests, InvalidTextureDimension) {
- DAWN_SKIP_TEST_IF(UsesWire());
- defaultDescriptor.dimension = wgpu::TextureDimension::e1D;
-
- ASSERT_DEVICE_ERROR(wgpu::Texture texture = WrapVulkanImage(
- device, &defaultDescriptor, defaultFd, defaultAllocationSize,
- defaultMemoryTypeIndex, {}, true, false));
- EXPECT_EQ(texture.Get(), nullptr);
- }
-
- // Test an error occurs if the descriptor mip level count isn't 1
- TEST_P(VulkanImageWrappingValidationTests, InvalidMipLevelCount) {
- DAWN_SKIP_TEST_IF(UsesWire());
- defaultDescriptor.mipLevelCount = 2;
-
- ASSERT_DEVICE_ERROR(wgpu::Texture texture = WrapVulkanImage(
- device, &defaultDescriptor, defaultFd, defaultAllocationSize,
- defaultMemoryTypeIndex, {}, true, false));
- EXPECT_EQ(texture.Get(), nullptr);
- }
-
- // Test an error occurs if the descriptor array layer count isn't 1
- TEST_P(VulkanImageWrappingValidationTests, InvalidArrayLayerCount) {
- DAWN_SKIP_TEST_IF(UsesWire());
- defaultDescriptor.arrayLayerCount = 2;
-
- ASSERT_DEVICE_ERROR(wgpu::Texture texture = WrapVulkanImage(
- device, &defaultDescriptor, defaultFd, defaultAllocationSize,
- defaultMemoryTypeIndex, {}, true, false));
- EXPECT_EQ(texture.Get(), nullptr);
- }
-
- // Test an error occurs if the descriptor sample count isn't 1
- TEST_P(VulkanImageWrappingValidationTests, InvalidSampleCount) {
- DAWN_SKIP_TEST_IF(UsesWire());
- defaultDescriptor.sampleCount = 4;
-
- ASSERT_DEVICE_ERROR(wgpu::Texture texture = WrapVulkanImage(
- device, &defaultDescriptor, defaultFd, defaultAllocationSize,
- defaultMemoryTypeIndex, {}, true, false));
- EXPECT_EQ(texture.Get(), nullptr);
- }
-
- // Test an error occurs if we try to export the signal semaphore twice
- TEST_P(VulkanImageWrappingValidationTests, DoubleSignalSemaphoreExport) {
- DAWN_SKIP_TEST_IF(UsesWire());
- wgpu::Texture texture =
- 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);
- }
-
- // Test an error occurs if we try to export the signal semaphore from a normal texture
- TEST_P(VulkanImageWrappingValidationTests, NormalTextureSignalSemaphoreExport) {
- 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);
- }
-
- // Test an error occurs if we try to export the signal semaphore from a destroyed texture
- TEST_P(VulkanImageWrappingValidationTests, DestroyedTextureSignalSemaphoreExport) {
- DAWN_SKIP_TEST_IF(UsesWire());
- 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);
- }
-
- // Fixture to test using external memory textures through different usages.
- // These tests are skipped if the harness is using the wire.
- class VulkanImageWrappingUsageTests : public VulkanImageWrappingTestBase {
- public:
- void TestSetUp() override {
- VulkanImageWrappingTestBase::TestSetUp();
- if (UsesWire()) {
- return;
- }
-
- // Create another device based on the original
- backendAdapter =
- reinterpret_cast<dawn_native::vulkan::Adapter*>(deviceVk->GetAdapter());
- deviceDescriptor.forceEnabledToggles = GetParam().forceEnabledWorkarounds;
- deviceDescriptor.forceDisabledToggles = GetParam().forceDisabledWorkarounds;
-
- secondDeviceVk = reinterpret_cast<dawn_native::vulkan::Device*>(
- backendAdapter->CreateDevice(&deviceDescriptor));
- secondDevice = wgpu::Device::Acquire(reinterpret_cast<WGPUDevice>(secondDeviceVk));
-
- CreateBindExportImage(deviceVk, 1, 1, VK_FORMAT_R8G8B8A8_UNORM, &defaultImage,
- &defaultAllocation, &defaultAllocationSize,
- &defaultMemoryTypeIndex, &defaultFd);
- defaultDescriptor.dimension = wgpu::TextureDimension::e2D;
- defaultDescriptor.format = wgpu::TextureFormat::RGBA8Unorm;
- defaultDescriptor.size = {1, 1, 1};
- defaultDescriptor.sampleCount = 1;
- defaultDescriptor.arrayLayerCount = 1;
- defaultDescriptor.mipLevelCount = 1;
- defaultDescriptor.usage = wgpu::TextureUsage::OutputAttachment |
- wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::CopyDst;
+class VulkanImageWrappingValidationTests : public VulkanImageWrappingTestBase {
+ public:
+ void TestSetUp() override {
+ VulkanImageWrappingTestBase::TestSetUp();
+ if (UsesWire()) {
+ return;
}
- void TearDown() override {
- if (UsesWire()) {
- VulkanImageWrappingTestBase::TearDown();
- return;
- }
+ CreateBindExportImage(deviceVk, 1, 1, VK_FORMAT_R8G8B8A8_UNORM, &defaultImage,
+ &defaultAllocation, &defaultAllocationSize, &defaultMemoryTypeIndex,
+ &defaultFd);
+ defaultDescriptor.dimension = wgpu::TextureDimension::e2D;
+ defaultDescriptor.format = wgpu::TextureFormat::RGBA8Unorm;
+ defaultDescriptor.size = {1, 1, 1};
+ defaultDescriptor.sampleCount = 1;
+ defaultDescriptor.arrayLayerCount = 1;
+ defaultDescriptor.mipLevelCount = 1;
+ defaultDescriptor.usage = wgpu::TextureUsage::OutputAttachment |
+ wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::CopyDst;
+ }
- deviceVk->GetFencedDeleter()->DeleteWhenUnused(defaultImage);
- deviceVk->GetFencedDeleter()->DeleteWhenUnused(defaultAllocation);
+ void TearDown() override {
+ if (UsesWire()) {
VulkanImageWrappingTestBase::TearDown();
+ return;
}
- protected:
- wgpu::Device secondDevice;
- dawn_native::vulkan::Device* secondDeviceVk;
+ deviceVk->GetFencedDeleter()->DeleteWhenUnused(defaultImage);
+ deviceVk->GetFencedDeleter()->DeleteWhenUnused(defaultAllocation);
+ VulkanImageWrappingTestBase::TearDown();
+ }
- dawn_native::vulkan::Adapter* backendAdapter;
- dawn_native::DeviceDescriptor deviceDescriptor;
+ protected:
+ wgpu::TextureDescriptor defaultDescriptor;
+ VkImage defaultImage;
+ VkDeviceMemory defaultAllocation;
+ VkDeviceSize defaultAllocationSize;
+ uint32_t defaultMemoryTypeIndex;
+ int defaultFd;
+};
- wgpu::TextureDescriptor defaultDescriptor;
- VkImage defaultImage;
- VkDeviceMemory defaultAllocation;
- VkDeviceSize defaultAllocationSize;
- uint32_t defaultMemoryTypeIndex;
- int defaultFd;
+// Test no error occurs if the import is valid
+TEST_P(VulkanImageWrappingValidationTests, SuccessfulImport) {
+ DAWN_SKIP_TEST_IF(UsesWire());
+ wgpu::Texture texture =
+ WrapVulkanImage(device, &defaultDescriptor, defaultFd, defaultAllocationSize,
+ defaultMemoryTypeIndex, {}, true, true);
+ EXPECT_NE(texture.Get(), nullptr);
+ IgnoreSignalSemaphore(device, texture);
+}
- // Clear a texture on a given device
- void ClearImage(wgpu::Device device, wgpu::Texture wrappedTexture, wgpu::Color clearColor) {
- wgpu::TextureView wrappedView = wrappedTexture.CreateView();
+// Test an error occurs if the texture descriptor is missing
+TEST_P(VulkanImageWrappingValidationTests, MissingTextureDescriptor) {
+ DAWN_SKIP_TEST_IF(UsesWire());
+ ASSERT_DEVICE_ERROR(wgpu::Texture texture =
+ WrapVulkanImage(device, nullptr, defaultFd, defaultAllocationSize,
+ defaultMemoryTypeIndex, {}, true, false));
+ EXPECT_EQ(texture.Get(), nullptr);
+}
- // Submit a clear operation
- utils::ComboRenderPassDescriptor renderPassDescriptor({wrappedView}, {});
- renderPassDescriptor.cColorAttachments[0].clearColor = clearColor;
+// Test an error occurs if the texture descriptor is invalid
+TEST_P(VulkanImageWrappingValidationTests, InvalidTextureDescriptor) {
+ DAWN_SKIP_TEST_IF(UsesWire());
+ wgpu::ChainedStruct chainedDescriptor;
+ defaultDescriptor.nextInChain = &chainedDescriptor;
- wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
- wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPassDescriptor);
- pass.EndPass();
+ ASSERT_DEVICE_ERROR(wgpu::Texture texture = WrapVulkanImage(
+ device, &defaultDescriptor, defaultFd, defaultAllocationSize,
+ defaultMemoryTypeIndex, {}, true, false));
+ EXPECT_EQ(texture.Get(), nullptr);
+}
- wgpu::CommandBuffer commands = encoder.Finish();
+// Test an error occurs if the descriptor dimension isn't 2D
+TEST_P(VulkanImageWrappingValidationTests, InvalidTextureDimension) {
+ DAWN_SKIP_TEST_IF(UsesWire());
+ defaultDescriptor.dimension = wgpu::TextureDimension::e1D;
- wgpu::Queue queue = device.CreateQueue();
- queue.Submit(1, &commands);
+ ASSERT_DEVICE_ERROR(wgpu::Texture texture = WrapVulkanImage(
+ device, &defaultDescriptor, defaultFd, defaultAllocationSize,
+ defaultMemoryTypeIndex, {}, true, false));
+ EXPECT_EQ(texture.Get(), nullptr);
+}
+
+// Test an error occurs if the descriptor mip level count isn't 1
+TEST_P(VulkanImageWrappingValidationTests, InvalidMipLevelCount) {
+ DAWN_SKIP_TEST_IF(UsesWire());
+ defaultDescriptor.mipLevelCount = 2;
+
+ ASSERT_DEVICE_ERROR(wgpu::Texture texture = WrapVulkanImage(
+ device, &defaultDescriptor, defaultFd, defaultAllocationSize,
+ defaultMemoryTypeIndex, {}, true, false));
+ EXPECT_EQ(texture.Get(), nullptr);
+}
+
+// Test an error occurs if the descriptor array layer count isn't 1
+TEST_P(VulkanImageWrappingValidationTests, InvalidArrayLayerCount) {
+ DAWN_SKIP_TEST_IF(UsesWire());
+ defaultDescriptor.arrayLayerCount = 2;
+
+ ASSERT_DEVICE_ERROR(wgpu::Texture texture = WrapVulkanImage(
+ device, &defaultDescriptor, defaultFd, defaultAllocationSize,
+ defaultMemoryTypeIndex, {}, true, false));
+ EXPECT_EQ(texture.Get(), nullptr);
+}
+
+// Test an error occurs if the descriptor sample count isn't 1
+TEST_P(VulkanImageWrappingValidationTests, InvalidSampleCount) {
+ DAWN_SKIP_TEST_IF(UsesWire());
+ defaultDescriptor.sampleCount = 4;
+
+ ASSERT_DEVICE_ERROR(wgpu::Texture texture = WrapVulkanImage(
+ device, &defaultDescriptor, defaultFd, defaultAllocationSize,
+ defaultMemoryTypeIndex, {}, true, false));
+ EXPECT_EQ(texture.Get(), nullptr);
+}
+
+// Test an error occurs if we try to export the signal semaphore twice
+TEST_P(VulkanImageWrappingValidationTests, DoubleSignalSemaphoreExport) {
+ DAWN_SKIP_TEST_IF(UsesWire());
+ wgpu::Texture texture =
+ 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);
+}
+
+// Test an error occurs if we try to export the signal semaphore from a normal texture
+TEST_P(VulkanImageWrappingValidationTests, NormalTextureSignalSemaphoreExport) {
+ 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);
+}
+
+// Test an error occurs if we try to export the signal semaphore from a destroyed texture
+TEST_P(VulkanImageWrappingValidationTests, DestroyedTextureSignalSemaphoreExport) {
+ DAWN_SKIP_TEST_IF(UsesWire());
+ 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);
+}
+
+// Fixture to test using external memory textures through different usages.
+// These tests are skipped if the harness is using the wire.
+class VulkanImageWrappingUsageTests : public VulkanImageWrappingTestBase {
+ public:
+ void TestSetUp() override {
+ VulkanImageWrappingTestBase::TestSetUp();
+ if (UsesWire()) {
+ return;
}
- // Submits a 1x1x1 copy from source to destination
- void SimpleCopyTextureToTexture(wgpu::Device device,
- wgpu::Queue queue,
- wgpu::Texture source,
- wgpu::Texture destination) {
- wgpu::TextureCopyView copySrc;
- copySrc.texture = source;
- copySrc.mipLevel = 0;
- copySrc.arrayLayer = 0;
- copySrc.origin = {0, 0, 0};
+ // Create another device based on the original
+ backendAdapter = reinterpret_cast<dawn_native::vulkan::Adapter*>(deviceVk->GetAdapter());
+ deviceDescriptor.forceEnabledToggles = GetParam().forceEnabledWorkarounds;
+ deviceDescriptor.forceDisabledToggles = GetParam().forceDisabledWorkarounds;
- wgpu::TextureCopyView copyDst;
- copyDst.texture = destination;
- copyDst.mipLevel = 0;
- copyDst.arrayLayer = 0;
- copyDst.origin = {0, 0, 0};
+ secondDeviceVk = reinterpret_cast<dawn_native::vulkan::Device*>(
+ backendAdapter->CreateDevice(&deviceDescriptor));
+ secondDevice = wgpu::Device::Acquire(reinterpret_cast<WGPUDevice>(secondDeviceVk));
- wgpu::Extent3D copySize = {1, 1, 1};
+ CreateBindExportImage(deviceVk, 1, 1, VK_FORMAT_R8G8B8A8_UNORM, &defaultImage,
+ &defaultAllocation, &defaultAllocationSize, &defaultMemoryTypeIndex,
+ &defaultFd);
+ defaultDescriptor.dimension = wgpu::TextureDimension::e2D;
+ defaultDescriptor.format = wgpu::TextureFormat::RGBA8Unorm;
+ defaultDescriptor.size = {1, 1, 1};
+ defaultDescriptor.sampleCount = 1;
+ defaultDescriptor.arrayLayerCount = 1;
+ defaultDescriptor.mipLevelCount = 1;
+ defaultDescriptor.usage = wgpu::TextureUsage::OutputAttachment |
+ wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::CopyDst;
+ }
- wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
- encoder.CopyTextureToTexture(©Src, ©Dst, ©Size);
- wgpu::CommandBuffer commands = encoder.Finish();
-
- queue.Submit(1, &commands);
+ void TearDown() override {
+ if (UsesWire()) {
+ VulkanImageWrappingTestBase::TearDown();
+ return;
}
- };
- // Clear an image in |secondDevice|
- // Verify clear color is visible in |device|
- TEST_P(VulkanImageWrappingUsageTests, ClearImageAcrossDevices) {
- DAWN_SKIP_TEST_IF(UsesWire());
-
- // 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|
- EXPECT_PIXEL_RGBA8_EQ(RGBA8(1, 2, 3, 4), nextWrappedTexture, 0, 0);
-
- IgnoreSignalSemaphore(device, nextWrappedTexture);
+ deviceVk->GetFencedDeleter()->DeleteWhenUnused(defaultImage);
+ deviceVk->GetFencedDeleter()->DeleteWhenUnused(defaultAllocation);
+ VulkanImageWrappingTestBase::TearDown();
}
- // 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());
- // Import the image on |device
- wgpu::Texture wrappedTextureAlias =
- WrapVulkanImage(device, &defaultDescriptor, defaultFd, defaultAllocationSize,
- defaultMemoryTypeIndex, {});
+ protected:
+ wgpu::Device secondDevice;
+ dawn_native::vulkan::Device* secondDeviceVk;
- int memoryFd = GetMemoryFd(deviceVk, defaultAllocation);
+ dawn_native::vulkan::Adapter* backendAdapter;
+ dawn_native::DeviceDescriptor deviceDescriptor;
- // Import the image on |secondDevice|
- wgpu::Texture wrappedTexture =
- WrapVulkanImage(secondDevice, &defaultDescriptor, defaultFd, defaultAllocationSize,
- defaultMemoryTypeIndex, {});
+ wgpu::TextureDescriptor defaultDescriptor;
+ VkImage defaultImage;
+ VkDeviceMemory defaultAllocation;
+ VkDeviceSize defaultAllocationSize;
+ uint32_t defaultMemoryTypeIndex;
+ int defaultFd;
- // Clear |wrappedTexture| on |secondDevice|
- ClearImage(secondDevice, wrappedTexture, {1 / 255.0f, 2 / 255.0f, 3 / 255.0f, 4 / 255.0f});
+ // Clear a texture on a given device
+ void ClearImage(wgpu::Device device, wgpu::Texture wrappedTexture, wgpu::Color clearColor) {
+ wgpu::TextureView wrappedView = wrappedTexture.CreateView();
- int signalFd = dawn_native::vulkan::ExportSignalSemaphoreOpaqueFD(secondDevice.Get(),
- wrappedTexture.Get());
+ // Submit a clear operation
+ utils::ComboRenderPassDescriptor renderPassDescriptor({wrappedView}, {});
+ renderPassDescriptor.cColorAttachments[0].clearColor = clearColor;
- // Import the image to |device|, making sure we wait on signalFd
- memoryFd = GetMemoryFd(deviceVk, defaultAllocation);
- wgpu::Texture nextWrappedTexture =
- WrapVulkanImage(device, &defaultDescriptor, memoryFd, defaultAllocationSize,
- defaultMemoryTypeIndex, {signalFd});
+ wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
+ wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPassDescriptor);
+ pass.EndPass();
- // Verify |device| sees the changes from |secondDevice| (waits)
- EXPECT_PIXEL_RGBA8_EQ(RGBA8(1, 2, 3, 4), nextWrappedTexture, 0, 0);
+ wgpu::CommandBuffer commands = encoder.Finish();
- // 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);
+ wgpu::Queue queue = device.CreateQueue();
+ queue.Submit(1, &commands);
}
- // 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) {
- DAWN_SKIP_TEST_IF(UsesWire());
-
- // 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}, 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);
- }
-
- // Import a texture into |secondDevice|
- // Issue a copy of the imported texture inside |device| to |copyDstTexture|
- // Verify the clear color from |secondDevice| is visible in |copyDstTexture|
- TEST_P(VulkanImageWrappingUsageTests, CopyTextureToTextureSrcSync) {
- DAWN_SKIP_TEST_IF(UsesWire());
-
- // 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 deviceWrappedTexture =
- WrapVulkanImage(device, &defaultDescriptor, memoryFd, defaultAllocationSize,
- defaultMemoryTypeIndex, {signalFd});
-
- // Create a second texture on |device|
- wgpu::Texture copyDstTexture = device.CreateTexture(&defaultDescriptor);
-
- // Copy |deviceWrappedTexture| into |copyDstTexture|
- SimpleCopyTextureToTexture(device, queue, deviceWrappedTexture, copyDstTexture);
-
- // Verify |copyDstTexture| sees changes from |secondDevice|
- EXPECT_PIXEL_RGBA8_EQ(RGBA8(1, 2, 3, 4), copyDstTexture, 0, 0);
-
- IgnoreSignalSemaphore(device, deviceWrappedTexture);
- }
-
- // Import a texture into |device|
- // Copy color A into texture on |device|
- // Import same texture into |secondDevice|, waiting on the copy signal
- // Copy color B using Texture to Texture copy on |secondDevice|
- // Import texture back into |device|, waiting on color B signal
- // Verify texture contains color B
- // If texture destination isn't synchronized, |secondDevice| could copy color B
- // into the texture first, then |device| writes color A
- TEST_P(VulkanImageWrappingUsageTests, CopyTextureToTextureDstSync) {
- DAWN_SKIP_TEST_IF(UsesWire());
-
- // Import the image on |device|
- wgpu::Texture wrappedTexture =
- WrapVulkanImage(device, &defaultDescriptor, defaultFd, defaultAllocationSize,
- defaultMemoryTypeIndex, {});
-
- // 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());
-
- // 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});
-
- // Create a texture with color B on |secondDevice|
- wgpu::Texture copySrcTexture = secondDevice.CreateTexture(&defaultDescriptor);
- ClearImage(secondDevice, copySrcTexture, {1 / 255.0f, 2 / 255.0f, 3 / 255.0f, 4 / 255.0f});
-
- // Copy color B on |secondDevice|
- wgpu::Queue secondDeviceQueue = secondDevice.CreateQueue();
- SimpleCopyTextureToTexture(secondDevice, secondDeviceQueue, copySrcTexture,
- secondDeviceWrappedTexture);
-
- // Re-import back into |device|, waiting on |secondDevice|'s signal
- signalFd = dawn_native::vulkan::ExportSignalSemaphoreOpaqueFD(
- secondDevice.Get(), secondDeviceWrappedTexture.Get());
- memoryFd = GetMemoryFd(deviceVk, defaultAllocation);
-
- wgpu::Texture nextWrappedTexture =
- WrapVulkanImage(device, &defaultDescriptor, memoryFd, defaultAllocationSize,
- defaultMemoryTypeIndex, {signalFd});
-
- // Verify |nextWrappedTexture| contains the color from our copy
- EXPECT_PIXEL_RGBA8_EQ(RGBA8(1, 2, 3, 4), nextWrappedTexture, 0, 0);
-
- IgnoreSignalSemaphore(device, nextWrappedTexture);
- }
-
- // Import a texture from |secondDevice|
- // Issue a copy of the imported texture inside |device| to |copyDstBuffer|
- // Verify the clear color from |secondDevice| is visible in |copyDstBuffer|
- TEST_P(VulkanImageWrappingUsageTests, CopyTextureToBufferSrcSync) {
- DAWN_SKIP_TEST_IF(UsesWire());
-
- // 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 deviceWrappedTexture =
- WrapVulkanImage(device, &defaultDescriptor, memoryFd, defaultAllocationSize,
- defaultMemoryTypeIndex, {signalFd});
-
- // Create a destination buffer on |device|
- wgpu::BufferDescriptor bufferDesc;
- bufferDesc.size = 4;
- bufferDesc.usage = wgpu::BufferUsage::CopyDst | wgpu::BufferUsage::CopySrc;
- wgpu::Buffer copyDstBuffer = device.CreateBuffer(&bufferDesc);
-
- // Copy |deviceWrappedTexture| into |copyDstBuffer|
+ // Submits a 1x1x1 copy from source to destination
+ void SimpleCopyTextureToTexture(wgpu::Device device,
+ wgpu::Queue queue,
+ wgpu::Texture source,
+ wgpu::Texture destination) {
wgpu::TextureCopyView copySrc;
- copySrc.texture = deviceWrappedTexture;
+ copySrc.texture = source;
copySrc.mipLevel = 0;
copySrc.arrayLayer = 0;
copySrc.origin = {0, 0, 0};
- wgpu::BufferCopyView copyDst;
- copyDst.buffer = copyDstBuffer;
- copyDst.offset = 0;
- copyDst.rowPitch = 256;
- copyDst.imageHeight = 0;
-
- wgpu::Extent3D copySize = {1, 1, 1};
-
- wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
- encoder.CopyTextureToBuffer(©Src, ©Dst, ©Size);
- wgpu::CommandBuffer commands = encoder.Finish();
- queue.Submit(1, &commands);
-
- // Verify |copyDstBuffer| sees changes from |secondDevice|
- uint32_t expected = 0x04030201;
- EXPECT_BUFFER_U32_EQ(expected, copyDstBuffer, 0);
-
- IgnoreSignalSemaphore(device, deviceWrappedTexture);
- }
-
- // Import a texture into |device|
- // Copy color A into texture on |device|
- // Import same texture into |secondDevice|, waiting on the copy signal
- // Copy color B using Buffer to Texture copy on |secondDevice|
- // Import texture back into |device|, waiting on color B signal
- // Verify texture contains color B
- // If texture destination isn't synchronized, |secondDevice| could copy color B
- // into the texture first, then |device| writes color A
- TEST_P(VulkanImageWrappingUsageTests, CopyBufferToTextureDstSync) {
- DAWN_SKIP_TEST_IF(UsesWire());
-
- // Import the image on |device|
- wgpu::Texture wrappedTexture =
- WrapVulkanImage(device, &defaultDescriptor, defaultFd, defaultAllocationSize,
- defaultMemoryTypeIndex, {});
-
- // 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());
-
- // 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});
-
- // Copy color B on |secondDevice|
- wgpu::Queue secondDeviceQueue = secondDevice.CreateQueue();
-
- // Create a buffer on |secondDevice|
- wgpu::Buffer copySrcBuffer =
- utils::CreateBufferFromData(secondDevice, wgpu::BufferUsage::CopySrc, {0x04030201});
-
- // Copy |copySrcBuffer| into |secondDeviceWrappedTexture|
- wgpu::BufferCopyView copySrc;
- copySrc.buffer = copySrcBuffer;
- copySrc.offset = 0;
- copySrc.rowPitch = 256;
- copySrc.imageHeight = 0;
-
wgpu::TextureCopyView copyDst;
- copyDst.texture = secondDeviceWrappedTexture;
+ copyDst.texture = destination;
copyDst.mipLevel = 0;
copyDst.arrayLayer = 0;
copyDst.origin = {0, 0, 0};
wgpu::Extent3D copySize = {1, 1, 1};
+ wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
+ encoder.CopyTextureToTexture(©Src, ©Dst, ©Size);
+ wgpu::CommandBuffer commands = encoder.Finish();
+
+ queue.Submit(1, &commands);
+ }
+};
+
+// Clear an image in |secondDevice|
+// Verify clear color is visible in |device|
+TEST_P(VulkanImageWrappingUsageTests, ClearImageAcrossDevices) {
+ DAWN_SKIP_TEST_IF(UsesWire());
+
+ // 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|
+ 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());
+ // Import the image on |device
+ wgpu::Texture wrappedTextureAlias = WrapVulkanImage(
+ device, &defaultDescriptor, defaultFd, defaultAllocationSize, defaultMemoryTypeIndex, {});
+
+ int memoryFd = GetMemoryFd(deviceVk, defaultAllocation);
+
+ // 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
+ 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);
+}
+
+// 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) {
+ DAWN_SKIP_TEST_IF(UsesWire());
+
+ // 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}, 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);
+}
+
+// Import a texture into |secondDevice|
+// Issue a copy of the imported texture inside |device| to |copyDstTexture|
+// Verify the clear color from |secondDevice| is visible in |copyDstTexture|
+TEST_P(VulkanImageWrappingUsageTests, CopyTextureToTextureSrcSync) {
+ DAWN_SKIP_TEST_IF(UsesWire());
+
+ // 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 deviceWrappedTexture =
+ WrapVulkanImage(device, &defaultDescriptor, memoryFd, defaultAllocationSize,
+ defaultMemoryTypeIndex, {signalFd});
+
+ // Create a second texture on |device|
+ wgpu::Texture copyDstTexture = device.CreateTexture(&defaultDescriptor);
+
+ // Copy |deviceWrappedTexture| into |copyDstTexture|
+ SimpleCopyTextureToTexture(device, queue, deviceWrappedTexture, copyDstTexture);
+
+ // Verify |copyDstTexture| sees changes from |secondDevice|
+ EXPECT_PIXEL_RGBA8_EQ(RGBA8(1, 2, 3, 4), copyDstTexture, 0, 0);
+
+ IgnoreSignalSemaphore(device, deviceWrappedTexture);
+}
+
+// Import a texture into |device|
+// Copy color A into texture on |device|
+// Import same texture into |secondDevice|, waiting on the copy signal
+// Copy color B using Texture to Texture copy on |secondDevice|
+// Import texture back into |device|, waiting on color B signal
+// Verify texture contains color B
+// If texture destination isn't synchronized, |secondDevice| could copy color B
+// into the texture first, then |device| writes color A
+TEST_P(VulkanImageWrappingUsageTests, CopyTextureToTextureDstSync) {
+ DAWN_SKIP_TEST_IF(UsesWire());
+
+ // Import the image on |device|
+ wgpu::Texture wrappedTexture = WrapVulkanImage(
+ device, &defaultDescriptor, defaultFd, defaultAllocationSize, defaultMemoryTypeIndex, {});
+
+ // 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());
+
+ // 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});
+
+ // Create a texture with color B on |secondDevice|
+ wgpu::Texture copySrcTexture = secondDevice.CreateTexture(&defaultDescriptor);
+ ClearImage(secondDevice, copySrcTexture, {1 / 255.0f, 2 / 255.0f, 3 / 255.0f, 4 / 255.0f});
+
+ // Copy color B on |secondDevice|
+ wgpu::Queue secondDeviceQueue = secondDevice.CreateQueue();
+ SimpleCopyTextureToTexture(secondDevice, secondDeviceQueue, copySrcTexture,
+ secondDeviceWrappedTexture);
+
+ // Re-import back into |device|, waiting on |secondDevice|'s signal
+ signalFd = dawn_native::vulkan::ExportSignalSemaphoreOpaqueFD(secondDevice.Get(),
+ secondDeviceWrappedTexture.Get());
+ memoryFd = GetMemoryFd(deviceVk, defaultAllocation);
+
+ wgpu::Texture nextWrappedTexture =
+ WrapVulkanImage(device, &defaultDescriptor, memoryFd, defaultAllocationSize,
+ defaultMemoryTypeIndex, {signalFd});
+
+ // Verify |nextWrappedTexture| contains the color from our copy
+ EXPECT_PIXEL_RGBA8_EQ(RGBA8(1, 2, 3, 4), nextWrappedTexture, 0, 0);
+
+ IgnoreSignalSemaphore(device, nextWrappedTexture);
+}
+
+// Import a texture from |secondDevice|
+// Issue a copy of the imported texture inside |device| to |copyDstBuffer|
+// Verify the clear color from |secondDevice| is visible in |copyDstBuffer|
+TEST_P(VulkanImageWrappingUsageTests, CopyTextureToBufferSrcSync) {
+ DAWN_SKIP_TEST_IF(UsesWire());
+
+ // 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 deviceWrappedTexture =
+ WrapVulkanImage(device, &defaultDescriptor, memoryFd, defaultAllocationSize,
+ defaultMemoryTypeIndex, {signalFd});
+
+ // Create a destination buffer on |device|
+ wgpu::BufferDescriptor bufferDesc;
+ bufferDesc.size = 4;
+ bufferDesc.usage = wgpu::BufferUsage::CopyDst | wgpu::BufferUsage::CopySrc;
+ wgpu::Buffer copyDstBuffer = device.CreateBuffer(&bufferDesc);
+
+ // Copy |deviceWrappedTexture| into |copyDstBuffer|
+ wgpu::TextureCopyView copySrc;
+ copySrc.texture = deviceWrappedTexture;
+ copySrc.mipLevel = 0;
+ copySrc.arrayLayer = 0;
+ copySrc.origin = {0, 0, 0};
+
+ wgpu::BufferCopyView copyDst;
+ copyDst.buffer = copyDstBuffer;
+ copyDst.offset = 0;
+ copyDst.rowPitch = 256;
+ copyDst.imageHeight = 0;
+
+ wgpu::Extent3D copySize = {1, 1, 1};
+
+ wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
+ encoder.CopyTextureToBuffer(©Src, ©Dst, ©Size);
+ wgpu::CommandBuffer commands = encoder.Finish();
+ queue.Submit(1, &commands);
+
+ // Verify |copyDstBuffer| sees changes from |secondDevice|
+ uint32_t expected = 0x04030201;
+ EXPECT_BUFFER_U32_EQ(expected, copyDstBuffer, 0);
+
+ IgnoreSignalSemaphore(device, deviceWrappedTexture);
+}
+
+// Import a texture into |device|
+// Copy color A into texture on |device|
+// Import same texture into |secondDevice|, waiting on the copy signal
+// Copy color B using Buffer to Texture copy on |secondDevice|
+// Import texture back into |device|, waiting on color B signal
+// Verify texture contains color B
+// If texture destination isn't synchronized, |secondDevice| could copy color B
+// into the texture first, then |device| writes color A
+TEST_P(VulkanImageWrappingUsageTests, CopyBufferToTextureDstSync) {
+ DAWN_SKIP_TEST_IF(UsesWire());
+
+ // Import the image on |device|
+ wgpu::Texture wrappedTexture = WrapVulkanImage(
+ device, &defaultDescriptor, defaultFd, defaultAllocationSize, defaultMemoryTypeIndex, {});
+
+ // 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());
+
+ // 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});
+
+ // Copy color B on |secondDevice|
+ wgpu::Queue secondDeviceQueue = secondDevice.CreateQueue();
+
+ // Create a buffer on |secondDevice|
+ wgpu::Buffer copySrcBuffer =
+ utils::CreateBufferFromData(secondDevice, wgpu::BufferUsage::CopySrc, {0x04030201});
+
+ // Copy |copySrcBuffer| into |secondDeviceWrappedTexture|
+ wgpu::BufferCopyView copySrc;
+ copySrc.buffer = copySrcBuffer;
+ copySrc.offset = 0;
+ copySrc.rowPitch = 256;
+ copySrc.imageHeight = 0;
+
+ wgpu::TextureCopyView copyDst;
+ copyDst.texture = secondDeviceWrappedTexture;
+ copyDst.mipLevel = 0;
+ copyDst.arrayLayer = 0;
+ copyDst.origin = {0, 0, 0};
+
+ wgpu::Extent3D copySize = {1, 1, 1};
+
+ wgpu::CommandEncoder encoder = secondDevice.CreateCommandEncoder();
+ encoder.CopyBufferToTexture(©Src, ©Dst, ©Size);
+ wgpu::CommandBuffer commands = encoder.Finish();
+ secondDeviceQueue.Submit(1, &commands);
+
+ // Re-import back into |device|, waiting on |secondDevice|'s signal
+ signalFd = dawn_native::vulkan::ExportSignalSemaphoreOpaqueFD(secondDevice.Get(),
+ secondDeviceWrappedTexture.Get());
+ memoryFd = GetMemoryFd(deviceVk, defaultAllocation);
+
+ wgpu::Texture nextWrappedTexture =
+ WrapVulkanImage(device, &defaultDescriptor, memoryFd, defaultAllocationSize,
+ defaultMemoryTypeIndex, {signalFd});
+
+ // Verify |nextWrappedTexture| contains the color from our copy
+ EXPECT_PIXEL_RGBA8_EQ(RGBA8(1, 2, 3, 4), nextWrappedTexture, 0, 0);
+
+ IgnoreSignalSemaphore(device, nextWrappedTexture);
+}
+
+// Import a texture from |secondDevice|
+// Issue a copy of the imported texture inside |device| to |copyDstTexture|
+// Issue second copy to |secondCopyDstTexture|
+// Verify the clear color from |secondDevice| is visible in both copies
+TEST_P(VulkanImageWrappingUsageTests, DoubleTextureUsage) {
+ DAWN_SKIP_TEST_IF(UsesWire());
+
+ // 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 deviceWrappedTexture =
+ WrapVulkanImage(device, &defaultDescriptor, memoryFd, defaultAllocationSize,
+ defaultMemoryTypeIndex, {signalFd});
+
+ // Create a second texture on |device|
+ wgpu::Texture copyDstTexture = device.CreateTexture(&defaultDescriptor);
+
+ // Create a third texture on |device|
+ wgpu::Texture secondCopyDstTexture = device.CreateTexture(&defaultDescriptor);
+
+ // Copy |deviceWrappedTexture| into |copyDstTexture|
+ SimpleCopyTextureToTexture(device, queue, deviceWrappedTexture, copyDstTexture);
+
+ // Copy |deviceWrappedTexture| into |secondCopyDstTexture|
+ SimpleCopyTextureToTexture(device, queue, deviceWrappedTexture, secondCopyDstTexture);
+
+ // Verify |copyDstTexture| sees changes from |secondDevice|
+ EXPECT_PIXEL_RGBA8_EQ(RGBA8(1, 2, 3, 4), copyDstTexture, 0, 0);
+
+ // Verify |secondCopyDstTexture| sees changes from |secondDevice|
+ EXPECT_PIXEL_RGBA8_EQ(RGBA8(1, 2, 3, 4), secondCopyDstTexture, 0, 0);
+
+ IgnoreSignalSemaphore(device, deviceWrappedTexture);
+}
+
+// Tex A on device 3 (external export)
+// Tex B on device 2 (external export)
+// Tex C on device 1 (external export)
+// Clear color for A on device 3
+// Copy A->B on device 3
+// Copy B->C on device 2 (wait on B from previous op)
+// Copy C->D on device 1 (wait on C from previous op)
+// Verify D has same color as A
+TEST_P(VulkanImageWrappingUsageTests, ChainTextureCopy) {
+ DAWN_SKIP_TEST_IF(UsesWire());
+
+ // Close |defaultFd| since this test doesn't import it anywhere
+ close(defaultFd);
+
+ // device 1 = |device|
+ // device 2 = |secondDevice|
+ // Create device 3
+ dawn_native::vulkan::Device* thirdDeviceVk = reinterpret_cast<dawn_native::vulkan::Device*>(
+ backendAdapter->CreateDevice(&deviceDescriptor));
+ wgpu::Device thirdDevice = wgpu::Device::Acquire(reinterpret_cast<WGPUDevice>(thirdDeviceVk));
+
+ // Make queue for device 2 and 3
+ wgpu::Queue secondDeviceQueue = secondDevice.CreateQueue();
+ wgpu::Queue thirdDeviceQueue = thirdDevice.CreateQueue();
+
+ // Allocate memory for A, B, C
+ VkImage imageA;
+ VkDeviceMemory allocationA;
+ int memoryFdA;
+ VkDeviceSize allocationSizeA;
+ uint32_t memoryTypeIndexA;
+ CreateBindExportImage(thirdDeviceVk, 1, 1, VK_FORMAT_R8G8B8A8_UNORM, &imageA, &allocationA,
+ &allocationSizeA, &memoryTypeIndexA, &memoryFdA);
+
+ VkImage imageB;
+ VkDeviceMemory allocationB;
+ int memoryFdB;
+ VkDeviceSize allocationSizeB;
+ uint32_t memoryTypeIndexB;
+ CreateBindExportImage(secondDeviceVk, 1, 1, VK_FORMAT_R8G8B8A8_UNORM, &imageB, &allocationB,
+ &allocationSizeB, &memoryTypeIndexB, &memoryFdB);
+
+ VkImage imageC;
+ VkDeviceMemory allocationC;
+ int memoryFdC;
+ VkDeviceSize allocationSizeC;
+ uint32_t memoryTypeIndexC;
+ CreateBindExportImage(deviceVk, 1, 1, VK_FORMAT_R8G8B8A8_UNORM, &imageC, &allocationC,
+ &allocationSizeC, &memoryTypeIndexC, &memoryFdC);
+
+ // Import TexA, TexB on device 3
+ wgpu::Texture wrappedTexADevice3 = WrapVulkanImage(thirdDevice, &defaultDescriptor, memoryFdA,
+ allocationSizeA, memoryTypeIndexA, {});
+
+ wgpu::Texture wrappedTexBDevice3 = WrapVulkanImage(thirdDevice, &defaultDescriptor, memoryFdB,
+ allocationSizeB, memoryTypeIndexB, {});
+
+ // Clear TexA
+ ClearImage(thirdDevice, wrappedTexADevice3, {1 / 255.0f, 2 / 255.0f, 3 / 255.0f, 4 / 255.0f});
+
+ // Copy A->B
+ SimpleCopyTextureToTexture(thirdDevice, thirdDeviceQueue, wrappedTexADevice3,
+ wrappedTexBDevice3);
+
+ int signalFdTexBDevice3 = dawn_native::vulkan::ExportSignalSemaphoreOpaqueFD(
+ thirdDevice.Get(), wrappedTexBDevice3.Get());
+ IgnoreSignalSemaphore(thirdDevice, wrappedTexADevice3);
+
+ // Import TexB, TexC on device 2
+ memoryFdB = GetMemoryFd(secondDeviceVk, allocationB);
+ wgpu::Texture wrappedTexBDevice2 =
+ WrapVulkanImage(secondDevice, &defaultDescriptor, memoryFdB, allocationSizeB,
+ memoryTypeIndexB, {signalFdTexBDevice3});
+
+ wgpu::Texture wrappedTexCDevice2 = WrapVulkanImage(secondDevice, &defaultDescriptor, memoryFdC,
+ allocationSizeC, memoryTypeIndexC, {});
+
+ // Copy B->C on device 2
+ SimpleCopyTextureToTexture(secondDevice, secondDeviceQueue, wrappedTexBDevice2,
+ wrappedTexCDevice2);
+
+ int signalFdTexCDevice2 = dawn_native::vulkan::ExportSignalSemaphoreOpaqueFD(
+ secondDevice.Get(), wrappedTexCDevice2.Get());
+ IgnoreSignalSemaphore(secondDevice, wrappedTexBDevice2);
+
+ // Import TexC on device 1
+ memoryFdC = GetMemoryFd(deviceVk, allocationC);
+ wgpu::Texture wrappedTexCDevice1 =
+ WrapVulkanImage(device, &defaultDescriptor, memoryFdC, allocationSizeC, memoryTypeIndexC,
+ {signalFdTexCDevice2});
+
+ // Create TexD on device 1
+ wgpu::Texture texD = device.CreateTexture(&defaultDescriptor);
+
+ // Copy C->D on device 1
+ SimpleCopyTextureToTexture(device, queue, wrappedTexCDevice1, texD);
+
+ // Verify D matches clear color
+ EXPECT_PIXEL_RGBA8_EQ(RGBA8(1, 2, 3, 4), texD, 0, 0);
+
+ thirdDeviceVk->GetFencedDeleter()->DeleteWhenUnused(imageA);
+ thirdDeviceVk->GetFencedDeleter()->DeleteWhenUnused(allocationA);
+ secondDeviceVk->GetFencedDeleter()->DeleteWhenUnused(imageB);
+ secondDeviceVk->GetFencedDeleter()->DeleteWhenUnused(allocationB);
+ deviceVk->GetFencedDeleter()->DeleteWhenUnused(imageC);
+ deviceVk->GetFencedDeleter()->DeleteWhenUnused(allocationC);
+
+ IgnoreSignalSemaphore(device, wrappedTexCDevice1);
+}
+
+// Tests a larger image is preserved when importing
+// TODO(http://crbug.com/dawn/206): This fails on AMD
+TEST_P(VulkanImageWrappingUsageTests, LargerImage) {
+ DAWN_SKIP_TEST_IF(UsesWire() || IsAMD());
+
+ close(defaultFd);
+
+ wgpu::TextureDescriptor descriptor;
+ descriptor.dimension = wgpu::TextureDimension::e2D;
+ descriptor.size.width = 640;
+ descriptor.size.height = 480;
+ descriptor.size.depth = 1;
+ descriptor.arrayLayerCount = 1;
+ descriptor.sampleCount = 1;
+ descriptor.format = wgpu::TextureFormat::BGRA8Unorm;
+ descriptor.mipLevelCount = 1;
+ descriptor.usage = wgpu::TextureUsage::CopyDst | wgpu::TextureUsage::CopySrc;
+
+ // Fill memory with textures to trigger layout issues on AMD
+ std::vector<wgpu::Texture> textures;
+ for (int i = 0; i < 20; i++) {
+ textures.push_back(device.CreateTexture(&descriptor));
+ }
+
+ wgpu::Queue secondDeviceQueue = secondDevice.CreateQueue();
+
+ // Make an image on |secondDevice|
+ VkImage imageA;
+ VkDeviceMemory allocationA;
+ int memoryFdA;
+ VkDeviceSize allocationSizeA;
+ uint32_t memoryTypeIndexA;
+ CreateBindExportImage(secondDeviceVk, 640, 480, VK_FORMAT_R8G8B8A8_UNORM, &imageA, &allocationA,
+ &allocationSizeA, &memoryTypeIndexA, &memoryFdA);
+
+ // Import the image on |secondDevice|
+ wgpu::Texture wrappedTexture = WrapVulkanImage(secondDevice, &descriptor, memoryFdA,
+ allocationSizeA, memoryTypeIndexA, {});
+
+ // Draw a non-trivial picture
+ int width = 640, height = 480, pixelSize = 4;
+ uint32_t rowPitch = Align(width * pixelSize, kTextureRowPitchAlignment);
+ uint32_t size = rowPitch * (height - 1) + width * pixelSize;
+ unsigned char data[size];
+ for (int row = 0; row < height; row++) {
+ for (int col = 0; col < width; col++) {
+ float normRow = static_cast<float>(row) / height;
+ float normCol = static_cast<float>(col) / width;
+ float dist = sqrt(normRow * normRow + normCol * normCol) * 3;
+ dist = dist - static_cast<int>(dist);
+ data[4 * (row * width + col)] = static_cast<unsigned char>(dist * 255);
+ data[4 * (row * width + col) + 1] = static_cast<unsigned char>(dist * 255);
+ data[4 * (row * width + col) + 2] = static_cast<unsigned char>(dist * 255);
+ data[4 * (row * width + col) + 3] = 255;
+ }
+ }
+
+ // Write the picture
+ {
+ wgpu::Buffer copySrcBuffer =
+ utils::CreateBufferFromData(secondDevice, data, size, wgpu::BufferUsage::CopySrc);
+ wgpu::BufferCopyView copySrc = utils::CreateBufferCopyView(copySrcBuffer, 0, rowPitch, 0);
+ wgpu::TextureCopyView copyDst =
+ utils::CreateTextureCopyView(wrappedTexture, 0, 0, {0, 0, 0});
+ wgpu::Extent3D copySize = {width, height, 1};
+
wgpu::CommandEncoder encoder = secondDevice.CreateCommandEncoder();
encoder.CopyBufferToTexture(©Src, ©Dst, ©Size);
wgpu::CommandBuffer commands = encoder.Finish();
secondDeviceQueue.Submit(1, &commands);
-
- // Re-import back into |device|, waiting on |secondDevice|'s signal
- signalFd = dawn_native::vulkan::ExportSignalSemaphoreOpaqueFD(
- secondDevice.Get(), secondDeviceWrappedTexture.Get());
- memoryFd = GetMemoryFd(deviceVk, defaultAllocation);
-
- wgpu::Texture nextWrappedTexture =
- WrapVulkanImage(device, &defaultDescriptor, memoryFd, defaultAllocationSize,
- defaultMemoryTypeIndex, {signalFd});
-
- // Verify |nextWrappedTexture| contains the color from our copy
- EXPECT_PIXEL_RGBA8_EQ(RGBA8(1, 2, 3, 4), nextWrappedTexture, 0, 0);
-
- IgnoreSignalSemaphore(device, nextWrappedTexture);
}
- // Import a texture from |secondDevice|
- // Issue a copy of the imported texture inside |device| to |copyDstTexture|
- // Issue second copy to |secondCopyDstTexture|
- // Verify the clear color from |secondDevice| is visible in both copies
- TEST_P(VulkanImageWrappingUsageTests, DoubleTextureUsage) {
- DAWN_SKIP_TEST_IF(UsesWire());
+ int signalFd = dawn_native::vulkan::ExportSignalSemaphoreOpaqueFD(secondDevice.Get(),
+ wrappedTexture.Get());
+ int memoryFd = GetMemoryFd(secondDeviceVk, allocationA);
- // Import the image on |secondDevice|
- wgpu::Texture wrappedTexture =
- WrapVulkanImage(secondDevice, &defaultDescriptor, defaultFd, defaultAllocationSize,
- defaultMemoryTypeIndex, {});
+ // Import the image on |device|
+ wgpu::Texture nextWrappedTexture = WrapVulkanImage(
+ device, &descriptor, memoryFd, allocationSizeA, memoryTypeIndexA, {signalFd});
- // Clear |wrappedTexture| on |secondDevice|
- ClearImage(secondDevice, wrappedTexture, {1 / 255.0f, 2 / 255.0f, 3 / 255.0f, 4 / 255.0f});
+ // Copy the image into a buffer for comparison
+ wgpu::BufferDescriptor copyDesc;
+ copyDesc.size = size;
+ copyDesc.usage = wgpu::BufferUsage::CopySrc | wgpu::BufferUsage::CopyDst;
+ wgpu::Buffer copyDstBuffer = device.CreateBuffer(©Desc);
+ {
+ wgpu::TextureCopyView copySrc =
+ utils::CreateTextureCopyView(nextWrappedTexture, 0, 0, {0, 0, 0});
+ wgpu::BufferCopyView copyDst = utils::CreateBufferCopyView(copyDstBuffer, 0, rowPitch, 0);
- int signalFd = dawn_native::vulkan::ExportSignalSemaphoreOpaqueFD(secondDevice.Get(),
- wrappedTexture.Get());
+ wgpu::Extent3D copySize = {width, height, 1};
- // Import the image to |device|, making sure we wait on |signalFd|
- int memoryFd = GetMemoryFd(deviceVk, defaultAllocation);
- wgpu::Texture deviceWrappedTexture =
- WrapVulkanImage(device, &defaultDescriptor, memoryFd, defaultAllocationSize,
- defaultMemoryTypeIndex, {signalFd});
-
- // Create a second texture on |device|
- wgpu::Texture copyDstTexture = device.CreateTexture(&defaultDescriptor);
-
- // Create a third texture on |device|
- wgpu::Texture secondCopyDstTexture = device.CreateTexture(&defaultDescriptor);
-
- // Copy |deviceWrappedTexture| into |copyDstTexture|
- SimpleCopyTextureToTexture(device, queue, deviceWrappedTexture, copyDstTexture);
-
- // Copy |deviceWrappedTexture| into |secondCopyDstTexture|
- SimpleCopyTextureToTexture(device, queue, deviceWrappedTexture, secondCopyDstTexture);
-
- // Verify |copyDstTexture| sees changes from |secondDevice|
- EXPECT_PIXEL_RGBA8_EQ(RGBA8(1, 2, 3, 4), copyDstTexture, 0, 0);
-
- // Verify |secondCopyDstTexture| sees changes from |secondDevice|
- EXPECT_PIXEL_RGBA8_EQ(RGBA8(1, 2, 3, 4), secondCopyDstTexture, 0, 0);
-
- IgnoreSignalSemaphore(device, deviceWrappedTexture);
+ wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
+ encoder.CopyTextureToBuffer(©Src, ©Dst, ©Size);
+ wgpu::CommandBuffer commands = encoder.Finish();
+ queue.Submit(1, &commands);
}
- // Tex A on device 3 (external export)
- // Tex B on device 2 (external export)
- // Tex C on device 1 (external export)
- // Clear color for A on device 3
- // Copy A->B on device 3
- // Copy B->C on device 2 (wait on B from previous op)
- // Copy C->D on device 1 (wait on C from previous op)
- // Verify D has same color as A
- TEST_P(VulkanImageWrappingUsageTests, ChainTextureCopy) {
- DAWN_SKIP_TEST_IF(UsesWire());
+ // Check the image is not corrupted on |device|
+ EXPECT_BUFFER_U32_RANGE_EQ(reinterpret_cast<uint32_t*>(data), copyDstBuffer, 0, size / 4);
- // Close |defaultFd| since this test doesn't import it anywhere
- close(defaultFd);
+ IgnoreSignalSemaphore(device, nextWrappedTexture);
+ secondDeviceVk->GetFencedDeleter()->DeleteWhenUnused(imageA);
+ secondDeviceVk->GetFencedDeleter()->DeleteWhenUnused(allocationA);
+}
- // device 1 = |device|
- // device 2 = |secondDevice|
- // Create device 3
- dawn_native::vulkan::Device* thirdDeviceVk = reinterpret_cast<dawn_native::vulkan::Device*>(
- backendAdapter->CreateDevice(&deviceDescriptor));
- wgpu::Device thirdDevice =
- wgpu::Device::Acquire(reinterpret_cast<WGPUDevice>(thirdDeviceVk));
-
- // Make queue for device 2 and 3
- wgpu::Queue secondDeviceQueue = secondDevice.CreateQueue();
- wgpu::Queue thirdDeviceQueue = thirdDevice.CreateQueue();
-
- // Allocate memory for A, B, C
- VkImage imageA;
- VkDeviceMemory allocationA;
- int memoryFdA;
- VkDeviceSize allocationSizeA;
- uint32_t memoryTypeIndexA;
- CreateBindExportImage(thirdDeviceVk, 1, 1, VK_FORMAT_R8G8B8A8_UNORM, &imageA, &allocationA,
- &allocationSizeA, &memoryTypeIndexA, &memoryFdA);
-
- VkImage imageB;
- VkDeviceMemory allocationB;
- int memoryFdB;
- VkDeviceSize allocationSizeB;
- uint32_t memoryTypeIndexB;
- CreateBindExportImage(secondDeviceVk, 1, 1, VK_FORMAT_R8G8B8A8_UNORM, &imageB, &allocationB,
- &allocationSizeB, &memoryTypeIndexB, &memoryFdB);
-
- VkImage imageC;
- VkDeviceMemory allocationC;
- int memoryFdC;
- VkDeviceSize allocationSizeC;
- uint32_t memoryTypeIndexC;
- CreateBindExportImage(deviceVk, 1, 1, VK_FORMAT_R8G8B8A8_UNORM, &imageC, &allocationC,
- &allocationSizeC, &memoryTypeIndexC, &memoryFdC);
-
- // Import TexA, TexB on device 3
- wgpu::Texture wrappedTexADevice3 = WrapVulkanImage(
- thirdDevice, &defaultDescriptor, memoryFdA, allocationSizeA, memoryTypeIndexA, {});
-
- wgpu::Texture wrappedTexBDevice3 = WrapVulkanImage(
- thirdDevice, &defaultDescriptor, memoryFdB, allocationSizeB, memoryTypeIndexB, {});
-
- // Clear TexA
- ClearImage(thirdDevice, wrappedTexADevice3,
- {1 / 255.0f, 2 / 255.0f, 3 / 255.0f, 4 / 255.0f});
-
- // Copy A->B
- SimpleCopyTextureToTexture(thirdDevice, thirdDeviceQueue, wrappedTexADevice3,
- wrappedTexBDevice3);
-
- int signalFdTexBDevice3 = dawn_native::vulkan::ExportSignalSemaphoreOpaqueFD(
- thirdDevice.Get(), wrappedTexBDevice3.Get());
- IgnoreSignalSemaphore(thirdDevice, wrappedTexADevice3);
-
- // Import TexB, TexC on device 2
- memoryFdB = GetMemoryFd(secondDeviceVk, allocationB);
- wgpu::Texture wrappedTexBDevice2 =
- WrapVulkanImage(secondDevice, &defaultDescriptor, memoryFdB, allocationSizeB,
- memoryTypeIndexB, {signalFdTexBDevice3});
-
- wgpu::Texture wrappedTexCDevice2 = WrapVulkanImage(
- secondDevice, &defaultDescriptor, memoryFdC, allocationSizeC, memoryTypeIndexC, {});
-
- // Copy B->C on device 2
- SimpleCopyTextureToTexture(secondDevice, secondDeviceQueue, wrappedTexBDevice2,
- wrappedTexCDevice2);
-
- int signalFdTexCDevice2 = dawn_native::vulkan::ExportSignalSemaphoreOpaqueFD(
- secondDevice.Get(), wrappedTexCDevice2.Get());
- IgnoreSignalSemaphore(secondDevice, wrappedTexBDevice2);
-
- // Import TexC on device 1
- memoryFdC = GetMemoryFd(deviceVk, allocationC);
- wgpu::Texture wrappedTexCDevice1 =
- WrapVulkanImage(device, &defaultDescriptor, memoryFdC, allocationSizeC,
- memoryTypeIndexC, {signalFdTexCDevice2});
-
- // Create TexD on device 1
- wgpu::Texture texD = device.CreateTexture(&defaultDescriptor);
-
- // Copy C->D on device 1
- SimpleCopyTextureToTexture(device, queue, wrappedTexCDevice1, texD);
-
- // Verify D matches clear color
- EXPECT_PIXEL_RGBA8_EQ(RGBA8(1, 2, 3, 4), texD, 0, 0);
-
- thirdDeviceVk->GetFencedDeleter()->DeleteWhenUnused(imageA);
- thirdDeviceVk->GetFencedDeleter()->DeleteWhenUnused(allocationA);
- secondDeviceVk->GetFencedDeleter()->DeleteWhenUnused(imageB);
- secondDeviceVk->GetFencedDeleter()->DeleteWhenUnused(allocationB);
- deviceVk->GetFencedDeleter()->DeleteWhenUnused(imageC);
- deviceVk->GetFencedDeleter()->DeleteWhenUnused(allocationC);
-
- IgnoreSignalSemaphore(device, wrappedTexCDevice1);
- }
-
- // Tests a larger image is preserved when importing
- // TODO(http://crbug.com/dawn/206): This fails on AMD
- TEST_P(VulkanImageWrappingUsageTests, LargerImage) {
- DAWN_SKIP_TEST_IF(UsesWire() || IsAMD());
-
- close(defaultFd);
-
- wgpu::TextureDescriptor descriptor;
- descriptor.dimension = wgpu::TextureDimension::e2D;
- descriptor.size.width = 640;
- descriptor.size.height = 480;
- descriptor.size.depth = 1;
- descriptor.arrayLayerCount = 1;
- descriptor.sampleCount = 1;
- descriptor.format = wgpu::TextureFormat::BGRA8Unorm;
- descriptor.mipLevelCount = 1;
- descriptor.usage = wgpu::TextureUsage::CopyDst | wgpu::TextureUsage::CopySrc;
-
- // Fill memory with textures to trigger layout issues on AMD
- std::vector<wgpu::Texture> textures;
- for (int i = 0; i < 20; i++) {
- textures.push_back(device.CreateTexture(&descriptor));
- }
-
- wgpu::Queue secondDeviceQueue = secondDevice.CreateQueue();
-
- // Make an image on |secondDevice|
- VkImage imageA;
- VkDeviceMemory allocationA;
- int memoryFdA;
- VkDeviceSize allocationSizeA;
- uint32_t memoryTypeIndexA;
- CreateBindExportImage(secondDeviceVk, 640, 480, VK_FORMAT_R8G8B8A8_UNORM, &imageA,
- &allocationA, &allocationSizeA, &memoryTypeIndexA, &memoryFdA);
-
- // Import the image on |secondDevice|
- wgpu::Texture wrappedTexture = WrapVulkanImage(secondDevice, &descriptor, memoryFdA,
- allocationSizeA, memoryTypeIndexA, {});
-
- // Draw a non-trivial picture
- int width = 640, height = 480, pixelSize = 4;
- uint32_t rowPitch = Align(width * pixelSize, kTextureRowPitchAlignment);
- uint32_t size = rowPitch * (height - 1) + width * pixelSize;
- unsigned char data[size];
- for (int row = 0; row < height; row++) {
- for (int col = 0; col < width; col++) {
- float normRow = static_cast<float>(row) / height;
- float normCol = static_cast<float>(col) / width;
- float dist = sqrt(normRow * normRow + normCol * normCol) * 3;
- dist = dist - static_cast<int>(dist);
- data[4 * (row * width + col)] = static_cast<unsigned char>(dist * 255);
- data[4 * (row * width + col) + 1] = static_cast<unsigned char>(dist * 255);
- data[4 * (row * width + col) + 2] = static_cast<unsigned char>(dist * 255);
- data[4 * (row * width + col) + 3] = 255;
- }
- }
-
- // Write the picture
- {
- wgpu::Buffer copySrcBuffer =
- utils::CreateBufferFromData(secondDevice, data, size, wgpu::BufferUsage::CopySrc);
- wgpu::BufferCopyView copySrc =
- utils::CreateBufferCopyView(copySrcBuffer, 0, rowPitch, 0);
- wgpu::TextureCopyView copyDst =
- utils::CreateTextureCopyView(wrappedTexture, 0, 0, {0, 0, 0});
- wgpu::Extent3D copySize = {width, height, 1};
-
- wgpu::CommandEncoder encoder = secondDevice.CreateCommandEncoder();
- encoder.CopyBufferToTexture(©Src, ©Dst, ©Size);
- wgpu::CommandBuffer commands = encoder.Finish();
- secondDeviceQueue.Submit(1, &commands);
- }
-
- int signalFd = dawn_native::vulkan::ExportSignalSemaphoreOpaqueFD(secondDevice.Get(),
- wrappedTexture.Get());
- int memoryFd = GetMemoryFd(secondDeviceVk, allocationA);
-
- // Import the image on |device|
- wgpu::Texture nextWrappedTexture = WrapVulkanImage(
- device, &descriptor, memoryFd, allocationSizeA, memoryTypeIndexA, {signalFd});
-
- // Copy the image into a buffer for comparison
- wgpu::BufferDescriptor copyDesc;
- copyDesc.size = size;
- copyDesc.usage = wgpu::BufferUsage::CopySrc | wgpu::BufferUsage::CopyDst;
- wgpu::Buffer copyDstBuffer = device.CreateBuffer(©Desc);
- {
- wgpu::TextureCopyView copySrc =
- utils::CreateTextureCopyView(nextWrappedTexture, 0, 0, {0, 0, 0});
- wgpu::BufferCopyView copyDst =
- utils::CreateBufferCopyView(copyDstBuffer, 0, rowPitch, 0);
-
- wgpu::Extent3D copySize = {width, height, 1};
-
- wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
- encoder.CopyTextureToBuffer(©Src, ©Dst, ©Size);
- wgpu::CommandBuffer commands = encoder.Finish();
- queue.Submit(1, &commands);
- }
-
- // Check the image is not corrupted on |device|
- EXPECT_BUFFER_U32_RANGE_EQ(reinterpret_cast<uint32_t*>(data), copyDstBuffer, 0, size / 4);
-
- IgnoreSignalSemaphore(device, nextWrappedTexture);
- secondDeviceVk->GetFencedDeleter()->DeleteWhenUnused(imageA);
- secondDeviceVk->GetFencedDeleter()->DeleteWhenUnused(allocationA);
- }
-
- DAWN_INSTANTIATE_TEST(VulkanImageWrappingValidationTests, VulkanBackend);
- DAWN_INSTANTIATE_TEST(VulkanImageWrappingUsageTests, VulkanBackend);
-
-}} // namespace dawn_native::vulkan
+DAWN_INSTANTIATE_TEST(VulkanImageWrappingValidationTests, VulkanBackend);
+DAWN_INSTANTIATE_TEST(VulkanImageWrappingUsageTests, VulkanBackend);