1 // Copyright 2019 The Dawn Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #include "common/Math.h" 16 #include "tests/DawnTest.h" 17 18 #include "common/vulkan_platform.h" 19 #include "dawn_native/VulkanBackend.h" 20 #include "dawn_native/vulkan/AdapterVk.h" 21 #include "dawn_native/vulkan/DeviceVk.h" 22 #include "dawn_native/vulkan/FencedDeleter.h" 23 #include "dawn_native/vulkan/ResourceMemoryAllocatorVk.h" 24 #include "dawn_native/vulkan/TextureVk.h" 25 #include "utils/SystemUtils.h" 26 #include "utils/WGPUHelpers.h" 27 28 namespace dawn_native { namespace vulkan { 29 30 namespace { 31 32 class VulkanImageWrappingTestBase : public DawnTest { 33 protected: GetRequiredFeatures()34 std::vector<const char*> GetRequiredFeatures() override { 35 return {"dawn-internal-usages"}; 36 } 37 38 public: SetUp()39 void SetUp() override { 40 DawnTest::SetUp(); 41 DAWN_TEST_UNSUPPORTED_IF(UsesWire()); 42 43 deviceVk = dawn_native::vulkan::ToBackend(dawn_native::FromAPI(device.Get())); 44 } 45 46 // Creates a VkImage with external memory CreateImage(dawn_native::vulkan::Device * deviceVk,uint32_t width,uint32_t height,VkFormat format,VkImage * image)47 ::VkResult CreateImage(dawn_native::vulkan::Device* deviceVk, 48 uint32_t width, 49 uint32_t height, 50 VkFormat format, 51 VkImage* image) { 52 VkExternalMemoryImageCreateInfoKHR externalInfo; 53 externalInfo.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO_KHR; 54 externalInfo.pNext = nullptr; 55 externalInfo.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR; 56 57 auto usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | 58 VK_IMAGE_USAGE_TRANSFER_DST_BIT; 59 60 VkImageCreateInfo createInfo; 61 createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; 62 createInfo.pNext = &externalInfo; 63 createInfo.flags = VK_IMAGE_CREATE_ALIAS_BIT_KHR; 64 createInfo.imageType = VK_IMAGE_TYPE_2D; 65 createInfo.format = format; 66 createInfo.extent = {width, height, 1}; 67 createInfo.mipLevels = 1; 68 createInfo.arrayLayers = 1; 69 createInfo.samples = VK_SAMPLE_COUNT_1_BIT; 70 createInfo.tiling = VK_IMAGE_TILING_OPTIMAL; 71 createInfo.usage = usage; 72 createInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; 73 createInfo.queueFamilyIndexCount = 0; 74 createInfo.pQueueFamilyIndices = nullptr; 75 createInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; 76 77 return deviceVk->fn.CreateImage(deviceVk->GetVkDevice(), &createInfo, nullptr, 78 &**image); 79 } 80 81 // Allocates memory for an image AllocateMemory(dawn_native::vulkan::Device * deviceVk,VkImage handle,VkDeviceMemory * allocation,VkDeviceSize * allocationSize,uint32_t * memoryTypeIndex)82 ::VkResult AllocateMemory(dawn_native::vulkan::Device* deviceVk, 83 VkImage handle, 84 VkDeviceMemory* allocation, 85 VkDeviceSize* allocationSize, 86 uint32_t* memoryTypeIndex) { 87 // Create the image memory and associate it with the container 88 VkMemoryRequirements requirements; 89 deviceVk->fn.GetImageMemoryRequirements(deviceVk->GetVkDevice(), handle, 90 &requirements); 91 92 // Import memory from file descriptor 93 VkExportMemoryAllocateInfoKHR externalInfo; 94 externalInfo.sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_KHR; 95 externalInfo.pNext = nullptr; 96 externalInfo.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR; 97 98 int bestType = deviceVk->GetResourceMemoryAllocator()->FindBestTypeIndex( 99 requirements, MemoryKind::Opaque); 100 VkMemoryAllocateInfo allocateInfo; 101 allocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; 102 allocateInfo.pNext = &externalInfo; 103 allocateInfo.allocationSize = requirements.size; 104 allocateInfo.memoryTypeIndex = static_cast<uint32_t>(bestType); 105 106 *allocationSize = allocateInfo.allocationSize; 107 *memoryTypeIndex = allocateInfo.memoryTypeIndex; 108 109 return deviceVk->fn.AllocateMemory(deviceVk->GetVkDevice(), &allocateInfo, nullptr, 110 &**allocation); 111 } 112 113 // Binds memory to an image BindMemory(dawn_native::vulkan::Device * deviceVk,VkImage handle,VkDeviceMemory * memory)114 ::VkResult BindMemory(dawn_native::vulkan::Device* deviceVk, 115 VkImage handle, 116 VkDeviceMemory* memory) { 117 return deviceVk->fn.BindImageMemory(deviceVk->GetVkDevice(), handle, *memory, 0); 118 } 119 120 // Extracts a file descriptor representing memory on a device GetMemoryFd(dawn_native::vulkan::Device * deviceVk,VkDeviceMemory memory)121 int GetMemoryFd(dawn_native::vulkan::Device* deviceVk, VkDeviceMemory memory) { 122 VkMemoryGetFdInfoKHR getFdInfo; 123 getFdInfo.sType = VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR; 124 getFdInfo.pNext = nullptr; 125 getFdInfo.memory = memory; 126 getFdInfo.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR; 127 128 int memoryFd = -1; 129 deviceVk->fn.GetMemoryFdKHR(deviceVk->GetVkDevice(), &getFdInfo, &memoryFd); 130 131 EXPECT_GE(memoryFd, 0) << "Failed to get file descriptor for external memory"; 132 return memoryFd; 133 } 134 135 // Prepares and exports memory for an image on a given device 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)136 void CreateBindExportImage(dawn_native::vulkan::Device* deviceVk, 137 uint32_t width, 138 uint32_t height, 139 VkFormat format, 140 VkImage* handle, 141 VkDeviceMemory* allocation, 142 VkDeviceSize* allocationSize, 143 uint32_t* memoryTypeIndex, 144 int* memoryFd) { 145 ::VkResult result = CreateImage(deviceVk, width, height, format, handle); 146 EXPECT_EQ(result, VK_SUCCESS) << "Failed to create external image"; 147 148 ::VkResult resultBool = 149 AllocateMemory(deviceVk, *handle, allocation, allocationSize, memoryTypeIndex); 150 EXPECT_EQ(resultBool, VK_SUCCESS) << "Failed to allocate external memory"; 151 152 result = BindMemory(deviceVk, *handle, allocation); 153 EXPECT_EQ(result, VK_SUCCESS) << "Failed to bind image memory"; 154 155 *memoryFd = GetMemoryFd(deviceVk, *allocation); 156 } 157 158 // Wraps a vulkan image from external memory WrapVulkanImage(wgpu::Device dawnDevice,const wgpu::TextureDescriptor * textureDescriptor,int memoryFd,VkDeviceSize allocationSize,uint32_t memoryTypeIndex,std::vector<int> waitFDs,bool isInitialized=true,bool expectValid=true)159 wgpu::Texture WrapVulkanImage(wgpu::Device dawnDevice, 160 const wgpu::TextureDescriptor* textureDescriptor, 161 int memoryFd, 162 VkDeviceSize allocationSize, 163 uint32_t memoryTypeIndex, 164 std::vector<int> waitFDs, 165 bool isInitialized = true, 166 bool expectValid = true) { 167 dawn_native::vulkan::ExternalImageDescriptorOpaqueFD descriptor; 168 return WrapVulkanImage(dawnDevice, textureDescriptor, memoryFd, allocationSize, 169 memoryTypeIndex, waitFDs, descriptor.releasedOldLayout, 170 descriptor.releasedNewLayout, isInitialized, expectValid); 171 } 172 WrapVulkanImage(wgpu::Device dawnDevice,const wgpu::TextureDescriptor * textureDescriptor,int memoryFd,VkDeviceSize allocationSize,uint32_t memoryTypeIndex,std::vector<int> waitFDs,VkImageLayout releasedOldLayout,VkImageLayout releasedNewLayout,bool isInitialized=true,bool expectValid=true)173 wgpu::Texture WrapVulkanImage(wgpu::Device dawnDevice, 174 const wgpu::TextureDescriptor* textureDescriptor, 175 int memoryFd, 176 VkDeviceSize allocationSize, 177 uint32_t memoryTypeIndex, 178 std::vector<int> waitFDs, 179 VkImageLayout releasedOldLayout, 180 VkImageLayout releasedNewLayout, 181 bool isInitialized = true, 182 bool expectValid = true) { 183 dawn_native::vulkan::ExternalImageDescriptorOpaqueFD descriptor; 184 descriptor.cTextureDescriptor = 185 reinterpret_cast<const WGPUTextureDescriptor*>(textureDescriptor); 186 descriptor.isInitialized = isInitialized; 187 descriptor.allocationSize = allocationSize; 188 descriptor.memoryTypeIndex = memoryTypeIndex; 189 descriptor.memoryFD = memoryFd; 190 descriptor.waitFDs = waitFDs; 191 descriptor.releasedOldLayout = releasedOldLayout; 192 descriptor.releasedNewLayout = releasedNewLayout; 193 194 WGPUTexture texture = 195 dawn_native::vulkan::WrapVulkanImage(dawnDevice.Get(), &descriptor); 196 197 if (expectValid) { 198 EXPECT_NE(texture, nullptr) << "Failed to wrap image, are external memory / " 199 "semaphore extensions supported?"; 200 } else { 201 EXPECT_EQ(texture, nullptr); 202 } 203 204 return wgpu::Texture::Acquire(texture); 205 } 206 207 // Exports the signal from a wrapped texture and ignores it 208 // We have to export the signal before destroying the wrapped texture else it's an 209 // assertion failure IgnoreSignalSemaphore(wgpu::Texture wrappedTexture)210 void IgnoreSignalSemaphore(wgpu::Texture wrappedTexture) { 211 dawn_native::vulkan::ExternalImageExportInfoOpaqueFD info; 212 dawn_native::vulkan::ExportVulkanImage(wrappedTexture.Get(), 213 VK_IMAGE_LAYOUT_GENERAL, &info); 214 for (int handle : info.semaphoreHandles) { 215 ASSERT_NE(handle, -1); 216 close(handle); 217 } 218 } 219 220 protected: 221 dawn_native::vulkan::Device* deviceVk; 222 }; 223 224 } // anonymous namespace 225 226 class VulkanImageWrappingValidationTests : public VulkanImageWrappingTestBase { 227 public: SetUp()228 void SetUp() override { 229 VulkanImageWrappingTestBase::SetUp(); 230 DAWN_TEST_UNSUPPORTED_IF(UsesWire()); 231 232 CreateBindExportImage(deviceVk, 1, 1, VK_FORMAT_R8G8B8A8_UNORM, &defaultImage, 233 &defaultAllocation, &defaultAllocationSize, 234 &defaultMemoryTypeIndex, &defaultFd); 235 defaultDescriptor.dimension = wgpu::TextureDimension::e2D; 236 defaultDescriptor.format = wgpu::TextureFormat::RGBA8Unorm; 237 defaultDescriptor.size = {1, 1, 1}; 238 defaultDescriptor.sampleCount = 1; 239 defaultDescriptor.mipLevelCount = 1; 240 defaultDescriptor.usage = wgpu::TextureUsage::RenderAttachment | 241 wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::CopyDst; 242 } 243 TearDown()244 void TearDown() override { 245 if (UsesWire()) { 246 VulkanImageWrappingTestBase::TearDown(); 247 return; 248 } 249 250 deviceVk->GetFencedDeleter()->DeleteWhenUnused(defaultImage); 251 deviceVk->GetFencedDeleter()->DeleteWhenUnused(defaultAllocation); 252 VulkanImageWrappingTestBase::TearDown(); 253 } 254 255 protected: 256 wgpu::TextureDescriptor defaultDescriptor; 257 VkImage defaultImage; 258 VkDeviceMemory defaultAllocation; 259 VkDeviceSize defaultAllocationSize; 260 uint32_t defaultMemoryTypeIndex; 261 int defaultFd; 262 }; 263 264 // Test no error occurs if the import is valid TEST_P(VulkanImageWrappingValidationTests,SuccessfulImport)265 TEST_P(VulkanImageWrappingValidationTests, SuccessfulImport) { 266 wgpu::Texture texture = 267 WrapVulkanImage(device, &defaultDescriptor, defaultFd, defaultAllocationSize, 268 defaultMemoryTypeIndex, {}, true, true); 269 EXPECT_NE(texture.Get(), nullptr); 270 IgnoreSignalSemaphore(texture); 271 } 272 273 // Test no error occurs if the import is valid with DawnTextureInternalUsageDescriptor TEST_P(VulkanImageWrappingValidationTests,SuccessfulImportWithInternalUsageDescriptor)274 TEST_P(VulkanImageWrappingValidationTests, SuccessfulImportWithInternalUsageDescriptor) { 275 wgpu::DawnTextureInternalUsageDescriptor internalDesc = {}; 276 defaultDescriptor.nextInChain = &internalDesc; 277 internalDesc.internalUsage = wgpu::TextureUsage::CopySrc; 278 internalDesc.sType = wgpu::SType::DawnTextureInternalUsageDescriptor; 279 280 wgpu::Texture texture = 281 WrapVulkanImage(device, &defaultDescriptor, defaultFd, defaultAllocationSize, 282 defaultMemoryTypeIndex, {}, true, true); 283 EXPECT_NE(texture.Get(), nullptr); 284 IgnoreSignalSemaphore(texture); 285 } 286 287 // Test an error occurs if an invalid sType is the nextInChain TEST_P(VulkanImageWrappingValidationTests,InvalidTextureDescriptor)288 TEST_P(VulkanImageWrappingValidationTests, InvalidTextureDescriptor) { 289 wgpu::ChainedStruct chainedDescriptor; 290 chainedDescriptor.sType = wgpu::SType::SurfaceDescriptorFromWindowsSwapChainPanel; 291 defaultDescriptor.nextInChain = &chainedDescriptor; 292 293 ASSERT_DEVICE_ERROR(wgpu::Texture texture = WrapVulkanImage( 294 device, &defaultDescriptor, defaultFd, defaultAllocationSize, 295 defaultMemoryTypeIndex, {}, true, false)); 296 EXPECT_EQ(texture.Get(), nullptr); 297 } 298 299 // Test an error occurs if the descriptor dimension isn't 2D TEST_P(VulkanImageWrappingValidationTests,InvalidTextureDimension)300 TEST_P(VulkanImageWrappingValidationTests, InvalidTextureDimension) { 301 defaultDescriptor.dimension = wgpu::TextureDimension::e1D; 302 303 ASSERT_DEVICE_ERROR(wgpu::Texture texture = WrapVulkanImage( 304 device, &defaultDescriptor, defaultFd, defaultAllocationSize, 305 defaultMemoryTypeIndex, {}, true, false)); 306 EXPECT_EQ(texture.Get(), nullptr); 307 } 308 309 // Test an error occurs if the descriptor mip level count isn't 1 TEST_P(VulkanImageWrappingValidationTests,InvalidMipLevelCount)310 TEST_P(VulkanImageWrappingValidationTests, InvalidMipLevelCount) { 311 defaultDescriptor.mipLevelCount = 2; 312 313 ASSERT_DEVICE_ERROR(wgpu::Texture texture = WrapVulkanImage( 314 device, &defaultDescriptor, defaultFd, defaultAllocationSize, 315 defaultMemoryTypeIndex, {}, true, false)); 316 EXPECT_EQ(texture.Get(), nullptr); 317 } 318 319 // Test an error occurs if the descriptor depth isn't 1 TEST_P(VulkanImageWrappingValidationTests,InvalidDepth)320 TEST_P(VulkanImageWrappingValidationTests, InvalidDepth) { 321 defaultDescriptor.size.depthOrArrayLayers = 2; 322 323 ASSERT_DEVICE_ERROR(wgpu::Texture texture = WrapVulkanImage( 324 device, &defaultDescriptor, defaultFd, defaultAllocationSize, 325 defaultMemoryTypeIndex, {}, true, false)); 326 EXPECT_EQ(texture.Get(), nullptr); 327 } 328 329 // Test an error occurs if the descriptor sample count isn't 1 TEST_P(VulkanImageWrappingValidationTests,InvalidSampleCount)330 TEST_P(VulkanImageWrappingValidationTests, InvalidSampleCount) { 331 defaultDescriptor.sampleCount = 4; 332 333 ASSERT_DEVICE_ERROR(wgpu::Texture texture = WrapVulkanImage( 334 device, &defaultDescriptor, defaultFd, defaultAllocationSize, 335 defaultMemoryTypeIndex, {}, true, false)); 336 EXPECT_EQ(texture.Get(), nullptr); 337 } 338 339 // Test an error occurs if we try to export the signal semaphore twice TEST_P(VulkanImageWrappingValidationTests,DoubleSignalSemaphoreExport)340 TEST_P(VulkanImageWrappingValidationTests, DoubleSignalSemaphoreExport) { 341 wgpu::Texture texture = 342 WrapVulkanImage(device, &defaultDescriptor, defaultFd, defaultAllocationSize, 343 defaultMemoryTypeIndex, {}, true, true); 344 ASSERT_NE(texture.Get(), nullptr); 345 IgnoreSignalSemaphore(texture); 346 347 dawn_native::vulkan::ExternalImageExportInfoOpaqueFD exportInfo; 348 ASSERT_DEVICE_ERROR(bool success = dawn_native::vulkan::ExportVulkanImage( 349 texture.Get(), VK_IMAGE_LAYOUT_GENERAL, &exportInfo)); 350 ASSERT_FALSE(success); 351 } 352 353 // Test an error occurs if we try to export the signal semaphore from a normal texture TEST_P(VulkanImageWrappingValidationTests,NormalTextureSignalSemaphoreExport)354 TEST_P(VulkanImageWrappingValidationTests, NormalTextureSignalSemaphoreExport) { 355 wgpu::Texture texture = device.CreateTexture(&defaultDescriptor); 356 ASSERT_NE(texture.Get(), nullptr); 357 358 dawn_native::vulkan::ExternalImageExportInfoOpaqueFD exportInfo; 359 ASSERT_DEVICE_ERROR(bool success = dawn_native::vulkan::ExportVulkanImage( 360 texture.Get(), VK_IMAGE_LAYOUT_GENERAL, &exportInfo)); 361 ASSERT_FALSE(success); 362 } 363 364 // Test an error occurs if we try to export the signal semaphore from a destroyed texture TEST_P(VulkanImageWrappingValidationTests,DestroyedTextureSignalSemaphoreExport)365 TEST_P(VulkanImageWrappingValidationTests, DestroyedTextureSignalSemaphoreExport) { 366 wgpu::Texture texture = device.CreateTexture(&defaultDescriptor); 367 ASSERT_NE(texture.Get(), nullptr); 368 texture.Destroy(); 369 370 dawn_native::vulkan::ExternalImageExportInfoOpaqueFD exportInfo; 371 ASSERT_DEVICE_ERROR(bool success = dawn_native::vulkan::ExportVulkanImage( 372 texture.Get(), VK_IMAGE_LAYOUT_GENERAL, &exportInfo)); 373 ASSERT_FALSE(success); 374 } 375 376 // Fixture to test using external memory textures through different usages. 377 // These tests are skipped if the harness is using the wire. 378 class VulkanImageWrappingUsageTests : public VulkanImageWrappingTestBase { 379 public: SetUp()380 void SetUp() override { 381 VulkanImageWrappingTestBase::SetUp(); 382 DAWN_TEST_UNSUPPORTED_IF(UsesWire()); 383 384 // Create another device based on the original 385 backendAdapter = dawn_native::vulkan::ToBackend(deviceVk->GetAdapter()); 386 deviceDescriptor.forceEnabledToggles = GetParam().forceEnabledWorkarounds; 387 deviceDescriptor.forceDisabledToggles = GetParam().forceDisabledWorkarounds; 388 389 secondDeviceVk = 390 dawn_native::vulkan::ToBackend(backendAdapter->CreateDevice(&deviceDescriptor)); 391 secondDevice = wgpu::Device::Acquire(dawn_native::ToAPI(secondDeviceVk)); 392 393 CreateBindExportImage(deviceVk, 1, 1, VK_FORMAT_R8G8B8A8_UNORM, &defaultImage, 394 &defaultAllocation, &defaultAllocationSize, 395 &defaultMemoryTypeIndex, &defaultFd); 396 defaultDescriptor.dimension = wgpu::TextureDimension::e2D; 397 defaultDescriptor.format = wgpu::TextureFormat::RGBA8Unorm; 398 defaultDescriptor.size = {1, 1, 1}; 399 defaultDescriptor.sampleCount = 1; 400 defaultDescriptor.mipLevelCount = 1; 401 defaultDescriptor.usage = wgpu::TextureUsage::RenderAttachment | 402 wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::CopyDst; 403 } 404 TearDown()405 void TearDown() override { 406 if (UsesWire()) { 407 VulkanImageWrappingTestBase::TearDown(); 408 return; 409 } 410 411 deviceVk->GetFencedDeleter()->DeleteWhenUnused(defaultImage); 412 deviceVk->GetFencedDeleter()->DeleteWhenUnused(defaultAllocation); 413 VulkanImageWrappingTestBase::TearDown(); 414 } 415 416 protected: 417 wgpu::Device secondDevice; 418 dawn_native::vulkan::Device* secondDeviceVk; 419 420 dawn_native::vulkan::Adapter* backendAdapter; 421 dawn_native::DawnDeviceDescriptor deviceDescriptor; 422 423 wgpu::TextureDescriptor defaultDescriptor; 424 VkImage defaultImage; 425 VkDeviceMemory defaultAllocation; 426 VkDeviceSize defaultAllocationSize; 427 uint32_t defaultMemoryTypeIndex; 428 int defaultFd; 429 430 // Clear a texture on a given device ClearImage(wgpu::Device dawnDevice,wgpu::Texture wrappedTexture,wgpu::Color clearColor)431 void ClearImage(wgpu::Device dawnDevice, 432 wgpu::Texture wrappedTexture, 433 wgpu::Color clearColor) { 434 wgpu::TextureView wrappedView = wrappedTexture.CreateView(); 435 436 // Submit a clear operation 437 utils::ComboRenderPassDescriptor renderPassDescriptor({wrappedView}, {}); 438 renderPassDescriptor.cColorAttachments[0].clearColor = clearColor; 439 440 wgpu::CommandEncoder encoder = dawnDevice.CreateCommandEncoder(); 441 wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPassDescriptor); 442 pass.EndPass(); 443 444 wgpu::CommandBuffer commands = encoder.Finish(); 445 446 wgpu::Queue queue = dawnDevice.GetQueue(); 447 queue.Submit(1, &commands); 448 } 449 450 // Submits a 1x1x1 copy from source to destination SimpleCopyTextureToTexture(wgpu::Device dawnDevice,wgpu::Queue dawnQueue,wgpu::Texture source,wgpu::Texture destination)451 void SimpleCopyTextureToTexture(wgpu::Device dawnDevice, 452 wgpu::Queue dawnQueue, 453 wgpu::Texture source, 454 wgpu::Texture destination) { 455 wgpu::ImageCopyTexture copySrc; 456 copySrc.texture = source; 457 copySrc.mipLevel = 0; 458 copySrc.origin = {0, 0, 0}; 459 460 wgpu::ImageCopyTexture copyDst; 461 copyDst.texture = destination; 462 copyDst.mipLevel = 0; 463 copyDst.origin = {0, 0, 0}; 464 465 wgpu::Extent3D copySize = {1, 1, 1}; 466 467 wgpu::CommandEncoder encoder = dawnDevice.CreateCommandEncoder(); 468 encoder.CopyTextureToTexture(©Src, ©Dst, ©Size); 469 wgpu::CommandBuffer commands = encoder.Finish(); 470 471 dawnQueue.Submit(1, &commands); 472 } 473 }; 474 475 // Clear an image in |secondDevice| 476 // Verify clear color is visible in |device| TEST_P(VulkanImageWrappingUsageTests,ClearImageAcrossDevices)477 TEST_P(VulkanImageWrappingUsageTests, ClearImageAcrossDevices) { 478 // Import the image on |secondDevice| 479 wgpu::Texture wrappedTexture = 480 WrapVulkanImage(secondDevice, &defaultDescriptor, defaultFd, defaultAllocationSize, 481 defaultMemoryTypeIndex, {}, VK_IMAGE_LAYOUT_UNDEFINED, 482 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); 483 484 // Clear |wrappedTexture| on |secondDevice| 485 ClearImage(secondDevice, wrappedTexture, {1 / 255.0f, 2 / 255.0f, 3 / 255.0f, 4 / 255.0f}); 486 487 dawn_native::vulkan::ExternalImageExportInfoOpaqueFD exportInfo; 488 dawn_native::vulkan::ExportVulkanImage(wrappedTexture.Get(), 489 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, &exportInfo); 490 491 // Import the image to |device|, making sure we wait on signalFd 492 int memoryFd = GetMemoryFd(deviceVk, defaultAllocation); 493 wgpu::Texture nextWrappedTexture = 494 WrapVulkanImage(device, &defaultDescriptor, memoryFd, defaultAllocationSize, 495 defaultMemoryTypeIndex, exportInfo.semaphoreHandles, 496 exportInfo.releasedOldLayout, exportInfo.releasedNewLayout); 497 498 // Verify |device| sees the changes from |secondDevice| 499 EXPECT_PIXEL_RGBA8_EQ(RGBA8(1, 2, 3, 4), nextWrappedTexture, 0, 0); 500 501 IgnoreSignalSemaphore(nextWrappedTexture); 502 } 503 504 // Clear an image in |secondDevice| 505 // Verify clear color is not visible in |device| if we import the texture as not cleared TEST_P(VulkanImageWrappingUsageTests,UninitializedTextureIsCleared)506 TEST_P(VulkanImageWrappingUsageTests, UninitializedTextureIsCleared) { 507 // Import the image on |secondDevice| 508 wgpu::Texture wrappedTexture = 509 WrapVulkanImage(secondDevice, &defaultDescriptor, defaultFd, defaultAllocationSize, 510 defaultMemoryTypeIndex, {}, VK_IMAGE_LAYOUT_UNDEFINED, 511 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); 512 513 // Clear |wrappedTexture| on |secondDevice| 514 ClearImage(secondDevice, wrappedTexture, {1 / 255.0f, 2 / 255.0f, 3 / 255.0f, 4 / 255.0f}); 515 516 dawn_native::vulkan::ExternalImageExportInfoOpaqueFD exportInfo; 517 dawn_native::vulkan::ExportVulkanImage(wrappedTexture.Get(), 518 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, &exportInfo); 519 520 // Import the image to |device|, making sure we wait on the semaphore 521 int memoryFd = GetMemoryFd(deviceVk, defaultAllocation); 522 wgpu::Texture nextWrappedTexture = 523 WrapVulkanImage(device, &defaultDescriptor, memoryFd, defaultAllocationSize, 524 defaultMemoryTypeIndex, exportInfo.semaphoreHandles, 525 exportInfo.releasedOldLayout, exportInfo.releasedNewLayout, false); 526 527 // Verify |device| doesn't see the changes from |secondDevice| 528 EXPECT_PIXEL_RGBA8_EQ(RGBA8(0, 0, 0, 0), nextWrappedTexture, 0, 0); 529 530 IgnoreSignalSemaphore(nextWrappedTexture); 531 } 532 533 // Import a texture into |secondDevice| 534 // Issue a copy of the imported texture inside |device| to |copyDstTexture| 535 // Verify the clear color from |secondDevice| is visible in |copyDstTexture| TEST_P(VulkanImageWrappingUsageTests,CopyTextureToTextureSrcSync)536 TEST_P(VulkanImageWrappingUsageTests, CopyTextureToTextureSrcSync) { 537 // Import the image on |secondDevice| 538 wgpu::Texture wrappedTexture = 539 WrapVulkanImage(secondDevice, &defaultDescriptor, defaultFd, defaultAllocationSize, 540 defaultMemoryTypeIndex, {}, VK_IMAGE_LAYOUT_UNDEFINED, 541 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); 542 543 // Clear |wrappedTexture| on |secondDevice| 544 ClearImage(secondDevice, wrappedTexture, {1 / 255.0f, 2 / 255.0f, 3 / 255.0f, 4 / 255.0f}); 545 546 dawn_native::vulkan::ExternalImageExportInfoOpaqueFD exportInfo; 547 dawn_native::vulkan::ExportVulkanImage(wrappedTexture.Get(), 548 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, &exportInfo); 549 550 // Import the image to |device|, making sure we wait on the semaphore 551 int memoryFd = GetMemoryFd(deviceVk, defaultAllocation); 552 wgpu::Texture deviceWrappedTexture = 553 WrapVulkanImage(device, &defaultDescriptor, memoryFd, defaultAllocationSize, 554 defaultMemoryTypeIndex, exportInfo.semaphoreHandles, 555 exportInfo.releasedOldLayout, exportInfo.releasedNewLayout); 556 557 // Create a second texture on |device| 558 wgpu::Texture copyDstTexture = device.CreateTexture(&defaultDescriptor); 559 560 // Copy |deviceWrappedTexture| into |copyDstTexture| 561 SimpleCopyTextureToTexture(device, queue, deviceWrappedTexture, copyDstTexture); 562 563 // Verify |copyDstTexture| sees changes from |secondDevice| 564 EXPECT_PIXEL_RGBA8_EQ(RGBA8(1, 2, 3, 4), copyDstTexture, 0, 0); 565 566 IgnoreSignalSemaphore(deviceWrappedTexture); 567 } 568 569 // Import a texture into |device| 570 // Copy color A into texture on |device| 571 // Import same texture into |secondDevice|, waiting on the copy signal 572 // Copy color B using Texture to Texture copy on |secondDevice| 573 // Import texture back into |device|, waiting on color B signal 574 // Verify texture contains color B 575 // If texture destination isn't synchronized, |secondDevice| could copy color B 576 // into the texture first, then |device| writes color A TEST_P(VulkanImageWrappingUsageTests,CopyTextureToTextureDstSync)577 TEST_P(VulkanImageWrappingUsageTests, CopyTextureToTextureDstSync) { 578 // Import the image on |device| 579 wgpu::Texture wrappedTexture = WrapVulkanImage( 580 device, &defaultDescriptor, defaultFd, defaultAllocationSize, defaultMemoryTypeIndex, 581 {}, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); 582 583 // Clear |wrappedTexture| on |device| 584 ClearImage(device, wrappedTexture, {5 / 255.0f, 6 / 255.0f, 7 / 255.0f, 8 / 255.0f}); 585 586 dawn_native::vulkan::ExternalImageExportInfoOpaqueFD exportInfo; 587 dawn_native::vulkan::ExportVulkanImage(wrappedTexture.Get(), 588 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &exportInfo); 589 590 // Import the image to |secondDevice|, making sure we wait on the semaphore 591 int memoryFd = GetMemoryFd(deviceVk, defaultAllocation); 592 wgpu::Texture secondDeviceWrappedTexture = 593 WrapVulkanImage(secondDevice, &defaultDescriptor, memoryFd, defaultAllocationSize, 594 defaultMemoryTypeIndex, exportInfo.semaphoreHandles, 595 exportInfo.releasedOldLayout, exportInfo.releasedNewLayout); 596 597 // Create a texture with color B on |secondDevice| 598 wgpu::Texture copySrcTexture = secondDevice.CreateTexture(&defaultDescriptor); 599 ClearImage(secondDevice, copySrcTexture, {1 / 255.0f, 2 / 255.0f, 3 / 255.0f, 4 / 255.0f}); 600 601 // Copy color B on |secondDevice| 602 wgpu::Queue secondDeviceQueue = secondDevice.GetQueue(); 603 SimpleCopyTextureToTexture(secondDevice, secondDeviceQueue, copySrcTexture, 604 secondDeviceWrappedTexture); 605 606 // Re-import back into |device|, waiting on |secondDevice|'s signal 607 dawn_native::vulkan::ExternalImageExportInfoOpaqueFD secondExportInfo; 608 dawn_native::vulkan::ExportVulkanImage(secondDeviceWrappedTexture.Get(), 609 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, 610 &secondExportInfo); 611 memoryFd = GetMemoryFd(deviceVk, defaultAllocation); 612 613 wgpu::Texture nextWrappedTexture = 614 WrapVulkanImage(device, &defaultDescriptor, memoryFd, defaultAllocationSize, 615 defaultMemoryTypeIndex, secondExportInfo.semaphoreHandles, 616 secondExportInfo.releasedOldLayout, secondExportInfo.releasedNewLayout); 617 618 // Verify |nextWrappedTexture| contains the color from our copy 619 EXPECT_PIXEL_RGBA8_EQ(RGBA8(1, 2, 3, 4), nextWrappedTexture, 0, 0); 620 621 IgnoreSignalSemaphore(nextWrappedTexture); 622 } 623 624 // Import a texture from |secondDevice| 625 // Issue a copy of the imported texture inside |device| to |copyDstBuffer| 626 // Verify the clear color from |secondDevice| is visible in |copyDstBuffer| TEST_P(VulkanImageWrappingUsageTests,CopyTextureToBufferSrcSync)627 TEST_P(VulkanImageWrappingUsageTests, CopyTextureToBufferSrcSync) { 628 // Import the image on |secondDevice| 629 wgpu::Texture wrappedTexture = 630 WrapVulkanImage(secondDevice, &defaultDescriptor, defaultFd, defaultAllocationSize, 631 defaultMemoryTypeIndex, {}, VK_IMAGE_LAYOUT_UNDEFINED, 632 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); 633 634 // Clear |wrappedTexture| on |secondDevice| 635 ClearImage(secondDevice, wrappedTexture, {1 / 255.0f, 2 / 255.0f, 3 / 255.0f, 4 / 255.0f}); 636 637 dawn_native::vulkan::ExternalImageExportInfoOpaqueFD exportInfo; 638 dawn_native::vulkan::ExportVulkanImage(wrappedTexture.Get(), 639 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, &exportInfo); 640 641 // Import the image to |device|, making sure we wait on the semaphore 642 int memoryFd = GetMemoryFd(deviceVk, defaultAllocation); 643 wgpu::Texture deviceWrappedTexture = 644 WrapVulkanImage(device, &defaultDescriptor, memoryFd, defaultAllocationSize, 645 defaultMemoryTypeIndex, exportInfo.semaphoreHandles, 646 exportInfo.releasedOldLayout, exportInfo.releasedNewLayout); 647 648 // Create a destination buffer on |device| 649 wgpu::BufferDescriptor bufferDesc; 650 bufferDesc.size = 4; 651 bufferDesc.usage = wgpu::BufferUsage::CopyDst | wgpu::BufferUsage::CopySrc; 652 wgpu::Buffer copyDstBuffer = device.CreateBuffer(&bufferDesc); 653 654 // Copy |deviceWrappedTexture| into |copyDstBuffer| 655 wgpu::ImageCopyTexture copySrc = 656 utils::CreateImageCopyTexture(deviceWrappedTexture, 0, {0, 0, 0}); 657 wgpu::ImageCopyBuffer copyDst = utils::CreateImageCopyBuffer(copyDstBuffer, 0, 256); 658 659 wgpu::Extent3D copySize = {1, 1, 1}; 660 661 wgpu::CommandEncoder encoder = device.CreateCommandEncoder(); 662 encoder.CopyTextureToBuffer(©Src, ©Dst, ©Size); 663 wgpu::CommandBuffer commands = encoder.Finish(); 664 queue.Submit(1, &commands); 665 666 // Verify |copyDstBuffer| sees changes from |secondDevice| 667 uint32_t expected = 0x04030201; 668 EXPECT_BUFFER_U32_EQ(expected, copyDstBuffer, 0); 669 670 IgnoreSignalSemaphore(deviceWrappedTexture); 671 } 672 673 // Import a texture into |device| 674 // Copy color A into texture on |device| 675 // Import same texture into |secondDevice|, waiting on the copy signal 676 // Copy color B using Buffer to Texture copy on |secondDevice| 677 // Import texture back into |device|, waiting on color B signal 678 // Verify texture contains color B 679 // If texture destination isn't synchronized, |secondDevice| could copy color B 680 // into the texture first, then |device| writes color A TEST_P(VulkanImageWrappingUsageTests,CopyBufferToTextureDstSync)681 TEST_P(VulkanImageWrappingUsageTests, CopyBufferToTextureDstSync) { 682 // Import the image on |device| 683 wgpu::Texture wrappedTexture = WrapVulkanImage( 684 device, &defaultDescriptor, defaultFd, defaultAllocationSize, defaultMemoryTypeIndex, 685 {}, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); 686 687 // Clear |wrappedTexture| on |device| 688 ClearImage(device, wrappedTexture, {5 / 255.0f, 6 / 255.0f, 7 / 255.0f, 8 / 255.0f}); 689 690 dawn_native::vulkan::ExternalImageExportInfoOpaqueFD exportInfo; 691 dawn_native::vulkan::ExportVulkanImage(wrappedTexture.Get(), 692 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, &exportInfo); 693 694 // Import the image to |secondDevice|, making sure we wait on |signalFd| 695 int memoryFd = GetMemoryFd(deviceVk, defaultAllocation); 696 wgpu::Texture secondDeviceWrappedTexture = 697 WrapVulkanImage(secondDevice, &defaultDescriptor, memoryFd, defaultAllocationSize, 698 defaultMemoryTypeIndex, exportInfo.semaphoreHandles, 699 exportInfo.releasedOldLayout, exportInfo.releasedNewLayout); 700 701 // Copy color B on |secondDevice| 702 wgpu::Queue secondDeviceQueue = secondDevice.GetQueue(); 703 704 // Create a buffer on |secondDevice| 705 wgpu::Buffer copySrcBuffer = 706 utils::CreateBufferFromData(secondDevice, wgpu::BufferUsage::CopySrc, {0x04030201}); 707 708 // Copy |copySrcBuffer| into |secondDeviceWrappedTexture| 709 wgpu::ImageCopyBuffer copySrc = utils::CreateImageCopyBuffer(copySrcBuffer, 0, 256); 710 wgpu::ImageCopyTexture copyDst = 711 utils::CreateImageCopyTexture(secondDeviceWrappedTexture, 0, {0, 0, 0}); 712 713 wgpu::Extent3D copySize = {1, 1, 1}; 714 715 wgpu::CommandEncoder encoder = secondDevice.CreateCommandEncoder(); 716 encoder.CopyBufferToTexture(©Src, ©Dst, ©Size); 717 wgpu::CommandBuffer commands = encoder.Finish(); 718 secondDeviceQueue.Submit(1, &commands); 719 720 // Re-import back into |device|, waiting on |secondDevice|'s signal 721 dawn_native::vulkan::ExternalImageExportInfoOpaqueFD secondExportInfo; 722 dawn_native::vulkan::ExportVulkanImage(secondDeviceWrappedTexture.Get(), 723 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, 724 &secondExportInfo); 725 memoryFd = GetMemoryFd(deviceVk, defaultAllocation); 726 727 wgpu::Texture nextWrappedTexture = 728 WrapVulkanImage(device, &defaultDescriptor, memoryFd, defaultAllocationSize, 729 defaultMemoryTypeIndex, secondExportInfo.semaphoreHandles, 730 secondExportInfo.releasedOldLayout, secondExportInfo.releasedNewLayout); 731 732 // Verify |nextWrappedTexture| contains the color from our copy 733 EXPECT_PIXEL_RGBA8_EQ(RGBA8(1, 2, 3, 4), nextWrappedTexture, 0, 0); 734 735 IgnoreSignalSemaphore(nextWrappedTexture); 736 } 737 738 // Import a texture from |secondDevice| 739 // Issue a copy of the imported texture inside |device| to |copyDstTexture| 740 // Issue second copy to |secondCopyDstTexture| 741 // Verify the clear color from |secondDevice| is visible in both copies TEST_P(VulkanImageWrappingUsageTests,DoubleTextureUsage)742 TEST_P(VulkanImageWrappingUsageTests, DoubleTextureUsage) { 743 // Import the image on |secondDevice| 744 wgpu::Texture wrappedTexture = 745 WrapVulkanImage(secondDevice, &defaultDescriptor, defaultFd, defaultAllocationSize, 746 defaultMemoryTypeIndex, {}, VK_IMAGE_LAYOUT_UNDEFINED, 747 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); 748 749 // Clear |wrappedTexture| on |secondDevice| 750 ClearImage(secondDevice, wrappedTexture, {1 / 255.0f, 2 / 255.0f, 3 / 255.0f, 4 / 255.0f}); 751 752 dawn_native::vulkan::ExternalImageExportInfoOpaqueFD exportInfo; 753 dawn_native::vulkan::ExportVulkanImage(wrappedTexture.Get(), 754 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, &exportInfo); 755 756 // Import the image to |device|, making sure we wait on the semaphore 757 int memoryFd = GetMemoryFd(deviceVk, defaultAllocation); 758 wgpu::Texture deviceWrappedTexture = 759 WrapVulkanImage(device, &defaultDescriptor, memoryFd, defaultAllocationSize, 760 defaultMemoryTypeIndex, exportInfo.semaphoreHandles, 761 exportInfo.releasedOldLayout, exportInfo.releasedNewLayout); 762 763 // Create a second texture on |device| 764 wgpu::Texture copyDstTexture = device.CreateTexture(&defaultDescriptor); 765 766 // Create a third texture on |device| 767 wgpu::Texture secondCopyDstTexture = device.CreateTexture(&defaultDescriptor); 768 769 // Copy |deviceWrappedTexture| into |copyDstTexture| 770 SimpleCopyTextureToTexture(device, queue, deviceWrappedTexture, copyDstTexture); 771 772 // Copy |deviceWrappedTexture| into |secondCopyDstTexture| 773 SimpleCopyTextureToTexture(device, queue, deviceWrappedTexture, secondCopyDstTexture); 774 775 // Verify |copyDstTexture| sees changes from |secondDevice| 776 EXPECT_PIXEL_RGBA8_EQ(RGBA8(1, 2, 3, 4), copyDstTexture, 0, 0); 777 778 // Verify |secondCopyDstTexture| sees changes from |secondDevice| 779 EXPECT_PIXEL_RGBA8_EQ(RGBA8(1, 2, 3, 4), secondCopyDstTexture, 0, 0); 780 781 IgnoreSignalSemaphore(deviceWrappedTexture); 782 } 783 784 // Tex A on device 3 (external export) 785 // Tex B on device 2 (external export) 786 // Tex C on device 1 (external export) 787 // Clear color for A on device 3 788 // Copy A->B on device 3 789 // Copy B->C on device 2 (wait on B from previous op) 790 // Copy C->D on device 1 (wait on C from previous op) 791 // Verify D has same color as A TEST_P(VulkanImageWrappingUsageTests,ChainTextureCopy)792 TEST_P(VulkanImageWrappingUsageTests, ChainTextureCopy) { 793 // Close |defaultFd| since this test doesn't import it anywhere 794 close(defaultFd); 795 796 // device 1 = |device| 797 // device 2 = |secondDevice| 798 // Create device 3 799 dawn_native::vulkan::Device* thirdDeviceVk = 800 dawn_native::vulkan::ToBackend(backendAdapter->CreateDevice(&deviceDescriptor)); 801 wgpu::Device thirdDevice = wgpu::Device::Acquire(dawn_native::ToAPI(thirdDeviceVk)); 802 803 // Make queue for device 2 and 3 804 wgpu::Queue secondDeviceQueue = secondDevice.GetQueue(); 805 wgpu::Queue thirdDeviceQueue = thirdDevice.GetQueue(); 806 807 // Allocate memory for A, B, C 808 VkImage imageA; 809 VkDeviceMemory allocationA; 810 int memoryFdA; 811 VkDeviceSize allocationSizeA; 812 uint32_t memoryTypeIndexA; 813 CreateBindExportImage(thirdDeviceVk, 1, 1, VK_FORMAT_R8G8B8A8_UNORM, &imageA, &allocationA, 814 &allocationSizeA, &memoryTypeIndexA, &memoryFdA); 815 816 VkImage imageB; 817 VkDeviceMemory allocationB; 818 int memoryFdB; 819 VkDeviceSize allocationSizeB; 820 uint32_t memoryTypeIndexB; 821 CreateBindExportImage(secondDeviceVk, 1, 1, VK_FORMAT_R8G8B8A8_UNORM, &imageB, &allocationB, 822 &allocationSizeB, &memoryTypeIndexB, &memoryFdB); 823 824 VkImage imageC; 825 VkDeviceMemory allocationC; 826 int memoryFdC; 827 VkDeviceSize allocationSizeC; 828 uint32_t memoryTypeIndexC; 829 CreateBindExportImage(deviceVk, 1, 1, VK_FORMAT_R8G8B8A8_UNORM, &imageC, &allocationC, 830 &allocationSizeC, &memoryTypeIndexC, &memoryFdC); 831 832 // Import TexA, TexB on device 3 833 wgpu::Texture wrappedTexADevice3 = WrapVulkanImage( 834 thirdDevice, &defaultDescriptor, memoryFdA, allocationSizeA, memoryTypeIndexA, {}, 835 VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); 836 837 wgpu::Texture wrappedTexBDevice3 = WrapVulkanImage( 838 thirdDevice, &defaultDescriptor, memoryFdB, allocationSizeB, memoryTypeIndexB, {}, 839 VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); 840 841 // Clear TexA 842 ClearImage(thirdDevice, wrappedTexADevice3, 843 {1 / 255.0f, 2 / 255.0f, 3 / 255.0f, 4 / 255.0f}); 844 845 // Copy A->B 846 SimpleCopyTextureToTexture(thirdDevice, thirdDeviceQueue, wrappedTexADevice3, 847 wrappedTexBDevice3); 848 849 dawn_native::vulkan::ExternalImageExportInfoOpaqueFD exportInfoTexBDevice3; 850 dawn_native::vulkan::ExportVulkanImage( 851 wrappedTexBDevice3.Get(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, &exportInfoTexBDevice3); 852 853 IgnoreSignalSemaphore(wrappedTexADevice3); 854 855 // Import TexB, TexC on device 2 856 memoryFdB = GetMemoryFd(secondDeviceVk, allocationB); 857 wgpu::Texture wrappedTexBDevice2 = WrapVulkanImage( 858 secondDevice, &defaultDescriptor, memoryFdB, allocationSizeB, memoryTypeIndexB, 859 exportInfoTexBDevice3.semaphoreHandles, exportInfoTexBDevice3.releasedOldLayout, 860 exportInfoTexBDevice3.releasedNewLayout); 861 862 wgpu::Texture wrappedTexCDevice2 = WrapVulkanImage( 863 secondDevice, &defaultDescriptor, memoryFdC, allocationSizeC, memoryTypeIndexC, {}, 864 VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); 865 866 // Copy B->C on device 2 867 SimpleCopyTextureToTexture(secondDevice, secondDeviceQueue, wrappedTexBDevice2, 868 wrappedTexCDevice2); 869 870 dawn_native::vulkan::ExternalImageExportInfoOpaqueFD exportInfoTexCDevice2; 871 dawn_native::vulkan::ExportVulkanImage( 872 wrappedTexCDevice2.Get(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, &exportInfoTexCDevice2); 873 874 IgnoreSignalSemaphore(wrappedTexBDevice2); 875 876 // Import TexC on device 1 877 memoryFdC = GetMemoryFd(deviceVk, allocationC); 878 wgpu::Texture wrappedTexCDevice1 = WrapVulkanImage( 879 device, &defaultDescriptor, memoryFdC, allocationSizeC, memoryTypeIndexC, 880 exportInfoTexCDevice2.semaphoreHandles, exportInfoTexCDevice2.releasedOldLayout, 881 exportInfoTexCDevice2.releasedNewLayout); 882 883 // Create TexD on device 1 884 wgpu::Texture texD = device.CreateTexture(&defaultDescriptor); 885 886 // Copy C->D on device 1 887 SimpleCopyTextureToTexture(device, queue, wrappedTexCDevice1, texD); 888 889 // Verify D matches clear color 890 EXPECT_PIXEL_RGBA8_EQ(RGBA8(1, 2, 3, 4), texD, 0, 0); 891 892 thirdDeviceVk->GetFencedDeleter()->DeleteWhenUnused(imageA); 893 thirdDeviceVk->GetFencedDeleter()->DeleteWhenUnused(allocationA); 894 secondDeviceVk->GetFencedDeleter()->DeleteWhenUnused(imageB); 895 secondDeviceVk->GetFencedDeleter()->DeleteWhenUnused(allocationB); 896 deviceVk->GetFencedDeleter()->DeleteWhenUnused(imageC); 897 deviceVk->GetFencedDeleter()->DeleteWhenUnused(allocationC); 898 899 IgnoreSignalSemaphore(wrappedTexCDevice1); 900 } 901 902 // Tests a larger image is preserved when importing TEST_P(VulkanImageWrappingUsageTests,LargerImage)903 TEST_P(VulkanImageWrappingUsageTests, LargerImage) { 904 close(defaultFd); 905 906 wgpu::TextureDescriptor descriptor; 907 descriptor.dimension = wgpu::TextureDimension::e2D; 908 descriptor.size.width = 640; 909 descriptor.size.height = 480; 910 descriptor.size.depthOrArrayLayers = 1; 911 descriptor.sampleCount = 1; 912 descriptor.format = wgpu::TextureFormat::BGRA8Unorm; 913 descriptor.mipLevelCount = 1; 914 descriptor.usage = wgpu::TextureUsage::CopyDst | wgpu::TextureUsage::CopySrc; 915 916 // Fill memory with textures to trigger layout issues on AMD 917 std::vector<wgpu::Texture> textures; 918 for (int i = 0; i < 20; i++) { 919 textures.push_back(device.CreateTexture(&descriptor)); 920 } 921 922 wgpu::Queue secondDeviceQueue = secondDevice.GetQueue(); 923 924 // Make an image on |secondDevice| 925 VkImage imageA; 926 VkDeviceMemory allocationA; 927 int memoryFdA; 928 VkDeviceSize allocationSizeA; 929 uint32_t memoryTypeIndexA; 930 CreateBindExportImage(secondDeviceVk, 640, 480, VK_FORMAT_R8G8B8A8_UNORM, &imageA, 931 &allocationA, &allocationSizeA, &memoryTypeIndexA, &memoryFdA); 932 933 // Import the image on |secondDevice| 934 wgpu::Texture wrappedTexture = 935 WrapVulkanImage(secondDevice, &descriptor, memoryFdA, allocationSizeA, memoryTypeIndexA, 936 {}, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); 937 938 // Draw a non-trivial picture 939 uint32_t width = 640, height = 480, pixelSize = 4; 940 uint32_t bytesPerRow = Align(width * pixelSize, kTextureBytesPerRowAlignment); 941 std::vector<unsigned char> data(bytesPerRow * (height - 1) + width * pixelSize); 942 943 for (uint32_t row = 0; row < height; row++) { 944 for (uint32_t col = 0; col < width; col++) { 945 float normRow = static_cast<float>(row) / height; 946 float normCol = static_cast<float>(col) / width; 947 float dist = sqrt(normRow * normRow + normCol * normCol) * 3; 948 dist = dist - static_cast<int>(dist); 949 data[4 * (row * width + col)] = static_cast<unsigned char>(dist * 255); 950 data[4 * (row * width + col) + 1] = static_cast<unsigned char>(dist * 255); 951 data[4 * (row * width + col) + 2] = static_cast<unsigned char>(dist * 255); 952 data[4 * (row * width + col) + 3] = 255; 953 } 954 } 955 956 // Write the picture 957 { 958 wgpu::Buffer copySrcBuffer = utils::CreateBufferFromData( 959 secondDevice, data.data(), data.size(), wgpu::BufferUsage::CopySrc); 960 wgpu::ImageCopyBuffer copySrc = 961 utils::CreateImageCopyBuffer(copySrcBuffer, 0, bytesPerRow); 962 wgpu::ImageCopyTexture copyDst = 963 utils::CreateImageCopyTexture(wrappedTexture, 0, {0, 0, 0}); 964 wgpu::Extent3D copySize = {width, height, 1}; 965 966 wgpu::CommandEncoder encoder = secondDevice.CreateCommandEncoder(); 967 encoder.CopyBufferToTexture(©Src, ©Dst, ©Size); 968 wgpu::CommandBuffer commands = encoder.Finish(); 969 secondDeviceQueue.Submit(1, &commands); 970 } 971 972 dawn_native::vulkan::ExternalImageExportInfoOpaqueFD exportInfo; 973 dawn_native::vulkan::ExportVulkanImage(wrappedTexture.Get(), 974 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, &exportInfo); 975 976 int memoryFd = GetMemoryFd(secondDeviceVk, allocationA); 977 978 // Import the image on |device| 979 wgpu::Texture nextWrappedTexture = 980 WrapVulkanImage(device, &descriptor, memoryFd, allocationSizeA, memoryTypeIndexA, 981 exportInfo.semaphoreHandles, exportInfo.releasedOldLayout, 982 exportInfo.releasedNewLayout); 983 984 // Copy the image into a buffer for comparison 985 wgpu::BufferDescriptor copyDesc; 986 copyDesc.size = data.size(); 987 copyDesc.usage = wgpu::BufferUsage::CopySrc | wgpu::BufferUsage::CopyDst; 988 wgpu::Buffer copyDstBuffer = device.CreateBuffer(©Desc); 989 { 990 wgpu::ImageCopyTexture copySrc = 991 utils::CreateImageCopyTexture(nextWrappedTexture, 0, {0, 0, 0}); 992 wgpu::ImageCopyBuffer copyDst = 993 utils::CreateImageCopyBuffer(copyDstBuffer, 0, bytesPerRow); 994 995 wgpu::Extent3D copySize = {width, height, 1}; 996 997 wgpu::CommandEncoder encoder = device.CreateCommandEncoder(); 998 encoder.CopyTextureToBuffer(©Src, ©Dst, ©Size); 999 wgpu::CommandBuffer commands = encoder.Finish(); 1000 queue.Submit(1, &commands); 1001 } 1002 1003 // Check the image is not corrupted on |device| 1004 EXPECT_BUFFER_U32_RANGE_EQ(reinterpret_cast<uint32_t*>(data.data()), copyDstBuffer, 0, 1005 data.size() / 4); 1006 1007 IgnoreSignalSemaphore(nextWrappedTexture); 1008 secondDeviceVk->GetFencedDeleter()->DeleteWhenUnused(imageA); 1009 secondDeviceVk->GetFencedDeleter()->DeleteWhenUnused(allocationA); 1010 } 1011 1012 DAWN_INSTANTIATE_TEST(VulkanImageWrappingValidationTests, VulkanBackend()); 1013 DAWN_INSTANTIATE_TEST(VulkanImageWrappingUsageTests, VulkanBackend()); 1014 1015 }} // namespace dawn_native::vulkan 1016