mirror of
https://github.com/encounter/dawn-cmake.git
synced 2025-05-13 19:01:24 +00:00
If these extern variables are initialized after DAWN_INSTANTIATE_TEST, they will be zero. Change them to be function calls instead. Since they're function calls, fold in arguments from ForceToggles to enable/disable toggles. Bug: dawn:341 Change-Id: I1aeaa1e535a0a003977e8ce7ab3d5278c5d81281 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/16162 Reviewed-by: Mark Henderson <mehe@google.com> Reviewed-by: Corentin Wallez <cwallez@chromium.org> Commit-Queue: Austin Eng <enga@chromium.org>
1033 lines
47 KiB
C++
1033 lines
47 KiB
C++
// Copyright 2019 The Dawn Authors
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
#include "common/Math.h"
|
|
#include "tests/DawnTest.h"
|
|
|
|
#include "common/vulkan_platform.h"
|
|
#include "dawn_native/VulkanBackend.h"
|
|
#include "dawn_native/vulkan/AdapterVk.h"
|
|
#include "dawn_native/vulkan/DeviceVk.h"
|
|
#include "dawn_native/vulkan/FencedDeleter.h"
|
|
#include "dawn_native/vulkan/ResourceMemoryAllocatorVk.h"
|
|
#include "dawn_native/vulkan/TextureVk.h"
|
|
#include "utils/SystemUtils.h"
|
|
#include "utils/WGPUHelpers.h"
|
|
|
|
namespace dawn_native { namespace vulkan {
|
|
|
|
namespace {
|
|
|
|
class VulkanImageWrappingTestBase : public DawnTest {
|
|
public:
|
|
void TestSetUp() override {
|
|
if (UsesWire()) {
|
|
return;
|
|
}
|
|
|
|
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* 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;
|
|
}
|
|
|
|
void TearDown() override {
|
|
if (UsesWire()) {
|
|
VulkanImageWrappingTestBase::TearDown();
|
|
return;
|
|
}
|
|
|
|
deviceVk->GetFencedDeleter()->DeleteWhenUnused(defaultImage);
|
|
deviceVk->GetFencedDeleter()->DeleteWhenUnused(defaultAllocation);
|
|
VulkanImageWrappingTestBase::TearDown();
|
|
}
|
|
|
|
protected:
|
|
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);
|
|
}
|
|
|
|
// 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;
|
|
}
|
|
|
|
void TearDown() override {
|
|
if (UsesWire()) {
|
|
VulkanImageWrappingTestBase::TearDown();
|
|
return;
|
|
}
|
|
|
|
deviceVk->GetFencedDeleter()->DeleteWhenUnused(defaultImage);
|
|
deviceVk->GetFencedDeleter()->DeleteWhenUnused(defaultAllocation);
|
|
VulkanImageWrappingTestBase::TearDown();
|
|
}
|
|
|
|
protected:
|
|
wgpu::Device secondDevice;
|
|
dawn_native::vulkan::Device* secondDeviceVk;
|
|
|
|
dawn_native::vulkan::Adapter* backendAdapter;
|
|
dawn_native::DeviceDescriptor deviceDescriptor;
|
|
|
|
wgpu::TextureDescriptor defaultDescriptor;
|
|
VkImage defaultImage;
|
|
VkDeviceMemory defaultAllocation;
|
|
VkDeviceSize defaultAllocationSize;
|
|
uint32_t defaultMemoryTypeIndex;
|
|
int defaultFd;
|
|
|
|
// Clear a texture on a given device
|
|
void ClearImage(wgpu::Device device, wgpu::Texture wrappedTexture, wgpu::Color clearColor) {
|
|
wgpu::TextureView wrappedView = wrappedTexture.CreateView();
|
|
|
|
// Submit a clear operation
|
|
utils::ComboRenderPassDescriptor renderPassDescriptor({wrappedView}, {});
|
|
renderPassDescriptor.cColorAttachments[0].clearColor = clearColor;
|
|
|
|
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
|
|
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPassDescriptor);
|
|
pass.EndPass();
|
|
|
|
wgpu::CommandBuffer commands = encoder.Finish();
|
|
|
|
wgpu::Queue queue = device.CreateQueue();
|
|
queue.Submit(1, &commands);
|
|
}
|
|
|
|
// 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};
|
|
|
|
wgpu::TextureCopyView copyDst;
|
|
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);
|
|
}
|
|
|
|
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
|