diff --git a/BUILD.gn b/BUILD.gn index e2fa87ef61..7bf9726579 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -1005,10 +1005,8 @@ source_set("dawn_white_box_tests_sources") { if (dawn_enable_vulkan) { deps += [ "third_party:vulkan_headers" ] - if (is_chromeos) { - sources += [ "src/tests/white_box/VulkanImageWrappingTestsDmaBuf.cpp" ] - } else if (is_linux) { - sources += [ "src/tests/white_box/VulkanImageWrappingTestsOpaqueFD.cpp" ] + if (is_linux) { + sources += [ "src/tests/white_box/VulkanImageWrappingTests.cpp" ] } if (dawn_enable_error_injection) { @@ -1064,10 +1062,6 @@ test("dawn_end2end_tests") { if (dawn_enable_opengl) { deps += [ ":dawn_glfw" ] } - - if (is_chromeos) { - libs += [ "gbm" ] - } } test("dawn_perf_tests") { diff --git a/src/tests/white_box/VulkanImageWrappingTestsOpaqueFD.cpp b/src/tests/white_box/VulkanImageWrappingTests.cpp similarity index 100% rename from src/tests/white_box/VulkanImageWrappingTestsOpaqueFD.cpp rename to src/tests/white_box/VulkanImageWrappingTests.cpp diff --git a/src/tests/white_box/VulkanImageWrappingTestsDmaBuf.cpp b/src/tests/white_box/VulkanImageWrappingTestsDmaBuf.cpp deleted file mode 100644 index ca995ae425..0000000000 --- a/src/tests/white_box/VulkanImageWrappingTestsDmaBuf.cpp +++ /dev/null @@ -1,857 +0,0 @@ -// Copyright 2020 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 "tests/DawnTest.h" - -#include "common/Math.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" - -#include -#include -#include - -namespace dawn_native { namespace vulkan { - - namespace { - - class VulkanImageWrappingTestBase : public DawnTest { - public: - void TestSetUp() override { - DAWN_SKIP_TEST_IF(UsesWire()); - - gbmDevice = CreateGbmDevice(); - deviceVk = reinterpret_cast(device.Get()); - - defaultGbmBo = CreateGbmBo(1, 1, true /* linear */); - defaultStride = gbm_bo_get_stride_for_plane(defaultGbmBo, 0); - defaultModifier = gbm_bo_get_modifier(defaultGbmBo); - defaultFd = gbm_bo_get_fd(defaultGbmBo); - - 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()) - return; - - gbm_bo_destroy(defaultGbmBo); - gbm_device_destroy(gbmDevice); - } - - gbm_device* CreateGbmDevice() { - // Render nodes [1] are the primary interface for communicating with the GPU on - // devices that support DRM. The actual filename of the render node is - // implementation-specific, so we must scan through all possible filenames to find - // one that we can use [2]. - // - // [1] https://dri.freedesktop.org/docs/drm/gpu/drm-uapi.html#render-nodes - // [2] - // https://cs.chromium.org/chromium/src/ui/ozone/platform/wayland/gpu/drm_render_node_path_finder.cc - const uint32_t kRenderNodeStart = 128; - const uint32_t kRenderNodeEnd = kRenderNodeStart + 16; - const std::string kRenderNodeTemplate = "/dev/dri/renderD"; - - int renderNodeFd = -1; - for (uint32_t i = kRenderNodeStart; i < kRenderNodeEnd; i++) { - std::string renderNode = kRenderNodeTemplate + std::to_string(i); - renderNodeFd = open(renderNode.c_str(), O_RDWR); - if (renderNodeFd >= 0) - break; - } - EXPECT_GE(renderNodeFd, 0) << "Failed to get file descriptor for render node"; - - gbm_device* gbmDevice = gbm_create_device(renderNodeFd); - EXPECT_NE(gbmDevice, nullptr) << "Failed to create GBM device"; - return gbmDevice; - } - - gbm_bo* CreateGbmBo(uint32_t width, uint32_t height, bool linear) { - uint32_t flags = GBM_BO_USE_RENDERING; - if (linear) - flags |= GBM_BO_USE_LINEAR; - gbm_bo* gbmBo = gbm_bo_create(gbmDevice, width, height, GBM_FORMAT_XBGR8888, flags); - EXPECT_NE(gbmBo, nullptr) << "Failed to create GBM buffer object"; - return gbmBo; - } - - wgpu::Texture WrapVulkanImage(wgpu::Device device, - const wgpu::TextureDescriptor* textureDescriptor, - int memoryFd, - uint32_t stride, - uint64_t drmModifier, - std::vector waitFDs, - bool isCleared = true, - bool expectValid = true) { - dawn_native::vulkan::ExternalImageDescriptorDmaBuf descriptor; - descriptor.cTextureDescriptor = - reinterpret_cast(textureDescriptor); - descriptor.isCleared = isCleared; - descriptor.stride = stride; - descriptor.drmModifier = drmModifier; - 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; - gbm_device* gbmDevice; - wgpu::TextureDescriptor defaultDescriptor; - gbm_bo* defaultGbmBo; - int defaultFd; - uint32_t defaultStride; - uint64_t defaultModifier; - }; - - } // anonymous namespace - - using VulkanImageWrappingValidationTests = VulkanImageWrappingTestBase; - - // Test no error occurs if the import is valid - TEST_P(VulkanImageWrappingValidationTests, SuccessfulImport) { - wgpu::Texture texture = WrapVulkanImage(device, &defaultDescriptor, defaultFd, - defaultStride, defaultModifier, {}, true, true); - EXPECT_NE(texture.Get(), nullptr); - IgnoreSignalSemaphore(device, texture); - } - - // Test an error occurs if the texture descriptor is missing - TEST_P(VulkanImageWrappingValidationTests, MissingTextureDescriptor) { - ASSERT_DEVICE_ERROR(wgpu::Texture texture = - WrapVulkanImage(device, nullptr, defaultFd, defaultStride, - defaultModifier, {}, true, false)); - EXPECT_EQ(texture.Get(), nullptr); - close(defaultFd); - } - - // Test an error occurs if the texture descriptor is invalid - TEST_P(VulkanImageWrappingValidationTests, InvalidTextureDescriptor) { - wgpu::ChainedStruct chainedDescriptor; - defaultDescriptor.nextInChain = &chainedDescriptor; - - ASSERT_DEVICE_ERROR(wgpu::Texture texture = - WrapVulkanImage(device, &defaultDescriptor, defaultFd, - defaultStride, defaultModifier, {}, true, false)); - EXPECT_EQ(texture.Get(), nullptr); - close(defaultFd); - } - - // Test an error occurs if the descriptor dimension isn't 2D - TEST_P(VulkanImageWrappingValidationTests, InvalidTextureDimension) { - defaultDescriptor.dimension = wgpu::TextureDimension::e1D; - - ASSERT_DEVICE_ERROR(wgpu::Texture texture = - WrapVulkanImage(device, &defaultDescriptor, defaultFd, - defaultStride, defaultModifier, {}, true, false)); - EXPECT_EQ(texture.Get(), nullptr); - close(defaultFd); - } - - // Test an error occurs if the descriptor mip level count isn't 1 - TEST_P(VulkanImageWrappingValidationTests, InvalidMipLevelCount) { - defaultDescriptor.mipLevelCount = 2; - - ASSERT_DEVICE_ERROR(wgpu::Texture texture = - WrapVulkanImage(device, &defaultDescriptor, defaultFd, - defaultStride, defaultModifier, {}, true, false)); - EXPECT_EQ(texture.Get(), nullptr); - close(defaultFd); - } - - // Test an error occurs if the descriptor array layer count isn't 1 - TEST_P(VulkanImageWrappingValidationTests, InvalidArrayLayerCount) { - defaultDescriptor.arrayLayerCount = 2; - - ASSERT_DEVICE_ERROR(wgpu::Texture texture = - WrapVulkanImage(device, &defaultDescriptor, defaultFd, - defaultStride, defaultModifier, {}, true, false)); - EXPECT_EQ(texture.Get(), nullptr); - close(defaultFd); - } - - // Test an error occurs if the descriptor sample count isn't 1 - TEST_P(VulkanImageWrappingValidationTests, InvalidSampleCount) { - defaultDescriptor.sampleCount = 4; - - ASSERT_DEVICE_ERROR(wgpu::Texture texture = - WrapVulkanImage(device, &defaultDescriptor, defaultFd, - defaultStride, defaultModifier, {}, true, false)); - EXPECT_EQ(texture.Get(), nullptr); - close(defaultFd); - } - - // Test an error occurs if we try to export the signal semaphore twice - TEST_P(VulkanImageWrappingValidationTests, DoubleSignalSemaphoreExport) { - wgpu::Texture texture = WrapVulkanImage(device, &defaultDescriptor, defaultFd, - defaultStride, defaultModifier, {}, true, true); - ASSERT_NE(texture.Get(), nullptr); - IgnoreSignalSemaphore(device, texture); - ASSERT_DEVICE_ERROR(int fd = dawn_native::vulkan::ExportSignalSemaphoreOpaqueFD( - device.Get(), texture.Get())); - ASSERT_EQ(fd, -1); - } - - // Test an error occurs if we try to export the signal semaphore from a normal texture - TEST_P(VulkanImageWrappingValidationTests, NormalTextureSignalSemaphoreExport) { - close(defaultFd); - - 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) { - close(defaultFd); - - 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(deviceVk->GetAdapter()); - deviceDescriptor.forceEnabledToggles = GetParam().forceEnabledWorkarounds; - deviceDescriptor.forceDisabledToggles = GetParam().forceDisabledWorkarounds; - - secondDeviceVk = reinterpret_cast( - backendAdapter->CreateDevice(&deviceDescriptor)); - secondDevice = wgpu::Device::Acquire(reinterpret_cast(secondDeviceVk)); - } - - protected: - dawn_native::vulkan::Adapter* backendAdapter; - dawn_native::DeviceDescriptor deviceDescriptor; - - wgpu::Device secondDevice; - dawn_native::vulkan::Device* secondDeviceVk; - - // 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; - renderPassDescriptor.cColorAttachments[0].loadOp = wgpu::LoadOp::Clear; - - 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) { - // Import the image on |secondDevice| - wgpu::Texture wrappedTexture = WrapVulkanImage(secondDevice, &defaultDescriptor, defaultFd, - defaultStride, defaultModifier, {}); - - // Clear |wrappedTexture| on |secondDevice| - ClearImage(secondDevice, wrappedTexture, {1 / 255.0f, 2 / 255.0f, 3 / 255.0f, 4 / 255.0f}); - - int signalFd = dawn_native::vulkan::ExportSignalSemaphoreOpaqueFD(secondDevice.Get(), - wrappedTexture.Get()); - - // Import the image to |device|, making sure we wait on signalFd - int nextFd = gbm_bo_get_fd(defaultGbmBo); - wgpu::Texture nextWrappedTexture = WrapVulkanImage( - device, &defaultDescriptor, nextFd, defaultStride, defaultModifier, {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) { - // Import the image on |device| - wgpu::Texture wrappedTextureAlias = WrapVulkanImage(device, &defaultDescriptor, defaultFd, - defaultStride, defaultModifier, {}); - - // Import the image on |secondDevice| - int nextFd = gbm_bo_get_fd(defaultGbmBo); - wgpu::Texture wrappedTexture = WrapVulkanImage(secondDevice, &defaultDescriptor, nextFd, - defaultStride, defaultModifier, {}); - - // Clear |wrappedTexture| on |secondDevice| - ClearImage(secondDevice, wrappedTexture, {1 / 255.0f, 2 / 255.0f, 3 / 255.0f, 4 / 255.0f}); - - int signalFd = dawn_native::vulkan::ExportSignalSemaphoreOpaqueFD(secondDevice.Get(), - wrappedTexture.Get()); - - // Import the image to |device|, making sure we wait on signalFd - nextFd = gbm_bo_get_fd(defaultGbmBo); - wgpu::Texture nextWrappedTexture = WrapVulkanImage( - device, &defaultDescriptor, nextFd, defaultStride, defaultModifier, {signalFd}); - - // Verify |device| sees the changes from |secondDevice| (waits) - EXPECT_PIXEL_RGBA8_EQ(RGBA8(1, 2, 3, 4), nextWrappedTexture, 0, 0); - - // Verify aliased texture sees changes from |secondDevice| (without waiting!) - EXPECT_PIXEL_RGBA8_EQ(RGBA8(1, 2, 3, 4), wrappedTextureAlias, 0, 0); - - IgnoreSignalSemaphore(device, nextWrappedTexture); - IgnoreSignalSemaphore(device, wrappedTextureAlias); - } - - // 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) { - // Import the image on |secondDevice| - wgpu::Texture wrappedTexture = WrapVulkanImage(secondDevice, &defaultDescriptor, defaultFd, - defaultStride, defaultModifier, {}); - - // Clear |wrappedTexture| on |secondDevice| - ClearImage(secondDevice, wrappedTexture, {1 / 255.0f, 2 / 255.0f, 3 / 255.0f, 4 / 255.0f}); - - int signalFd = dawn_native::vulkan::ExportSignalSemaphoreOpaqueFD(secondDevice.Get(), - wrappedTexture.Get()); - - // Import the image to |device|, making sure we wait on signalFd - int nextFd = gbm_bo_get_fd(defaultGbmBo); - wgpu::Texture nextWrappedTexture = WrapVulkanImage( - device, &defaultDescriptor, nextFd, defaultStride, defaultModifier, {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| - // Clear the texture on |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) { - // Import the image on |secondDevice| - wgpu::Texture wrappedTexture = WrapVulkanImage(secondDevice, &defaultDescriptor, defaultFd, - defaultStride, defaultModifier, {}); - - // Clear |wrappedTexture| on |secondDevice| - ClearImage(secondDevice, wrappedTexture, {1 / 255.0f, 2 / 255.0f, 3 / 255.0f, 4 / 255.0f}); - - int signalFd = dawn_native::vulkan::ExportSignalSemaphoreOpaqueFD(secondDevice.Get(), - wrappedTexture.Get()); - - // Import the image to |device|, making sure we wait on |signalFd| - int nextFd = gbm_bo_get_fd(defaultGbmBo); - wgpu::Texture deviceWrappedTexture = WrapVulkanImage( - device, &defaultDescriptor, nextFd, defaultStride, defaultModifier, {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| - // Clear texture with color A on |device| - // Import same texture into |secondDevice|, waiting on the copy signal - // Clear the new texture with color B on |secondDevice| - // 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) { - // Import the image on |device| - wgpu::Texture wrappedTexture = WrapVulkanImage(device, &defaultDescriptor, defaultFd, - defaultStride, defaultModifier, {}); - - // 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 nextFd = gbm_bo_get_fd(defaultGbmBo); - wgpu::Texture secondDeviceWrappedTexture = WrapVulkanImage( - secondDevice, &defaultDescriptor, nextFd, defaultStride, defaultModifier, {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()); - nextFd = gbm_bo_get_fd(defaultGbmBo); - - wgpu::Texture nextWrappedTexture = WrapVulkanImage( - device, &defaultDescriptor, nextFd, defaultStride, defaultModifier, {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| - // Clear the texture on |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) { - // Import the image on |secondDevice| - wgpu::Texture wrappedTexture = WrapVulkanImage(secondDevice, &defaultDescriptor, defaultFd, - defaultStride, defaultModifier, {}); - - // Clear |wrappedTexture| on |secondDevice| - ClearImage(secondDevice, wrappedTexture, {1 / 255.0f, 2 / 255.0f, 3 / 255.0f, 4 / 255.0f}); - - int signalFd = dawn_native::vulkan::ExportSignalSemaphoreOpaqueFD(secondDevice.Get(), - wrappedTexture.Get()); - - // Import the image to |device|, making sure we wait on |signalFd| - int nextFd = gbm_bo_get_fd(defaultGbmBo); - wgpu::Texture deviceWrappedTexture = WrapVulkanImage( - device, &defaultDescriptor, nextFd, defaultStride, defaultModifier, {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 = 1; - EXPECT_BUFFER_U32_EQ(expected, copyDstBuffer, 0); - - IgnoreSignalSemaphore(device, deviceWrappedTexture); - } - - // Import a texture into |device| - // Clear texture with color A 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) { - // Import the image on |device| - wgpu::Texture wrappedTexture = WrapVulkanImage(device, &defaultDescriptor, defaultFd, - defaultStride, defaultModifier, {}); - - // 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 nextFd = gbm_bo_get_fd(defaultGbmBo); - wgpu::Texture secondDeviceWrappedTexture = WrapVulkanImage( - secondDevice, &defaultDescriptor, nextFd, defaultStride, defaultModifier, {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()); - nextFd = gbm_bo_get_fd(defaultGbmBo); - - wgpu::Texture nextWrappedTexture = WrapVulkanImage( - device, &defaultDescriptor, nextFd, defaultStride, defaultModifier, {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| - // Clear the texture on |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) { - // Import the image on |secondDevice| - wgpu::Texture wrappedTexture = WrapVulkanImage(secondDevice, &defaultDescriptor, defaultFd, - defaultStride, defaultModifier, {}); - - // Clear |wrappedTexture| on |secondDevice| - ClearImage(secondDevice, wrappedTexture, {1 / 255.0f, 2 / 255.0f, 3 / 255.0f, 4 / 255.0f}); - - int signalFd = dawn_native::vulkan::ExportSignalSemaphoreOpaqueFD(secondDevice.Get(), - wrappedTexture.Get()); - - // Import the image to |device|, making sure we wait on |signalFd| - int nextFd = gbm_bo_get_fd(defaultGbmBo); - wgpu::Texture deviceWrappedTexture = WrapVulkanImage( - device, &defaultDescriptor, nextFd, defaultStride, defaultModifier, {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) { - // 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( - backendAdapter->CreateDevice(&deviceDescriptor)); - wgpu::Device thirdDevice = - wgpu::Device::Acquire(reinterpret_cast(thirdDeviceVk)); - - // Make queue for device 2 and 3 - wgpu::Queue secondDeviceQueue = secondDevice.CreateQueue(); - wgpu::Queue thirdDeviceQueue = thirdDevice.CreateQueue(); - - // Create BOs for A, B, C - gbm_bo* gbmBoA = CreateGbmBo(1, 1, true /* linear */); - uint32_t fdA = gbm_bo_get_fd(gbmBoA); - uint32_t strideA = gbm_bo_get_stride_for_plane(gbmBoA, 0); - uint64_t modifierA = gbm_bo_get_modifier(gbmBoA); - - gbm_bo* gbmBoB = CreateGbmBo(1, 1, true /* linear */); - uint32_t fdB = gbm_bo_get_fd(gbmBoB); - uint32_t strideB = gbm_bo_get_stride_for_plane(gbmBoB, 0); - uint64_t modifierB = gbm_bo_get_modifier(gbmBoB); - - gbm_bo* gbmBoC = CreateGbmBo(1, 1, true /* linear */); - uint32_t fdC = gbm_bo_get_fd(gbmBoC); - uint32_t strideC = gbm_bo_get_stride_for_plane(gbmBoC, 0); - uint64_t modifierC = gbm_bo_get_modifier(gbmBoC); - - // Import TexA, TexB on device 3 - wgpu::Texture wrappedTexADevice3 = - WrapVulkanImage(thirdDevice, &defaultDescriptor, fdA, strideA, modifierA, {}); - - wgpu::Texture wrappedTexBDevice3 = - WrapVulkanImage(thirdDevice, &defaultDescriptor, fdB, strideB, modifierB, {}); - - // 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 - fdB = gbm_bo_get_fd(gbmBoB); - wgpu::Texture wrappedTexBDevice2 = WrapVulkanImage( - secondDevice, &defaultDescriptor, fdB, strideB, modifierB, {signalFdTexBDevice3}); - - wgpu::Texture wrappedTexCDevice2 = - WrapVulkanImage(secondDevice, &defaultDescriptor, fdC, strideC, modifierC, {}); - - // 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 - fdC = gbm_bo_get_fd(gbmBoC); - wgpu::Texture wrappedTexCDevice1 = WrapVulkanImage(device, &defaultDescriptor, fdC, strideC, - modifierC, {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); - - IgnoreSignalSemaphore(device, wrappedTexCDevice1); - } - - // Tests a larger image is preserved when importing - TEST_P(VulkanImageWrappingUsageTests, LargerImage) { - 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 - std::vector textures; - for (int i = 0; i < 20; i++) { - textures.push_back(device.CreateTexture(&descriptor)); - } - - wgpu::Queue secondDeviceQueue = secondDevice.CreateQueue(); - - // Make an image on |secondDevice| - gbm_bo* gbmBo = CreateGbmBo(640, 480, false /* linear */); - uint32_t fd = gbm_bo_get_fd(gbmBo); - uint32_t stride = gbm_bo_get_stride_for_plane(gbmBo, 0); - uint64_t modifier = gbm_bo_get_modifier(gbmBo); - - // Import the image on |secondDevice| - wgpu::Texture wrappedTexture = - WrapVulkanImage(secondDevice, &descriptor, fd, stride, modifier, {}); - - // 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(row) / height; - float normCol = static_cast(col) / width; - float dist = sqrt(normRow * normRow + normCol * normCol) * 3; - dist = dist - static_cast(dist); - data[4 * (row * width + col)] = static_cast(dist * 255); - data[4 * (row * width + col) + 1] = static_cast(dist * 255); - data[4 * (row * width + col) + 2] = static_cast(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 nextFd = gbm_bo_get_fd(gbmBo); - - // Import the image on |device| - wgpu::Texture nextWrappedTexture = - WrapVulkanImage(device, &descriptor, nextFd, stride, modifier, {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(data), copyDstBuffer, 0, size / 4); - - IgnoreSignalSemaphore(device, nextWrappedTexture); - } - - DAWN_INSTANTIATE_TEST(VulkanImageWrappingValidationTests, VulkanBackend); - DAWN_INSTANTIATE_TEST(VulkanImageWrappingUsageTests, VulkanBackend); - -}} // namespace dawn_native::vulkan