diff --git a/src/tests/BUILD.gn b/src/tests/BUILD.gn index aab52af377..e62ce65c3f 100644 --- a/src/tests/BUILD.gn +++ b/src/tests/BUILD.gn @@ -492,7 +492,11 @@ source_set("dawn_white_box_tests_sources") { deps += [ "${dawn_root}/third_party/khronos:vulkan_headers" ] if (is_chromeos) { - sources += [ "white_box/VulkanImageWrappingTestsDmaBuf.cpp" ] + sources += [ + "white_box/VulkanImageWrappingTests.cpp", + "white_box/VulkanImageWrappingTests.h", + "white_box/VulkanImageWrappingTests_DmaBuf.cpp", + ] } else if (is_linux) { sources += [ "white_box/VulkanImageWrappingTests.cpp", diff --git a/src/tests/white_box/VulkanImageWrappingTests.cpp b/src/tests/white_box/VulkanImageWrappingTests.cpp index 7cf1df0cc7..3e14da5e85 100644 --- a/src/tests/white_box/VulkanImageWrappingTests.cpp +++ b/src/tests/white_box/VulkanImageWrappingTests.cpp @@ -25,13 +25,6 @@ namespace dawn::native { namespace vulkan { using ExternalTexture = VulkanImageWrappingTestBackend::ExternalTexture; using ExternalSemaphore = VulkanImageWrappingTestBackend::ExternalSemaphore; - ExternalImageDescriptorVkForTesting::ExternalImageDescriptorVkForTesting() - : ExternalImageDescriptorVk(ExternalImageType::OpaqueFD) { - } - ExternalImageExportInfoVkForTesting::ExternalImageExportInfoVkForTesting() - : ExternalImageExportInfoVk(ExternalImageType::OpaqueFD) { - } - namespace { class VulkanImageWrappingTestBase : public DawnTest { diff --git a/src/tests/white_box/VulkanImageWrappingTestsDmaBuf.cpp b/src/tests/white_box/VulkanImageWrappingTestsDmaBuf.cpp deleted file mode 100644 index 709e0bcbaf..0000000000 --- a/src/tests/white_box/VulkanImageWrappingTestsDmaBuf.cpp +++ /dev/null @@ -1,888 +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 - -namespace dawn::native::vulkan { - - namespace { - - class VulkanImageWrappingTestBase : public DawnTest { - protected: - std::vector GetRequiredFeatures() override { - return {wgpu::FeatureName::DawnInternalUsages}; - } - - public: - void SetUp() override { - DawnTest::SetUp(); - DAWN_TEST_UNSUPPORTED_IF(UsesWire()); - - gbmDevice = CreateGbmDevice(); - deviceVk = dawn::native::vulkan::ToBackend(dawn::native::FromAPI(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.mipLevelCount = 1; - defaultDescriptor.usage = wgpu::TextureUsage::RenderAttachment | - wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::CopyDst; - } - - void TearDown() override { - if (UsesWire()) { - DawnTest::TearDown(); - return; - } - - gbm_bo_destroy(defaultGbmBo); - gbm_device_destroy(gbmDevice); - - DawnTest::TearDown(); - } - - 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 dawnDevice, - const wgpu::TextureDescriptor* textureDescriptor, - int memoryFd, - uint32_t stride, - uint64_t drmModifier, - std::vector waitFDs, - bool isInitialized = true, - bool expectValid = true) { - dawn::native::vulkan::ExternalImageDescriptorDmaBuf descriptor; - return WrapVulkanImage(dawnDevice, textureDescriptor, memoryFd, stride, drmModifier, - waitFDs, descriptor.releasedOldLayout, - descriptor.releasedNewLayout, isInitialized, expectValid); - } - - wgpu::Texture WrapVulkanImage(wgpu::Device dawnDevice, - const wgpu::TextureDescriptor* textureDescriptor, - int memoryFd, - uint32_t stride, - uint64_t drmModifier, - std::vector waitFDs, - VkImageLayout releasedOldLayout, - VkImageLayout releasedNewLayout, - bool isInitialized = true, - bool expectValid = true) { - dawn::native::vulkan::ExternalImageDescriptorDmaBuf descriptor; - descriptor.cTextureDescriptor = - reinterpret_cast(textureDescriptor); - descriptor.isInitialized = isInitialized; - descriptor.stride = stride; - descriptor.drmModifier = drmModifier; - descriptor.memoryFD = memoryFd; - descriptor.waitFDs = waitFDs; - descriptor.releasedOldLayout = releasedOldLayout; - descriptor.releasedNewLayout = releasedNewLayout; - - WGPUTexture texture = - dawn::native::vulkan::WrapVulkanImage(dawnDevice.Get(), &descriptor); - - 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::Texture wrappedTexture) { - dawn::native::vulkan::ExternalImageExportInfoDmaBuf exportInfo; - dawn::native::vulkan::ExportVulkanImage(wrappedTexture.Get(), - VK_IMAGE_LAYOUT_GENERAL, &exportInfo); - for (int handle : exportInfo.semaphoreHandles) { - ASSERT_NE(handle, -1); - close(handle); - } - } - - 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(texture); - } - - // Test no error occurs if the import is valid with DawnTextureInternalUsageDescriptor - TEST_P(VulkanImageWrappingValidationTests, SuccessfulImportWithInternalUsageDescriptor) { - wgpu::DawnTextureInternalUsageDescriptor internalDesc = {}; - defaultDescriptor.nextInChain = &internalDesc; - internalDesc.internalUsage = wgpu::TextureUsage::CopySrc; - internalDesc.sType = wgpu::SType::DawnTextureInternalUsageDescriptor; - - wgpu::Texture texture = WrapVulkanImage(device, &defaultDescriptor, defaultFd, - defaultStride, defaultModifier, {}, true, true); - EXPECT_NE(texture.Get(), nullptr); - IgnoreSignalSemaphore(texture); - } - - // Test an error occurs if an invalid sType is the nextInChain - TEST_P(VulkanImageWrappingValidationTests, InvalidTextureDescriptor) { - wgpu::ChainedStruct chainedDescriptor; - chainedDescriptor.sType = wgpu::SType::SurfaceDescriptorFromWindowsSwapChainPanel; - 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 depth isn't 1 - TEST_P(VulkanImageWrappingValidationTests, InvalidDepth) { - defaultDescriptor.size.depthOrArrayLayers = 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(texture); - - dawn::native::vulkan::ExternalImageExportInfoDmaBuf exportInfo; - ASSERT_DEVICE_ERROR(bool success = dawn::native::vulkan::ExportVulkanImage( - texture.Get(), VK_IMAGE_LAYOUT_GENERAL, &exportInfo)); - ASSERT_FALSE(success); - } - - // Test an error occurs if we try to export the signal semaphore from a normal texture - TEST_P(VulkanImageWrappingValidationTests, NormalTextureSignalSemaphoreExport) { - close(defaultFd); - - wgpu::Texture texture = device.CreateTexture(&defaultDescriptor); - ASSERT_NE(texture.Get(), nullptr); - - dawn::native::vulkan::ExternalImageExportInfoDmaBuf exportInfo; - ASSERT_DEVICE_ERROR(bool success = dawn::native::vulkan::ExportVulkanImage( - texture.Get(), VK_IMAGE_LAYOUT_GENERAL, &exportInfo)); - ASSERT_FALSE(success); - } - - // Test an error occurs if we try to export the signal semaphore from a destroyed texture - TEST_P(VulkanImageWrappingValidationTests, DestroyedTextureSignalSemaphoreExport) { - close(defaultFd); - - wgpu::Texture texture = device.CreateTexture(&defaultDescriptor); - ASSERT_NE(texture.Get(), nullptr); - texture.Destroy(); - - dawn::native::vulkan::ExternalImageExportInfoDmaBuf exportInfo; - ASSERT_DEVICE_ERROR(bool success = dawn::native::vulkan::ExportVulkanImage( - texture.Get(), VK_IMAGE_LAYOUT_GENERAL, &exportInfo)); - ASSERT_FALSE(success); - } - - // Fixture to test using external memory textures through different usages. - // These tests are skipped if the harness is using the wire. - class VulkanImageWrappingUsageTests : public VulkanImageWrappingTestBase { - public: - void SetUp() override { - VulkanImageWrappingTestBase::SetUp(); - if (UsesWire()) { - return; - } - - // Create another device based on the original - backendAdapter = dawn::native::vulkan::ToBackend(deviceVk->GetAdapter()); - deviceDescriptor.nextInChain = &togglesDesc; - togglesDesc.forceEnabledToggles = GetParam().forceEnabledWorkarounds.data(); - togglesDesc.forceEnabledTogglesCount = GetParam().forceEnabledWorkarounds.size(); - togglesDesc.forceDisabledToggles = GetParam().forceDisabledWorkarounds.data(); - togglesDesc.forceDisabledTogglesCount = GetParam().forceDisabledWorkarounds.size(); - - secondDeviceVk = - dawn::native::vulkan::ToBackend(backendAdapter->APICreateDevice(&deviceDescriptor)); - secondDevice = wgpu::Device::Acquire(dawn::native::ToAPI(secondDeviceVk)); - } - - protected: - dawn::native::vulkan::Adapter* backendAdapter; - dawn::native::DeviceDescriptor deviceDescriptor; - dawn::native::DawnTogglesDeviceDescriptor togglesDesc; - - wgpu::Device secondDevice; - dawn::native::vulkan::Device* secondDeviceVk; - - // Clear a texture on a given device - void ClearImage(wgpu::Device dawnDevice, - 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 = dawnDevice.CreateCommandEncoder(); - wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPassDescriptor); - pass.EndPass(); - - wgpu::CommandBuffer commands = encoder.Finish(); - - wgpu::Queue queue = dawnDevice.GetQueue(); - queue.Submit(1, &commands); - } - - // Submits a 1x1x1 copy from source to destination - void SimpleCopyTextureToTexture(wgpu::Device dawnDevice, - wgpu::Queue dawnQueue, - wgpu::Texture source, - wgpu::Texture destination) { - wgpu::ImageCopyTexture copySrc = utils::CreateImageCopyTexture(source, 0, {0, 0, 0}); - wgpu::ImageCopyTexture copyDst = - utils::CreateImageCopyTexture(destination, 0, {0, 0, 0}); - - wgpu::Extent3D copySize = {1, 1, 1}; - - wgpu::CommandEncoder encoder = dawnDevice.CreateCommandEncoder(); - encoder.CopyTextureToTexture(©Src, ©Dst, ©Size); - wgpu::CommandBuffer commands = encoder.Finish(); - - dawnQueue.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, {}, - VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); - - // Clear |wrappedTexture| on |secondDevice| - ClearImage(secondDevice, wrappedTexture, {1 / 255.0f, 2 / 255.0f, 3 / 255.0f, 4 / 255.0f}); - - dawn::native::vulkan::ExternalImageExportInfoDmaBuf exportInfo; - dawn::native::vulkan::ExportVulkanImage(wrappedTexture.Get(), - VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, &exportInfo); - - // Import the image to |device|, making sure we wait on signalFd - int nextFd = gbm_bo_get_fd(defaultGbmBo); - wgpu::Texture nextWrappedTexture = - WrapVulkanImage(device, &defaultDescriptor, nextFd, defaultStride, defaultModifier, - exportInfo.semaphoreHandles, exportInfo.releasedOldLayout, - exportInfo.releasedNewLayout); - - // Verify |device| sees the changes from |secondDevice| - EXPECT_PIXEL_RGBA8_EQ(RGBA8(1, 2, 3, 4), nextWrappedTexture, 0, 0); - - IgnoreSignalSemaphore(nextWrappedTexture); - } - - // Clear an image in |secondDevice| - // Verify clear color is not visible in |device| if we import the texture as not cleared - TEST_P(VulkanImageWrappingUsageTests, UninitializedTextureIsCleared) { - // Import the image on |secondDevice| - wgpu::Texture wrappedTexture = WrapVulkanImage( - secondDevice, &defaultDescriptor, defaultFd, defaultStride, defaultModifier, {}, - VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); - - // Clear |wrappedTexture| on |secondDevice| - ClearImage(secondDevice, wrappedTexture, {1 / 255.0f, 2 / 255.0f, 3 / 255.0f, 4 / 255.0f}); - - dawn::native::vulkan::ExternalImageExportInfoDmaBuf exportInfo; - dawn::native::vulkan::ExportVulkanImage(wrappedTexture.Get(), - VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, &exportInfo); - - // Import the image to |device|, making sure we wait on signalFd - int nextFd = gbm_bo_get_fd(defaultGbmBo); - wgpu::Texture nextWrappedTexture = - WrapVulkanImage(device, &defaultDescriptor, nextFd, defaultStride, defaultModifier, - exportInfo.semaphoreHandles, exportInfo.releasedOldLayout, - exportInfo.releasedNewLayout, false); - - // Verify |device| doesn't see the changes from |secondDevice| - EXPECT_PIXEL_RGBA8_EQ(RGBA8(0, 0, 0, 0), nextWrappedTexture, 0, 0); - - IgnoreSignalSemaphore(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, {}, - VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); - - // Clear |wrappedTexture| on |secondDevice| - ClearImage(secondDevice, wrappedTexture, {1 / 255.0f, 2 / 255.0f, 3 / 255.0f, 4 / 255.0f}); - - dawn::native::vulkan::ExternalImageExportInfoDmaBuf exportInfo; - dawn::native::vulkan::ExportVulkanImage(wrappedTexture.Get(), - VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, &exportInfo); - - // Import the image to |device|, making sure we wait on |signalFd| - int nextFd = gbm_bo_get_fd(defaultGbmBo); - wgpu::Texture deviceWrappedTexture = - WrapVulkanImage(device, &defaultDescriptor, nextFd, defaultStride, defaultModifier, - exportInfo.semaphoreHandles, exportInfo.releasedOldLayout, - exportInfo.releasedNewLayout); - - // 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(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, {}, - VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); - - // Clear |wrappedTexture| on |device| - ClearImage(device, wrappedTexture, {5 / 255.0f, 6 / 255.0f, 7 / 255.0f, 8 / 255.0f}); - - dawn::native::vulkan::ExternalImageExportInfoDmaBuf exportInfo; - dawn::native::vulkan::ExportVulkanImage(wrappedTexture.Get(), - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &exportInfo); - - // Import the image to |secondDevice|, making sure we wait on |signalFd| - int nextFd = gbm_bo_get_fd(defaultGbmBo); - wgpu::Texture secondDeviceWrappedTexture = - WrapVulkanImage(secondDevice, &defaultDescriptor, nextFd, defaultStride, - defaultModifier, exportInfo.semaphoreHandles, - exportInfo.releasedOldLayout, exportInfo.releasedNewLayout); - - // 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.GetQueue(); - SimpleCopyTextureToTexture(secondDevice, secondDeviceQueue, copySrcTexture, - secondDeviceWrappedTexture); - - // Re-import back into |device|, waiting on |secondDevice|'s signal - dawn::native::vulkan::ExternalImageExportInfoDmaBuf secondExportInfo; - dawn::native::vulkan::ExportVulkanImage(secondDeviceWrappedTexture.Get(), - VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - &secondExportInfo); - nextFd = gbm_bo_get_fd(defaultGbmBo); - - wgpu::Texture nextWrappedTexture = - WrapVulkanImage(device, &defaultDescriptor, nextFd, defaultStride, defaultModifier, - secondExportInfo.semaphoreHandles, secondExportInfo.releasedOldLayout, - secondExportInfo.releasedNewLayout); - - // Verify |nextWrappedTexture| contains the color from our copy - EXPECT_PIXEL_RGBA8_EQ(RGBA8(1, 2, 3, 4), nextWrappedTexture, 0, 0); - - IgnoreSignalSemaphore(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, {}, - VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); - - // Clear |wrappedTexture| on |secondDevice| - ClearImage(secondDevice, wrappedTexture, {1 / 255.0f, 2 / 255.0f, 3 / 255.0f, 4 / 255.0f}); - - dawn::native::vulkan::ExternalImageExportInfoDmaBuf exportInfo; - dawn::native::vulkan::ExportVulkanImage(wrappedTexture.Get(), - VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, &exportInfo); - - // Import the image to |device|, making sure we wait on |signalFd| - int nextFd = gbm_bo_get_fd(defaultGbmBo); - wgpu::Texture deviceWrappedTexture = - WrapVulkanImage(device, &defaultDescriptor, nextFd, defaultStride, defaultModifier, - exportInfo.semaphoreHandles, exportInfo.releasedOldLayout, - exportInfo.releasedNewLayout); - - // 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::ImageCopyTexture copySrc = - utils::CreateImageCopyTexture(deviceWrappedTexture, 0, {0, 0, 0}); - wgpu::ImageCopyBuffer copyDst = utils::CreateImageCopyBuffer(copyDstBuffer, 0, 256); - - 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(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, {}, - VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); - - // Clear |wrappedTexture| on |device| - ClearImage(device, wrappedTexture, {5 / 255.0f, 6 / 255.0f, 7 / 255.0f, 8 / 255.0f}); - - dawn::native::vulkan::ExternalImageExportInfoDmaBuf exportInfo; - dawn::native::vulkan::ExportVulkanImage(wrappedTexture.Get(), - VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, &exportInfo); - - // Import the image to |secondDevice|, making sure we wait on |signalFd| - int nextFd = gbm_bo_get_fd(defaultGbmBo); - wgpu::Texture secondDeviceWrappedTexture = - WrapVulkanImage(secondDevice, &defaultDescriptor, nextFd, defaultStride, - defaultModifier, exportInfo.semaphoreHandles, - exportInfo.releasedOldLayout, exportInfo.releasedNewLayout); - - // Copy color B on |secondDevice| - wgpu::Queue secondDeviceQueue = secondDevice.GetQueue(); - - // Create a buffer on |secondDevice| - wgpu::Buffer copySrcBuffer = - utils::CreateBufferFromData(secondDevice, wgpu::BufferUsage::CopySrc, {0x04030201}); - - // Copy |copySrcBuffer| into |secondDeviceWrappedTexture| - wgpu::ImageCopyBuffer copySrc = utils::CreateImageCopyBuffer(copySrcBuffer, 0, 256); - wgpu::ImageCopyTexture copyDst = - utils::CreateImageCopyTexture(secondDeviceWrappedTexture, 0, {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 - dawn::native::vulkan::ExternalImageExportInfoDmaBuf secondExportInfo; - dawn::native::vulkan::ExportVulkanImage(secondDeviceWrappedTexture.Get(), - VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - &secondExportInfo); - nextFd = gbm_bo_get_fd(defaultGbmBo); - - wgpu::Texture nextWrappedTexture = - WrapVulkanImage(device, &defaultDescriptor, nextFd, defaultStride, defaultModifier, - secondExportInfo.semaphoreHandles, secondExportInfo.releasedOldLayout, - secondExportInfo.releasedNewLayout); - - // Verify |nextWrappedTexture| contains the color from our copy - EXPECT_PIXEL_RGBA8_EQ(RGBA8(1, 2, 3, 4), nextWrappedTexture, 0, 0); - - IgnoreSignalSemaphore(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, {}, - VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); - - // Clear |wrappedTexture| on |secondDevice| - ClearImage(secondDevice, wrappedTexture, {1 / 255.0f, 2 / 255.0f, 3 / 255.0f, 4 / 255.0f}); - - dawn::native::vulkan::ExternalImageExportInfoDmaBuf exportInfo; - dawn::native::vulkan::ExportVulkanImage(wrappedTexture.Get(), - VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, &exportInfo); - - // Import the image to |device|, making sure we wait on |signalFd| - int nextFd = gbm_bo_get_fd(defaultGbmBo); - wgpu::Texture deviceWrappedTexture = - WrapVulkanImage(device, &defaultDescriptor, nextFd, defaultStride, defaultModifier, - exportInfo.semaphoreHandles, exportInfo.releasedOldLayout, - exportInfo.releasedNewLayout); - - // 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(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 = - dawn::native::vulkan::ToBackend(backendAdapter->APICreateDevice(&deviceDescriptor)); - wgpu::Device thirdDevice = wgpu::Device::Acquire(dawn::native::ToAPI(thirdDeviceVk)); - - // Make queue for device 2 and 3 - wgpu::Queue secondDeviceQueue = secondDevice.GetQueue(); - wgpu::Queue thirdDeviceQueue = thirdDevice.GetQueue(); - - // 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, {}, - VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); - - wgpu::Texture wrappedTexBDevice3 = - WrapVulkanImage(thirdDevice, &defaultDescriptor, fdB, strideB, modifierB, {}, - VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); - - // 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); - - dawn::native::vulkan::ExternalImageExportInfoDmaBuf exportInfoTexBDevice3; - dawn::native::vulkan::ExportVulkanImage( - wrappedTexBDevice3.Get(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, &exportInfoTexBDevice3); - IgnoreSignalSemaphore(wrappedTexADevice3); - - // Import TexB, TexC on device 2 - fdB = gbm_bo_get_fd(gbmBoB); - wgpu::Texture wrappedTexBDevice2 = WrapVulkanImage( - secondDevice, &defaultDescriptor, fdB, strideB, modifierB, - exportInfoTexBDevice3.semaphoreHandles, exportInfoTexBDevice3.releasedOldLayout, - exportInfoTexBDevice3.releasedNewLayout); - - wgpu::Texture wrappedTexCDevice2 = - WrapVulkanImage(secondDevice, &defaultDescriptor, fdC, strideC, modifierC, {}, - VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); - - // Copy B->C on device 2 - SimpleCopyTextureToTexture(secondDevice, secondDeviceQueue, wrappedTexBDevice2, - wrappedTexCDevice2); - - dawn::native::vulkan::ExternalImageExportInfoDmaBuf exportInfoTexCDevice2; - dawn::native::vulkan::ExportVulkanImage( - wrappedTexCDevice2.Get(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, &exportInfoTexCDevice2); - IgnoreSignalSemaphore(wrappedTexBDevice2); - - // Import TexC on device 1 - fdC = gbm_bo_get_fd(gbmBoC); - wgpu::Texture wrappedTexCDevice1 = WrapVulkanImage( - device, &defaultDescriptor, fdC, strideC, modifierC, - exportInfoTexCDevice2.semaphoreHandles, exportInfoTexCDevice2.releasedOldLayout, - exportInfoTexCDevice2.releasedNewLayout); - - // 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(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.depthOrArrayLayers = 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.GetQueue(); - - // 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, {}, - VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); - - // Draw a non-trivial picture - uint32_t width = 640, height = 480, pixelSize = 4; - uint32_t bytesPerRow = Align(width * pixelSize, kTextureBytesPerRowAlignment); - std::vector data(bytesPerRow * (height - 1) + width * pixelSize); - - for (uint32_t row = 0; row < height; row++) { - for (uint32_t 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.data(), data.size(), wgpu::BufferUsage::CopySrc); - wgpu::ImageCopyBuffer copySrc = - utils::CreateImageCopyBuffer(copySrcBuffer, 0, bytesPerRow); - wgpu::ImageCopyTexture copyDst = - utils::CreateImageCopyTexture(wrappedTexture, 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); - } - dawn::native::vulkan::ExternalImageExportInfoDmaBuf exportInfo; - dawn::native::vulkan::ExportVulkanImage(wrappedTexture.Get(), - VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, &exportInfo); - int nextFd = gbm_bo_get_fd(gbmBo); - - // Import the image on |device| - wgpu::Texture nextWrappedTexture = WrapVulkanImage( - device, &descriptor, nextFd, stride, modifier, exportInfo.semaphoreHandles, - exportInfo.releasedOldLayout, exportInfo.releasedNewLayout); - - // Copy the image into a buffer for comparison - wgpu::BufferDescriptor copyDesc; - copyDesc.size = data.size(); - copyDesc.usage = wgpu::BufferUsage::CopySrc | wgpu::BufferUsage::CopyDst; - wgpu::Buffer copyDstBuffer = device.CreateBuffer(©Desc); - { - wgpu::ImageCopyTexture copySrc = - utils::CreateImageCopyTexture(nextWrappedTexture, 0, {0, 0, 0}); - wgpu::ImageCopyBuffer copyDst = - utils::CreateImageCopyBuffer(copyDstBuffer, 0, bytesPerRow); - - 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.data()), copyDstBuffer, 0, - data.size() / 4); - - IgnoreSignalSemaphore(nextWrappedTexture); - } - - DAWN_INSTANTIATE_TEST(VulkanImageWrappingValidationTests, VulkanBackend()); - DAWN_INSTANTIATE_TEST(VulkanImageWrappingUsageTests, VulkanBackend()); - -} // namespace dawn::native::vulkan diff --git a/src/tests/white_box/VulkanImageWrappingTests_DmaBuf.cpp b/src/tests/white_box/VulkanImageWrappingTests_DmaBuf.cpp new file mode 100644 index 0000000000..a382822e4d --- /dev/null +++ b/src/tests/white_box/VulkanImageWrappingTests_DmaBuf.cpp @@ -0,0 +1,189 @@ +// 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/white_box/VulkanImageWrappingTests.h" + +#include +#include +#include +#include + +namespace dawn::native::vulkan { + + ExternalImageDescriptorVkForTesting::ExternalImageDescriptorVkForTesting() + : ExternalImageDescriptorVk(ExternalImageType::DmaBuf) { + } + ExternalImageExportInfoVkForTesting::ExternalImageExportInfoVkForTesting() + : ExternalImageExportInfoVk(ExternalImageType::DmaBuf) { + } + + class ExternalSemaphoreDmaBuf : public VulkanImageWrappingTestBackend::ExternalSemaphore { + public: + ExternalSemaphoreDmaBuf(int handle) : mHandle(handle) { + } + ~ExternalSemaphoreDmaBuf() override { + if (mHandle != -1) { + close(mHandle); + } + } + int AcquireHandle() { + int handle = mHandle; + mHandle = -1; + return handle; + } + + private: + int mHandle = -1; + }; + + class ExternalTextureDmaBuf : public VulkanImageWrappingTestBackend::ExternalTexture { + public: + ExternalTextureDmaBuf(gbm_bo* bo, int fd, uint32_t stride, uint64_t drmModifier) + : mGbmBo(bo), mFd(fd), stride(stride), drmModifier(drmModifier) { + } + + ~ExternalTextureDmaBuf() override { + if (mFd != -1) { + close(mFd); + } + if (mGbmBo != nullptr) { + gbm_bo_destroy(mGbmBo); + } + } + + int Dup() const { + return dup(mFd); + } + + private: + gbm_bo* mGbmBo = nullptr; + int mFd = -1; + + public: + const uint32_t stride; + const uint64_t drmModifier; + }; + + class VulkanImageWrappingTestBackendDmaBuf : public VulkanImageWrappingTestBackend { + public: + VulkanImageWrappingTestBackendDmaBuf(const wgpu::Device& device) { + } + + ~VulkanImageWrappingTestBackendDmaBuf() { + if (mGbmDevice != nullptr) { + gbm_device_destroy(mGbmDevice); + mGbmDevice = nullptr; + } + } + + std::unique_ptr CreateTexture(uint32_t width, + uint32_t height, + wgpu::TextureFormat format, + wgpu::TextureUsage usage) override { + EXPECT_EQ(format, wgpu::TextureFormat::RGBA8Unorm); + + gbm_bo* bo = CreateGbmBo(width, height, true); + + return std::make_unique( + bo, gbm_bo_get_fd(bo), gbm_bo_get_stride_for_plane(bo, 0), gbm_bo_get_modifier(bo)); + } + + wgpu::Texture WrapImage( + const wgpu::Device& device, + const ExternalTexture* texture, + const ExternalImageDescriptorVkForTesting& descriptor, + std::vector> semaphores) override { + const ExternalTextureDmaBuf* textureDmaBuf = + static_cast(texture); + std::vector waitFDs; + for (auto& semaphore : semaphores) { + waitFDs.push_back( + static_cast(semaphore.get())->AcquireHandle()); + } + + ExternalImageDescriptorDmaBuf descriptorDmaBuf; + *static_cast(&descriptorDmaBuf) = descriptor; + + descriptorDmaBuf.memoryFD = textureDmaBuf->Dup(); + descriptorDmaBuf.waitFDs = std::move(waitFDs); + + descriptorDmaBuf.stride = textureDmaBuf->stride; + descriptorDmaBuf.drmModifier = textureDmaBuf->drmModifier; + + return dawn::native::vulkan::WrapVulkanImage(device.Get(), &descriptorDmaBuf); + } + + bool ExportImage(const wgpu::Texture& texture, + VkImageLayout layout, + ExternalImageExportInfoVkForTesting* exportInfo) override { + ExternalImageExportInfoDmaBuf infoDmaBuf; + bool success = ExportVulkanImage(texture.Get(), layout, &infoDmaBuf); + + *static_cast(exportInfo) = infoDmaBuf; + for (int fd : infoDmaBuf.semaphoreHandles) { + EXPECT_NE(fd, -1); + exportInfo->semaphores.push_back(std::make_unique(fd)); + } + + return success; + } + + void 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"; + mGbmDevice = gbmDevice; + } + + private: + 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(mGbmDevice, width, height, GBM_FORMAT_XBGR8888, flags); + EXPECT_NE(gbmBo, nullptr) << "Failed to create GBM buffer object"; + return gbmBo; + } + + gbm_device* mGbmDevice = nullptr; + }; + + // static + std::unique_ptr VulkanImageWrappingTestBackend::Create( + const wgpu::Device& device) { + auto backend = std::make_unique(device); + backend->CreateGbmDevice(); + return backend; + } +} // namespace dawn::native::vulkan \ No newline at end of file diff --git a/src/tests/white_box/VulkanImageWrappingTests_OpaqueFD.cpp b/src/tests/white_box/VulkanImageWrappingTests_OpaqueFD.cpp index 23275dcd64..7e94cb9efb 100644 --- a/src/tests/white_box/VulkanImageWrappingTests_OpaqueFD.cpp +++ b/src/tests/white_box/VulkanImageWrappingTests_OpaqueFD.cpp @@ -23,6 +23,13 @@ namespace dawn::native::vulkan { + ExternalImageDescriptorVkForTesting::ExternalImageDescriptorVkForTesting() + : ExternalImageDescriptorVk(ExternalImageType::OpaqueFD) { + } + ExternalImageExportInfoVkForTesting::ExternalImageExportInfoVkForTesting() + : ExternalImageExportInfoVk(ExternalImageType::OpaqueFD) { + } + class ExternalSemaphoreOpaqueFD : public VulkanImageWrappingTestBackend::ExternalSemaphore { public: ExternalSemaphoreOpaqueFD(int handle) : mHandle(handle) {