Vulkan: Lock device when creating and exporting ExternalImage.
Bug: dawn:1662
Change-Id: Iee505f3c2c861ef9c3a6cc6189deefff08c343b7
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/166160
Auto-Submit: Quyen Le <lehoangquyen@chromium.org>
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Commit-Queue: Austin Eng <enga@chromium.org>
Reviewed-by: Austin Eng <enga@chromium.org>
diff --git a/src/dawn/native/vulkan/VulkanBackend.cpp b/src/dawn/native/vulkan/VulkanBackend.cpp
index b8703ec..b409077 100644
--- a/src/dawn/native/vulkan/VulkanBackend.cpp
+++ b/src/dawn/native/vulkan/VulkanBackend.cpp
@@ -77,10 +77,11 @@
#endif
WGPUTexture WrapVulkanImage(WGPUDevice device, const ExternalImageDescriptorVk* descriptor) {
+ Device* backendDevice = ToBackend(FromAPI(device));
+ auto deviceLock(backendDevice->GetScopedLock());
switch (descriptor->GetType()) {
#if DAWN_PLATFORM_IS(ANDROID)
case ExternalImageType::AHardwareBuffer: {
- Device* backendDevice = ToBackend(FromAPI(device));
const ExternalImageDescriptorAHardwareBuffer* ahbDescriptor =
static_cast<const ExternalImageDescriptorAHardwareBuffer*>(descriptor);
@@ -90,7 +91,6 @@
#elif DAWN_PLATFORM_IS(LINUX)
case ExternalImageType::OpaqueFD:
case ExternalImageType::DmaBuf: {
- Device* backendDevice = ToBackend(FromAPI(device));
const ExternalImageDescriptorFD* fdDescriptor =
static_cast<const ExternalImageDescriptorFD*>(descriptor);
@@ -110,13 +110,14 @@
if (texture == nullptr) {
return false;
}
+ Texture* backendTexture = ToBackend(FromAPI(texture));
+ Device* device = ToBackend(backendTexture->GetDevice());
+ auto deviceLock(device->GetScopedLock());
#if DAWN_PLATFORM_IS(ANDROID) || DAWN_PLATFORM_IS(LINUX)
switch (info->GetType()) {
case ExternalImageType::AHardwareBuffer:
case ExternalImageType::OpaqueFD:
case ExternalImageType::DmaBuf: {
- Texture* backendTexture = ToBackend(FromAPI(texture));
- Device* device = ToBackend(backendTexture->GetDevice());
ExternalImageExportInfoFD* fdInfo = static_cast<ExternalImageExportInfoFD*>(info);
return device->SignalAndExportExternalTexture(backendTexture, desiredLayout, fdInfo,
diff --git a/src/dawn/tests/white_box/VulkanImageWrappingTests.cpp b/src/dawn/tests/white_box/VulkanImageWrappingTests.cpp
index 57cf38f..1e41801 100644
--- a/src/dawn/tests/white_box/VulkanImageWrappingTests.cpp
+++ b/src/dawn/tests/white_box/VulkanImageWrappingTests.cpp
@@ -976,6 +976,57 @@
IgnoreSignalSemaphore(texture);
}
+class VulkanImageWrappingMultithreadTests : public VulkanImageWrappingUsageTests {
+ protected:
+ std::vector<wgpu::FeatureName> GetRequiredFeatures() override {
+ std::vector<wgpu::FeatureName> features;
+ // TODO(crbug.com/dawn/1678): DawnWire doesn't support thread safe API yet.
+ if (!UsesWire()) {
+ features.push_back(wgpu::FeatureName::ImplicitDeviceSynchronization);
+ }
+ return features;
+ }
+
+ void SetUp() override {
+ VulkanImageWrappingUsageTests::SetUp();
+ // TODO(crbug.com/dawn/1678): DawnWire doesn't support thread safe API yet.
+ DAWN_TEST_UNSUPPORTED_IF(UsesWire());
+ }
+};
+
+// Test that wrapping multiple VulkanImage and clear them on multiple threads work.
+TEST_P(VulkanImageWrappingMultithreadTests, WrapAndClear_OnMultipleThreads) {
+ std::vector<std::unique_ptr<ExternalTexture>> testTextures(10);
+ for (auto& testTexture : testTextures) {
+ testTexture =
+ mBackend->CreateTexture(1, 1, defaultDescriptor.format, defaultDescriptor.usage);
+ }
+
+ wgpu::Device writeDevice = CreateDevice();
+
+ utils::RunInParallel(testTextures.size(), [&](uint32_t idx) {
+ // Import the image on |writeDevice|
+ wgpu::Texture wrappedTexture =
+ WrapVulkanImage(writeDevice, &defaultDescriptor, testTextures[idx].get(), {},
+ VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
+
+ // Clear |wrappedTexture| on |writeDevice|
+ ClearImage(writeDevice, wrappedTexture, {1 / 255.0f, 2 / 255.0f, 3 / 255.0f, 4 / 255.0f});
+
+ ExternalImageExportInfoVkForTesting exportInfo = GetExternalImageExportInfo();
+ ASSERT_TRUE(mBackend->ExportImage(wrappedTexture, &exportInfo));
+
+ // Import the image to |device|, making sure we wait on signalFd
+ wgpu::Texture nextWrappedTexture = WrapVulkanImage(
+ device, &defaultDescriptor, testTextures[idx].get(), std::move(exportInfo.semaphores),
+ exportInfo.releasedOldLayout, exportInfo.releasedNewLayout);
+
+ // Verify |device| sees the changes from |secondDevice|
+ EXPECT_PIXEL_RGBA8_EQ(utils::RGBA8(1, 2, 3, 4), nextWrappedTexture, 0, 0);
+
+ IgnoreSignalSemaphore(nextWrappedTexture);
+ });
+}
DAWN_INSTANTIATE_TEST_P(VulkanImageWrappingValidationTests,
{VulkanBackend()},
@@ -990,5 +1041,12 @@
{true, false} // DetectDedicatedAllocation
);
+DAWN_INSTANTIATE_TEST_P(VulkanImageWrappingMultithreadTests,
+ {VulkanBackend()},
+ {ExternalImageType::OpaqueFD, ExternalImageType::DmaBuf},
+ {true, false}, // UseDedicatedAllocation
+ {true, false} // DetectDedicatedAllocation
+);
+
} // anonymous namespace
} // namespace dawn::native::vulkan