1 // Copyright 2020 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 "tests/DawnTest.h" 16 17 #include "common/Math.h" 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 #include <fcntl.h> 29 #include <gbm.h> 30 31 namespace dawn_native { namespace vulkan { 32 33 namespace { 34 35 class VulkanImageWrappingTestBase : public DawnTest { 36 protected: GetRequiredFeatures()37 std::vector<const char*> GetRequiredFeatures() override { 38 return {"dawn-internal-usages"}; 39 } 40 41 public: SetUp()42 void SetUp() override { 43 DawnTest::SetUp(); 44 DAWN_TEST_UNSUPPORTED_IF(UsesWire()); 45 46 gbmDevice = CreateGbmDevice(); 47 deviceVk = dawn_native::vulkan::ToBackend(dawn_native::FromAPI(device.Get())); 48 49 defaultGbmBo = CreateGbmBo(1, 1, true /* linear */); 50 defaultStride = gbm_bo_get_stride_for_plane(defaultGbmBo, 0); 51 defaultModifier = gbm_bo_get_modifier(defaultGbmBo); 52 defaultFd = gbm_bo_get_fd(defaultGbmBo); 53 54 defaultDescriptor.dimension = wgpu::TextureDimension::e2D; 55 defaultDescriptor.format = wgpu::TextureFormat::RGBA8Unorm; 56 defaultDescriptor.size = {1, 1, 1}; 57 defaultDescriptor.sampleCount = 1; 58 defaultDescriptor.mipLevelCount = 1; 59 defaultDescriptor.usage = wgpu::TextureUsage::RenderAttachment | 60 wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::CopyDst; 61 } 62 TearDown()63 void TearDown() override { 64 if (UsesWire()) { 65 DawnTest::TearDown(); 66 return; 67 } 68 69 gbm_bo_destroy(defaultGbmBo); 70 gbm_device_destroy(gbmDevice); 71 72 DawnTest::TearDown(); 73 } 74 CreateGbmDevice()75 gbm_device* CreateGbmDevice() { 76 // Render nodes [1] are the primary interface for communicating with the GPU on 77 // devices that support DRM. The actual filename of the render node is 78 // implementation-specific, so we must scan through all possible filenames to find 79 // one that we can use [2]. 80 // 81 // [1] https://dri.freedesktop.org/docs/drm/gpu/drm-uapi.html#render-nodes 82 // [2] 83 // https://cs.chromium.org/chromium/src/ui/ozone/platform/wayland/gpu/drm_render_node_path_finder.cc 84 const uint32_t kRenderNodeStart = 128; 85 const uint32_t kRenderNodeEnd = kRenderNodeStart + 16; 86 const std::string kRenderNodeTemplate = "/dev/dri/renderD"; 87 88 int renderNodeFd = -1; 89 for (uint32_t i = kRenderNodeStart; i < kRenderNodeEnd; i++) { 90 std::string renderNode = kRenderNodeTemplate + std::to_string(i); 91 renderNodeFd = open(renderNode.c_str(), O_RDWR); 92 if (renderNodeFd >= 0) 93 break; 94 } 95 EXPECT_GE(renderNodeFd, 0) << "Failed to get file descriptor for render node"; 96 97 gbm_device* gbmDevice = gbm_create_device(renderNodeFd); 98 EXPECT_NE(gbmDevice, nullptr) << "Failed to create GBM device"; 99 return gbmDevice; 100 } 101 CreateGbmBo(uint32_t width,uint32_t height,bool linear)102 gbm_bo* CreateGbmBo(uint32_t width, uint32_t height, bool linear) { 103 uint32_t flags = GBM_BO_USE_RENDERING; 104 if (linear) 105 flags |= GBM_BO_USE_LINEAR; 106 gbm_bo* gbmBo = gbm_bo_create(gbmDevice, width, height, GBM_FORMAT_XBGR8888, flags); 107 EXPECT_NE(gbmBo, nullptr) << "Failed to create GBM buffer object"; 108 return gbmBo; 109 } 110 WrapVulkanImage(wgpu::Device dawnDevice,const wgpu::TextureDescriptor * textureDescriptor,int memoryFd,uint32_t stride,uint64_t drmModifier,std::vector<int> waitFDs,bool isInitialized=true,bool expectValid=true)111 wgpu::Texture WrapVulkanImage(wgpu::Device dawnDevice, 112 const wgpu::TextureDescriptor* textureDescriptor, 113 int memoryFd, 114 uint32_t stride, 115 uint64_t drmModifier, 116 std::vector<int> waitFDs, 117 bool isInitialized = true, 118 bool expectValid = true) { 119 dawn_native::vulkan::ExternalImageDescriptorDmaBuf descriptor; 120 return WrapVulkanImage(dawnDevice, textureDescriptor, memoryFd, stride, drmModifier, 121 waitFDs, descriptor.releasedOldLayout, 122 descriptor.releasedNewLayout, isInitialized, expectValid); 123 } 124 WrapVulkanImage(wgpu::Device dawnDevice,const wgpu::TextureDescriptor * textureDescriptor,int memoryFd,uint32_t stride,uint64_t drmModifier,std::vector<int> waitFDs,VkImageLayout releasedOldLayout,VkImageLayout releasedNewLayout,bool isInitialized=true,bool expectValid=true)125 wgpu::Texture WrapVulkanImage(wgpu::Device dawnDevice, 126 const wgpu::TextureDescriptor* textureDescriptor, 127 int memoryFd, 128 uint32_t stride, 129 uint64_t drmModifier, 130 std::vector<int> waitFDs, 131 VkImageLayout releasedOldLayout, 132 VkImageLayout releasedNewLayout, 133 bool isInitialized = true, 134 bool expectValid = true) { 135 dawn_native::vulkan::ExternalImageDescriptorDmaBuf descriptor; 136 descriptor.cTextureDescriptor = 137 reinterpret_cast<const WGPUTextureDescriptor*>(textureDescriptor); 138 descriptor.isInitialized = isInitialized; 139 descriptor.stride = stride; 140 descriptor.drmModifier = drmModifier; 141 descriptor.memoryFD = memoryFd; 142 descriptor.waitFDs = waitFDs; 143 descriptor.releasedOldLayout = releasedOldLayout; 144 descriptor.releasedNewLayout = releasedNewLayout; 145 146 WGPUTexture texture = 147 dawn_native::vulkan::WrapVulkanImage(dawnDevice.Get(), &descriptor); 148 149 if (expectValid) { 150 EXPECT_NE(texture, nullptr) << "Failed to wrap image, are external memory / " 151 "semaphore extensions supported?"; 152 } else { 153 EXPECT_EQ(texture, nullptr); 154 } 155 156 return wgpu::Texture::Acquire(texture); 157 } 158 159 // Exports the signal from a wrapped texture and ignores it 160 // We have to export the signal before destroying the wrapped texture else it's an 161 // assertion failure IgnoreSignalSemaphore(wgpu::Texture wrappedTexture)162 void IgnoreSignalSemaphore(wgpu::Texture wrappedTexture) { 163 dawn_native::vulkan::ExternalImageExportInfoDmaBuf exportInfo; 164 dawn_native::vulkan::ExportVulkanImage(wrappedTexture.Get(), VK_IMAGE_LAYOUT_GENERAL, &exportInfo); 165 for (int handle : exportInfo.semaphoreHandles) { 166 ASSERT_NE(handle, -1); 167 close(handle); 168 } 169 } 170 171 protected: 172 dawn_native::vulkan::Device* deviceVk; 173 gbm_device* gbmDevice; 174 wgpu::TextureDescriptor defaultDescriptor; 175 gbm_bo* defaultGbmBo; 176 int defaultFd; 177 uint32_t defaultStride; 178 uint64_t defaultModifier; 179 }; 180 181 } // anonymous namespace 182 183 using VulkanImageWrappingValidationTests = VulkanImageWrappingTestBase; 184 185 // Test no error occurs if the import is valid TEST_P(VulkanImageWrappingValidationTests,SuccessfulImport)186 TEST_P(VulkanImageWrappingValidationTests, SuccessfulImport) { 187 wgpu::Texture texture = WrapVulkanImage(device, &defaultDescriptor, defaultFd, 188 defaultStride, defaultModifier, {}, true, true); 189 EXPECT_NE(texture.Get(), nullptr); 190 IgnoreSignalSemaphore(texture); 191 } 192 193 // Test no error occurs if the import is valid with DawnTextureInternalUsageDescriptor TEST_P(VulkanImageWrappingValidationTests,SuccessfulImportWithInternalUsageDescriptor)194 TEST_P(VulkanImageWrappingValidationTests, SuccessfulImportWithInternalUsageDescriptor) { 195 wgpu::DawnTextureInternalUsageDescriptor internalDesc = {}; 196 defaultDescriptor.nextInChain = &internalDesc; 197 internalDesc.internalUsage = wgpu::TextureUsage::CopySrc; 198 internalDesc.sType = wgpu::SType::DawnTextureInternalUsageDescriptor; 199 200 wgpu::Texture texture = WrapVulkanImage(device, &defaultDescriptor, defaultFd, 201 defaultStride, defaultModifier, {}, true, true); 202 EXPECT_NE(texture.Get(), nullptr); 203 IgnoreSignalSemaphore(texture); 204 } 205 206 // Test an error occurs if an invalid sType is the nextInChain TEST_P(VulkanImageWrappingValidationTests,InvalidTextureDescriptor)207 TEST_P(VulkanImageWrappingValidationTests, InvalidTextureDescriptor) { 208 wgpu::ChainedStruct chainedDescriptor; 209 chainedDescriptor.sType = wgpu::SType::SurfaceDescriptorFromWindowsSwapChainPanel; 210 defaultDescriptor.nextInChain = &chainedDescriptor; 211 212 ASSERT_DEVICE_ERROR(wgpu::Texture texture = 213 WrapVulkanImage(device, &defaultDescriptor, defaultFd, 214 defaultStride, defaultModifier, {}, true, false)); 215 EXPECT_EQ(texture.Get(), nullptr); 216 close(defaultFd); 217 } 218 219 // Test an error occurs if the descriptor dimension isn't 2D TEST_P(VulkanImageWrappingValidationTests,InvalidTextureDimension)220 TEST_P(VulkanImageWrappingValidationTests, InvalidTextureDimension) { 221 defaultDescriptor.dimension = wgpu::TextureDimension::e1D; 222 223 ASSERT_DEVICE_ERROR(wgpu::Texture texture = 224 WrapVulkanImage(device, &defaultDescriptor, defaultFd, 225 defaultStride, defaultModifier, {}, true, false)); 226 EXPECT_EQ(texture.Get(), nullptr); 227 close(defaultFd); 228 } 229 230 // Test an error occurs if the descriptor mip level count isn't 1 TEST_P(VulkanImageWrappingValidationTests,InvalidMipLevelCount)231 TEST_P(VulkanImageWrappingValidationTests, InvalidMipLevelCount) { 232 defaultDescriptor.mipLevelCount = 2; 233 234 ASSERT_DEVICE_ERROR(wgpu::Texture texture = 235 WrapVulkanImage(device, &defaultDescriptor, defaultFd, 236 defaultStride, defaultModifier, {}, true, false)); 237 EXPECT_EQ(texture.Get(), nullptr); 238 close(defaultFd); 239 } 240 241 // Test an error occurs if the descriptor depth isn't 1 TEST_P(VulkanImageWrappingValidationTests,InvalidDepth)242 TEST_P(VulkanImageWrappingValidationTests, InvalidDepth) { 243 defaultDescriptor.size.depthOrArrayLayers = 2; 244 245 ASSERT_DEVICE_ERROR(wgpu::Texture texture = 246 WrapVulkanImage(device, &defaultDescriptor, defaultFd, 247 defaultStride, defaultModifier, {}, true, false)); 248 EXPECT_EQ(texture.Get(), nullptr); 249 close(defaultFd); 250 } 251 252 // Test an error occurs if the descriptor sample count isn't 1 TEST_P(VulkanImageWrappingValidationTests,InvalidSampleCount)253 TEST_P(VulkanImageWrappingValidationTests, InvalidSampleCount) { 254 defaultDescriptor.sampleCount = 4; 255 256 ASSERT_DEVICE_ERROR(wgpu::Texture texture = 257 WrapVulkanImage(device, &defaultDescriptor, defaultFd, 258 defaultStride, defaultModifier, {}, true, false)); 259 EXPECT_EQ(texture.Get(), nullptr); 260 close(defaultFd); 261 } 262 263 // Test an error occurs if we try to export the signal semaphore twice TEST_P(VulkanImageWrappingValidationTests,DoubleSignalSemaphoreExport)264 TEST_P(VulkanImageWrappingValidationTests, DoubleSignalSemaphoreExport) { 265 wgpu::Texture texture = WrapVulkanImage(device, &defaultDescriptor, defaultFd, 266 defaultStride, defaultModifier, {}, true, true); 267 ASSERT_NE(texture.Get(), nullptr); 268 IgnoreSignalSemaphore(texture); 269 270 dawn_native::vulkan::ExternalImageExportInfoDmaBuf exportInfo; 271 ASSERT_DEVICE_ERROR(bool success = dawn_native::vulkan::ExportVulkanImage( 272 texture.Get(), VK_IMAGE_LAYOUT_GENERAL, &exportInfo)); 273 ASSERT_FALSE(success); 274 } 275 276 // Test an error occurs if we try to export the signal semaphore from a normal texture TEST_P(VulkanImageWrappingValidationTests,NormalTextureSignalSemaphoreExport)277 TEST_P(VulkanImageWrappingValidationTests, NormalTextureSignalSemaphoreExport) { 278 close(defaultFd); 279 280 wgpu::Texture texture = device.CreateTexture(&defaultDescriptor); 281 ASSERT_NE(texture.Get(), nullptr); 282 283 dawn_native::vulkan::ExternalImageExportInfoDmaBuf exportInfo; 284 ASSERT_DEVICE_ERROR(bool success = dawn_native::vulkan::ExportVulkanImage( 285 texture.Get(), VK_IMAGE_LAYOUT_GENERAL, &exportInfo)); 286 ASSERT_FALSE(success); 287 } 288 289 // Test an error occurs if we try to export the signal semaphore from a destroyed texture TEST_P(VulkanImageWrappingValidationTests,DestroyedTextureSignalSemaphoreExport)290 TEST_P(VulkanImageWrappingValidationTests, DestroyedTextureSignalSemaphoreExport) { 291 close(defaultFd); 292 293 wgpu::Texture texture = device.CreateTexture(&defaultDescriptor); 294 ASSERT_NE(texture.Get(), nullptr); 295 texture.Destroy(); 296 297 dawn_native::vulkan::ExternalImageExportInfoDmaBuf exportInfo; 298 ASSERT_DEVICE_ERROR(bool success = dawn_native::vulkan::ExportVulkanImage( 299 texture.Get(), VK_IMAGE_LAYOUT_GENERAL, &exportInfo)); 300 ASSERT_FALSE(success); 301 } 302 303 // Fixture to test using external memory textures through different usages. 304 // These tests are skipped if the harness is using the wire. 305 class VulkanImageWrappingUsageTests : public VulkanImageWrappingTestBase { 306 public: SetUp()307 void SetUp() override { 308 VulkanImageWrappingTestBase::SetUp(); 309 if (UsesWire()) { 310 return; 311 } 312 313 // Create another device based on the original 314 backendAdapter = dawn_native::vulkan::ToBackend(deviceVk->GetAdapter()); 315 deviceDescriptor.forceEnabledToggles = GetParam().forceEnabledWorkarounds; 316 deviceDescriptor.forceDisabledToggles = GetParam().forceDisabledWorkarounds; 317 318 secondDeviceVk = 319 dawn_native::vulkan::ToBackend(backendAdapter->CreateDevice(&deviceDescriptor)); 320 secondDevice = wgpu::Device::Acquire(dawn_native::ToAPI(secondDeviceVk)); 321 } 322 323 protected: 324 dawn_native::vulkan::Adapter* backendAdapter; 325 dawn_native::DawnDeviceDescriptor deviceDescriptor; 326 327 wgpu::Device secondDevice; 328 dawn_native::vulkan::Device* secondDeviceVk; 329 330 // Clear a texture on a given device ClearImage(wgpu::Device dawnDevice,wgpu::Texture wrappedTexture,wgpu::Color clearColor)331 void ClearImage(wgpu::Device dawnDevice, 332 wgpu::Texture wrappedTexture, 333 wgpu::Color clearColor) { 334 wgpu::TextureView wrappedView = wrappedTexture.CreateView(); 335 336 // Submit a clear operation 337 utils::ComboRenderPassDescriptor renderPassDescriptor({wrappedView}, {}); 338 renderPassDescriptor.cColorAttachments[0].clearColor = clearColor; 339 renderPassDescriptor.cColorAttachments[0].loadOp = wgpu::LoadOp::Clear; 340 341 wgpu::CommandEncoder encoder = dawnDevice.CreateCommandEncoder(); 342 wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPassDescriptor); 343 pass.EndPass(); 344 345 wgpu::CommandBuffer commands = encoder.Finish(); 346 347 wgpu::Queue queue = dawnDevice.GetQueue(); 348 queue.Submit(1, &commands); 349 } 350 351 // Submits a 1x1x1 copy from source to destination SimpleCopyTextureToTexture(wgpu::Device dawnDevice,wgpu::Queue dawnQueue,wgpu::Texture source,wgpu::Texture destination)352 void SimpleCopyTextureToTexture(wgpu::Device dawnDevice, 353 wgpu::Queue dawnQueue, 354 wgpu::Texture source, 355 wgpu::Texture destination) { 356 wgpu::ImageCopyTexture copySrc = utils::CreateImageCopyTexture(source, 0, {0, 0, 0}); 357 wgpu::ImageCopyTexture copyDst = 358 utils::CreateImageCopyTexture(destination, 0, {0, 0, 0}); 359 360 wgpu::Extent3D copySize = {1, 1, 1}; 361 362 wgpu::CommandEncoder encoder = dawnDevice.CreateCommandEncoder(); 363 encoder.CopyTextureToTexture(©Src, ©Dst, ©Size); 364 wgpu::CommandBuffer commands = encoder.Finish(); 365 366 dawnQueue.Submit(1, &commands); 367 } 368 }; 369 370 // Clear an image in |secondDevice| 371 // Verify clear color is visible in |device| TEST_P(VulkanImageWrappingUsageTests,ClearImageAcrossDevices)372 TEST_P(VulkanImageWrappingUsageTests, ClearImageAcrossDevices) { 373 // Import the image on |secondDevice| 374 wgpu::Texture wrappedTexture = WrapVulkanImage( 375 secondDevice, &defaultDescriptor, defaultFd, defaultStride, defaultModifier, {}, 376 VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); 377 378 // Clear |wrappedTexture| on |secondDevice| 379 ClearImage(secondDevice, wrappedTexture, {1 / 255.0f, 2 / 255.0f, 3 / 255.0f, 4 / 255.0f}); 380 381 dawn_native::vulkan::ExternalImageExportInfoDmaBuf exportInfo; 382 dawn_native::vulkan::ExportVulkanImage(wrappedTexture.Get(), 383 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, &exportInfo); 384 385 // Import the image to |device|, making sure we wait on signalFd 386 int nextFd = gbm_bo_get_fd(defaultGbmBo); 387 wgpu::Texture nextWrappedTexture = 388 WrapVulkanImage(device, &defaultDescriptor, nextFd, defaultStride, defaultModifier, 389 exportInfo.semaphoreHandles, exportInfo.releasedOldLayout, 390 exportInfo.releasedNewLayout); 391 392 // Verify |device| sees the changes from |secondDevice| 393 EXPECT_PIXEL_RGBA8_EQ(RGBA8(1, 2, 3, 4), nextWrappedTexture, 0, 0); 394 395 IgnoreSignalSemaphore(nextWrappedTexture); 396 } 397 398 // Clear an image in |secondDevice| 399 // Verify clear color is not visible in |device| if we import the texture as not cleared TEST_P(VulkanImageWrappingUsageTests,UninitializedTextureIsCleared)400 TEST_P(VulkanImageWrappingUsageTests, UninitializedTextureIsCleared) { 401 // Import the image on |secondDevice| 402 wgpu::Texture wrappedTexture = WrapVulkanImage( 403 secondDevice, &defaultDescriptor, defaultFd, defaultStride, defaultModifier, {}, 404 VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); 405 406 // Clear |wrappedTexture| on |secondDevice| 407 ClearImage(secondDevice, wrappedTexture, {1 / 255.0f, 2 / 255.0f, 3 / 255.0f, 4 / 255.0f}); 408 409 dawn_native::vulkan::ExternalImageExportInfoDmaBuf exportInfo; 410 dawn_native::vulkan::ExportVulkanImage(wrappedTexture.Get(), 411 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, &exportInfo); 412 413 // Import the image to |device|, making sure we wait on signalFd 414 int nextFd = gbm_bo_get_fd(defaultGbmBo); 415 wgpu::Texture nextWrappedTexture = 416 WrapVulkanImage(device, &defaultDescriptor, nextFd, defaultStride, defaultModifier, 417 exportInfo.semaphoreHandles, exportInfo.releasedOldLayout, 418 exportInfo.releasedNewLayout, false); 419 420 // Verify |device| doesn't see the changes from |secondDevice| 421 EXPECT_PIXEL_RGBA8_EQ(RGBA8(0, 0, 0, 0), nextWrappedTexture, 0, 0); 422 423 IgnoreSignalSemaphore(nextWrappedTexture); 424 } 425 426 // Import a texture into |secondDevice| 427 // Clear the texture on |secondDevice| 428 // Issue a copy of the imported texture inside |device| to |copyDstTexture| 429 // Verify the clear color from |secondDevice| is visible in |copyDstTexture| TEST_P(VulkanImageWrappingUsageTests,CopyTextureToTextureSrcSync)430 TEST_P(VulkanImageWrappingUsageTests, CopyTextureToTextureSrcSync) { 431 // Import the image on |secondDevice| 432 wgpu::Texture wrappedTexture = WrapVulkanImage( 433 secondDevice, &defaultDescriptor, defaultFd, defaultStride, defaultModifier, {}, 434 VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); 435 436 // Clear |wrappedTexture| on |secondDevice| 437 ClearImage(secondDevice, wrappedTexture, {1 / 255.0f, 2 / 255.0f, 3 / 255.0f, 4 / 255.0f}); 438 439 dawn_native::vulkan::ExternalImageExportInfoDmaBuf exportInfo; 440 dawn_native::vulkan::ExportVulkanImage(wrappedTexture.Get(), 441 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, &exportInfo); 442 443 // Import the image to |device|, making sure we wait on |signalFd| 444 int nextFd = gbm_bo_get_fd(defaultGbmBo); 445 wgpu::Texture deviceWrappedTexture = 446 WrapVulkanImage(device, &defaultDescriptor, nextFd, defaultStride, defaultModifier, 447 exportInfo.semaphoreHandles, exportInfo.releasedOldLayout, 448 exportInfo.releasedNewLayout); 449 450 // Create a second texture on |device| 451 wgpu::Texture copyDstTexture = device.CreateTexture(&defaultDescriptor); 452 453 // Copy |deviceWrappedTexture| into |copyDstTexture| 454 SimpleCopyTextureToTexture(device, queue, deviceWrappedTexture, copyDstTexture); 455 456 // Verify |copyDstTexture| sees changes from |secondDevice| 457 EXPECT_PIXEL_RGBA8_EQ(RGBA8(1, 2, 3, 4), copyDstTexture, 0, 0); 458 459 IgnoreSignalSemaphore(deviceWrappedTexture); 460 } 461 462 // Import a texture into |device| 463 // Clear texture with color A on |device| 464 // Import same texture into |secondDevice|, waiting on the copy signal 465 // Clear the new texture with color B on |secondDevice| 466 // Copy color B using Texture to Texture copy on |secondDevice| 467 // Import texture back into |device|, waiting on color B signal 468 // Verify texture contains color B 469 // If texture destination isn't synchronized, |secondDevice| could copy color B 470 // into the texture first, then |device| writes color A TEST_P(VulkanImageWrappingUsageTests,CopyTextureToTextureDstSync)471 TEST_P(VulkanImageWrappingUsageTests, CopyTextureToTextureDstSync) { 472 // Import the image on |device| 473 wgpu::Texture wrappedTexture = WrapVulkanImage( 474 device, &defaultDescriptor, defaultFd, defaultStride, defaultModifier, {}, 475 VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); 476 477 // Clear |wrappedTexture| on |device| 478 ClearImage(device, wrappedTexture, {5 / 255.0f, 6 / 255.0f, 7 / 255.0f, 8 / 255.0f}); 479 480 dawn_native::vulkan::ExternalImageExportInfoDmaBuf exportInfo; 481 dawn_native::vulkan::ExportVulkanImage(wrappedTexture.Get(), 482 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &exportInfo); 483 484 // Import the image to |secondDevice|, making sure we wait on |signalFd| 485 int nextFd = gbm_bo_get_fd(defaultGbmBo); 486 wgpu::Texture secondDeviceWrappedTexture = 487 WrapVulkanImage(secondDevice, &defaultDescriptor, nextFd, defaultStride, 488 defaultModifier, exportInfo.semaphoreHandles, 489 exportInfo.releasedOldLayout, exportInfo.releasedNewLayout); 490 491 // Create a texture with color B on |secondDevice| 492 wgpu::Texture copySrcTexture = secondDevice.CreateTexture(&defaultDescriptor); 493 ClearImage(secondDevice, copySrcTexture, {1 / 255.0f, 2 / 255.0f, 3 / 255.0f, 4 / 255.0f}); 494 495 // Copy color B on |secondDevice| 496 wgpu::Queue secondDeviceQueue = secondDevice.GetQueue(); 497 SimpleCopyTextureToTexture(secondDevice, secondDeviceQueue, copySrcTexture, 498 secondDeviceWrappedTexture); 499 500 // Re-import back into |device|, waiting on |secondDevice|'s signal 501 dawn_native::vulkan::ExternalImageExportInfoDmaBuf secondExportInfo; 502 dawn_native::vulkan::ExportVulkanImage(secondDeviceWrappedTexture.Get(), 503 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, 504 &secondExportInfo); 505 nextFd = gbm_bo_get_fd(defaultGbmBo); 506 507 wgpu::Texture nextWrappedTexture = 508 WrapVulkanImage(device, &defaultDescriptor, nextFd, defaultStride, defaultModifier, 509 secondExportInfo.semaphoreHandles, secondExportInfo.releasedOldLayout, 510 secondExportInfo.releasedNewLayout); 511 512 // Verify |nextWrappedTexture| contains the color from our copy 513 EXPECT_PIXEL_RGBA8_EQ(RGBA8(1, 2, 3, 4), nextWrappedTexture, 0, 0); 514 515 IgnoreSignalSemaphore(nextWrappedTexture); 516 } 517 518 // Import a texture from |secondDevice| 519 // Clear the texture on |secondDevice| 520 // Issue a copy of the imported texture inside |device| to |copyDstBuffer| 521 // Verify the clear color from |secondDevice| is visible in |copyDstBuffer| TEST_P(VulkanImageWrappingUsageTests,CopyTextureToBufferSrcSync)522 TEST_P(VulkanImageWrappingUsageTests, CopyTextureToBufferSrcSync) { 523 // Import the image on |secondDevice| 524 wgpu::Texture wrappedTexture = WrapVulkanImage( 525 secondDevice, &defaultDescriptor, defaultFd, defaultStride, defaultModifier, {}, 526 VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); 527 528 // Clear |wrappedTexture| on |secondDevice| 529 ClearImage(secondDevice, wrappedTexture, {1 / 255.0f, 2 / 255.0f, 3 / 255.0f, 4 / 255.0f}); 530 531 dawn_native::vulkan::ExternalImageExportInfoDmaBuf exportInfo; 532 dawn_native::vulkan::ExportVulkanImage(wrappedTexture.Get(), 533 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, &exportInfo); 534 535 // Import the image to |device|, making sure we wait on |signalFd| 536 int nextFd = gbm_bo_get_fd(defaultGbmBo); 537 wgpu::Texture deviceWrappedTexture = 538 WrapVulkanImage(device, &defaultDescriptor, nextFd, defaultStride, defaultModifier, 539 exportInfo.semaphoreHandles, exportInfo.releasedOldLayout, 540 exportInfo.releasedNewLayout); 541 542 // Create a destination buffer on |device| 543 wgpu::BufferDescriptor bufferDesc; 544 bufferDesc.size = 4; 545 bufferDesc.usage = wgpu::BufferUsage::CopyDst | wgpu::BufferUsage::CopySrc; 546 wgpu::Buffer copyDstBuffer = device.CreateBuffer(&bufferDesc); 547 548 // Copy |deviceWrappedTexture| into |copyDstBuffer| 549 wgpu::ImageCopyTexture copySrc = 550 utils::CreateImageCopyTexture(deviceWrappedTexture, 0, {0, 0, 0}); 551 wgpu::ImageCopyBuffer copyDst = utils::CreateImageCopyBuffer(copyDstBuffer, 0, 256); 552 553 wgpu::Extent3D copySize = {1, 1, 1}; 554 555 wgpu::CommandEncoder encoder = device.CreateCommandEncoder(); 556 encoder.CopyTextureToBuffer(©Src, ©Dst, ©Size); 557 wgpu::CommandBuffer commands = encoder.Finish(); 558 queue.Submit(1, &commands); 559 560 // Verify |copyDstBuffer| sees changes from |secondDevice| 561 uint32_t expected = 0x04030201; 562 EXPECT_BUFFER_U32_EQ(expected, copyDstBuffer, 0); 563 564 IgnoreSignalSemaphore(deviceWrappedTexture); 565 } 566 567 // Import a texture into |device| 568 // Clear texture with color A on |device| 569 // Import same texture into |secondDevice|, waiting on the copy signal 570 // Copy color B using Buffer to Texture copy on |secondDevice| 571 // Import texture back into |device|, waiting on color B signal 572 // Verify texture contains color B 573 // If texture destination isn't synchronized, |secondDevice| could copy color B 574 // into the texture first, then |device| writes color A TEST_P(VulkanImageWrappingUsageTests,CopyBufferToTextureDstSync)575 TEST_P(VulkanImageWrappingUsageTests, CopyBufferToTextureDstSync) { 576 // Import the image on |device| 577 wgpu::Texture wrappedTexture = WrapVulkanImage( 578 device, &defaultDescriptor, defaultFd, defaultStride, defaultModifier, {}, 579 VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); 580 581 // Clear |wrappedTexture| on |device| 582 ClearImage(device, wrappedTexture, {5 / 255.0f, 6 / 255.0f, 7 / 255.0f, 8 / 255.0f}); 583 584 dawn_native::vulkan::ExternalImageExportInfoDmaBuf exportInfo; 585 dawn_native::vulkan::ExportVulkanImage(wrappedTexture.Get(), 586 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, &exportInfo); 587 588 // Import the image to |secondDevice|, making sure we wait on |signalFd| 589 int nextFd = gbm_bo_get_fd(defaultGbmBo); 590 wgpu::Texture secondDeviceWrappedTexture = 591 WrapVulkanImage(secondDevice, &defaultDescriptor, nextFd, defaultStride, 592 defaultModifier, exportInfo.semaphoreHandles, 593 exportInfo.releasedOldLayout, exportInfo.releasedNewLayout); 594 595 // Copy color B on |secondDevice| 596 wgpu::Queue secondDeviceQueue = secondDevice.GetQueue(); 597 598 // Create a buffer on |secondDevice| 599 wgpu::Buffer copySrcBuffer = 600 utils::CreateBufferFromData(secondDevice, wgpu::BufferUsage::CopySrc, {0x04030201}); 601 602 // Copy |copySrcBuffer| into |secondDeviceWrappedTexture| 603 wgpu::ImageCopyBuffer copySrc = utils::CreateImageCopyBuffer(copySrcBuffer, 0, 256); 604 wgpu::ImageCopyTexture copyDst = 605 utils::CreateImageCopyTexture(secondDeviceWrappedTexture, 0, {0, 0, 0}); 606 607 wgpu::Extent3D copySize = {1, 1, 1}; 608 609 wgpu::CommandEncoder encoder = secondDevice.CreateCommandEncoder(); 610 encoder.CopyBufferToTexture(©Src, ©Dst, ©Size); 611 wgpu::CommandBuffer commands = encoder.Finish(); 612 secondDeviceQueue.Submit(1, &commands); 613 614 // Re-import back into |device|, waiting on |secondDevice|'s signal 615 dawn_native::vulkan::ExternalImageExportInfoDmaBuf secondExportInfo; 616 dawn_native::vulkan::ExportVulkanImage(secondDeviceWrappedTexture.Get(), 617 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, 618 &secondExportInfo); 619 nextFd = gbm_bo_get_fd(defaultGbmBo); 620 621 wgpu::Texture nextWrappedTexture = 622 WrapVulkanImage(device, &defaultDescriptor, nextFd, defaultStride, defaultModifier, 623 secondExportInfo.semaphoreHandles, secondExportInfo.releasedOldLayout, 624 secondExportInfo.releasedNewLayout); 625 626 // Verify |nextWrappedTexture| contains the color from our copy 627 EXPECT_PIXEL_RGBA8_EQ(RGBA8(1, 2, 3, 4), nextWrappedTexture, 0, 0); 628 629 IgnoreSignalSemaphore(nextWrappedTexture); 630 } 631 632 // Import a texture from |secondDevice| 633 // Clear the texture on |secondDevice| 634 // Issue a copy of the imported texture inside |device| to |copyDstTexture| 635 // Issue second copy to |secondCopyDstTexture| 636 // Verify the clear color from |secondDevice| is visible in both copies TEST_P(VulkanImageWrappingUsageTests,DoubleTextureUsage)637 TEST_P(VulkanImageWrappingUsageTests, DoubleTextureUsage) { 638 // Import the image on |secondDevice| 639 wgpu::Texture wrappedTexture = WrapVulkanImage( 640 secondDevice, &defaultDescriptor, defaultFd, defaultStride, defaultModifier, {}, 641 VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); 642 643 // Clear |wrappedTexture| on |secondDevice| 644 ClearImage(secondDevice, wrappedTexture, {1 / 255.0f, 2 / 255.0f, 3 / 255.0f, 4 / 255.0f}); 645 646 dawn_native::vulkan::ExternalImageExportInfoDmaBuf exportInfo; 647 dawn_native::vulkan::ExportVulkanImage(wrappedTexture.Get(), 648 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, &exportInfo); 649 650 // Import the image to |device|, making sure we wait on |signalFd| 651 int nextFd = gbm_bo_get_fd(defaultGbmBo); 652 wgpu::Texture deviceWrappedTexture = 653 WrapVulkanImage(device, &defaultDescriptor, nextFd, defaultStride, defaultModifier, 654 exportInfo.semaphoreHandles, exportInfo.releasedOldLayout, 655 exportInfo.releasedNewLayout); 656 657 // Create a second texture on |device| 658 wgpu::Texture copyDstTexture = device.CreateTexture(&defaultDescriptor); 659 660 // Create a third texture on |device| 661 wgpu::Texture secondCopyDstTexture = device.CreateTexture(&defaultDescriptor); 662 663 // Copy |deviceWrappedTexture| into |copyDstTexture| 664 SimpleCopyTextureToTexture(device, queue, deviceWrappedTexture, copyDstTexture); 665 666 // Copy |deviceWrappedTexture| into |secondCopyDstTexture| 667 SimpleCopyTextureToTexture(device, queue, deviceWrappedTexture, secondCopyDstTexture); 668 669 // Verify |copyDstTexture| sees changes from |secondDevice| 670 EXPECT_PIXEL_RGBA8_EQ(RGBA8(1, 2, 3, 4), copyDstTexture, 0, 0); 671 672 // Verify |secondCopyDstTexture| sees changes from |secondDevice| 673 EXPECT_PIXEL_RGBA8_EQ(RGBA8(1, 2, 3, 4), secondCopyDstTexture, 0, 0); 674 675 IgnoreSignalSemaphore(deviceWrappedTexture); 676 } 677 678 // Tex A on device 3 (external export) 679 // Tex B on device 2 (external export) 680 // Tex C on device 1 (external export) 681 // Clear color for A on device 3 682 // Copy A->B on device 3 683 // Copy B->C on device 2 (wait on B from previous op) 684 // Copy C->D on device 1 (wait on C from previous op) 685 // Verify D has same color as A TEST_P(VulkanImageWrappingUsageTests,ChainTextureCopy)686 TEST_P(VulkanImageWrappingUsageTests, ChainTextureCopy) { 687 // Close |defaultFd| since this test doesn't import it anywhere 688 close(defaultFd); 689 690 // device 1 = |device| 691 // device 2 = |secondDevice| 692 // Create device 3 693 dawn_native::vulkan::Device* thirdDeviceVk = 694 dawn_native::vulkan::ToBackend(backendAdapter->CreateDevice(&deviceDescriptor)); 695 wgpu::Device thirdDevice = wgpu::Device::Acquire(dawn_native::ToAPI(thirdDeviceVk)); 696 697 // Make queue for device 2 and 3 698 wgpu::Queue secondDeviceQueue = secondDevice.GetQueue(); 699 wgpu::Queue thirdDeviceQueue = thirdDevice.GetQueue(); 700 701 // Create BOs for A, B, C 702 gbm_bo* gbmBoA = CreateGbmBo(1, 1, true /* linear */); 703 uint32_t fdA = gbm_bo_get_fd(gbmBoA); 704 uint32_t strideA = gbm_bo_get_stride_for_plane(gbmBoA, 0); 705 uint64_t modifierA = gbm_bo_get_modifier(gbmBoA); 706 707 gbm_bo* gbmBoB = CreateGbmBo(1, 1, true /* linear */); 708 uint32_t fdB = gbm_bo_get_fd(gbmBoB); 709 uint32_t strideB = gbm_bo_get_stride_for_plane(gbmBoB, 0); 710 uint64_t modifierB = gbm_bo_get_modifier(gbmBoB); 711 712 gbm_bo* gbmBoC = CreateGbmBo(1, 1, true /* linear */); 713 uint32_t fdC = gbm_bo_get_fd(gbmBoC); 714 uint32_t strideC = gbm_bo_get_stride_for_plane(gbmBoC, 0); 715 uint64_t modifierC = gbm_bo_get_modifier(gbmBoC); 716 717 // Import TexA, TexB on device 3 718 wgpu::Texture wrappedTexADevice3 = 719 WrapVulkanImage(thirdDevice, &defaultDescriptor, fdA, strideA, modifierA, {}, 720 VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); 721 722 wgpu::Texture wrappedTexBDevice3 = 723 WrapVulkanImage(thirdDevice, &defaultDescriptor, fdB, strideB, modifierB, {}, 724 VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); 725 726 // Clear TexA 727 ClearImage(thirdDevice, wrappedTexADevice3, 728 {1 / 255.0f, 2 / 255.0f, 3 / 255.0f, 4 / 255.0f}); 729 730 // Copy A->B 731 SimpleCopyTextureToTexture(thirdDevice, thirdDeviceQueue, wrappedTexADevice3, 732 wrappedTexBDevice3); 733 734 dawn_native::vulkan::ExternalImageExportInfoDmaBuf exportInfoTexBDevice3; 735 dawn_native::vulkan::ExportVulkanImage( 736 wrappedTexBDevice3.Get(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, &exportInfoTexBDevice3); 737 IgnoreSignalSemaphore(wrappedTexADevice3); 738 739 // Import TexB, TexC on device 2 740 fdB = gbm_bo_get_fd(gbmBoB); 741 wgpu::Texture wrappedTexBDevice2 = WrapVulkanImage( 742 secondDevice, &defaultDescriptor, fdB, strideB, modifierB, 743 exportInfoTexBDevice3.semaphoreHandles, exportInfoTexBDevice3.releasedOldLayout, 744 exportInfoTexBDevice3.releasedNewLayout); 745 746 wgpu::Texture wrappedTexCDevice2 = 747 WrapVulkanImage(secondDevice, &defaultDescriptor, fdC, strideC, modifierC, {}, 748 VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); 749 750 // Copy B->C on device 2 751 SimpleCopyTextureToTexture(secondDevice, secondDeviceQueue, wrappedTexBDevice2, 752 wrappedTexCDevice2); 753 754 dawn_native::vulkan::ExternalImageExportInfoDmaBuf exportInfoTexCDevice2; 755 dawn_native::vulkan::ExportVulkanImage( 756 wrappedTexCDevice2.Get(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, &exportInfoTexCDevice2); 757 IgnoreSignalSemaphore(wrappedTexBDevice2); 758 759 // Import TexC on device 1 760 fdC = gbm_bo_get_fd(gbmBoC); 761 wgpu::Texture wrappedTexCDevice1 = WrapVulkanImage( 762 device, &defaultDescriptor, fdC, strideC, modifierC, 763 exportInfoTexCDevice2.semaphoreHandles, exportInfoTexCDevice2.releasedOldLayout, 764 exportInfoTexCDevice2.releasedNewLayout); 765 766 // Create TexD on device 1 767 wgpu::Texture texD = device.CreateTexture(&defaultDescriptor); 768 769 // Copy C->D on device 1 770 SimpleCopyTextureToTexture(device, queue, wrappedTexCDevice1, texD); 771 772 // Verify D matches clear color 773 EXPECT_PIXEL_RGBA8_EQ(RGBA8(1, 2, 3, 4), texD, 0, 0); 774 775 IgnoreSignalSemaphore(wrappedTexCDevice1); 776 } 777 778 // Tests a larger image is preserved when importing TEST_P(VulkanImageWrappingUsageTests,LargerImage)779 TEST_P(VulkanImageWrappingUsageTests, LargerImage) { 780 close(defaultFd); 781 782 wgpu::TextureDescriptor descriptor; 783 descriptor.dimension = wgpu::TextureDimension::e2D; 784 descriptor.size.width = 640; 785 descriptor.size.height = 480; 786 descriptor.size.depthOrArrayLayers = 1; 787 descriptor.sampleCount = 1; 788 descriptor.format = wgpu::TextureFormat::BGRA8Unorm; 789 descriptor.mipLevelCount = 1; 790 descriptor.usage = wgpu::TextureUsage::CopyDst | wgpu::TextureUsage::CopySrc; 791 792 // Fill memory with textures 793 std::vector<wgpu::Texture> textures; 794 for (int i = 0; i < 20; i++) { 795 textures.push_back(device.CreateTexture(&descriptor)); 796 } 797 798 wgpu::Queue secondDeviceQueue = secondDevice.GetQueue(); 799 800 // Make an image on |secondDevice| 801 gbm_bo* gbmBo = CreateGbmBo(640, 480, false /* linear */); 802 uint32_t fd = gbm_bo_get_fd(gbmBo); 803 uint32_t stride = gbm_bo_get_stride_for_plane(gbmBo, 0); 804 uint64_t modifier = gbm_bo_get_modifier(gbmBo); 805 806 // Import the image on |secondDevice| 807 wgpu::Texture wrappedTexture = 808 WrapVulkanImage(secondDevice, &descriptor, fd, stride, modifier, {}, 809 VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); 810 811 // Draw a non-trivial picture 812 uint32_t width = 640, height = 480, pixelSize = 4; 813 uint32_t bytesPerRow = Align(width * pixelSize, kTextureBytesPerRowAlignment); 814 std::vector<unsigned char> data(bytesPerRow * (height - 1) + width * pixelSize); 815 816 for (uint32_t row = 0; row < height; row++) { 817 for (uint32_t col = 0; col < width; col++) { 818 float normRow = static_cast<float>(row) / height; 819 float normCol = static_cast<float>(col) / width; 820 float dist = sqrt(normRow * normRow + normCol * normCol) * 3; 821 dist = dist - static_cast<int>(dist); 822 data[4 * (row * width + col)] = static_cast<unsigned char>(dist * 255); 823 data[4 * (row * width + col) + 1] = static_cast<unsigned char>(dist * 255); 824 data[4 * (row * width + col) + 2] = static_cast<unsigned char>(dist * 255); 825 data[4 * (row * width + col) + 3] = 255; 826 } 827 } 828 829 // Write the picture 830 { 831 wgpu::Buffer copySrcBuffer = utils::CreateBufferFromData( 832 secondDevice, data.data(), data.size(), wgpu::BufferUsage::CopySrc); 833 wgpu::ImageCopyBuffer copySrc = 834 utils::CreateImageCopyBuffer(copySrcBuffer, 0, bytesPerRow); 835 wgpu::ImageCopyTexture copyDst = 836 utils::CreateImageCopyTexture(wrappedTexture, 0, {0, 0, 0}); 837 wgpu::Extent3D copySize = {width, height, 1}; 838 839 wgpu::CommandEncoder encoder = secondDevice.CreateCommandEncoder(); 840 encoder.CopyBufferToTexture(©Src, ©Dst, ©Size); 841 wgpu::CommandBuffer commands = encoder.Finish(); 842 secondDeviceQueue.Submit(1, &commands); 843 } 844 dawn_native::vulkan::ExternalImageExportInfoDmaBuf exportInfo; 845 dawn_native::vulkan::ExportVulkanImage(wrappedTexture.Get(), 846 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, &exportInfo); 847 int nextFd = gbm_bo_get_fd(gbmBo); 848 849 // Import the image on |device| 850 wgpu::Texture nextWrappedTexture = WrapVulkanImage( 851 device, &descriptor, nextFd, stride, modifier, exportInfo.semaphoreHandles, 852 exportInfo.releasedOldLayout, exportInfo.releasedNewLayout); 853 854 // Copy the image into a buffer for comparison 855 wgpu::BufferDescriptor copyDesc; 856 copyDesc.size = data.size(); 857 copyDesc.usage = wgpu::BufferUsage::CopySrc | wgpu::BufferUsage::CopyDst; 858 wgpu::Buffer copyDstBuffer = device.CreateBuffer(©Desc); 859 { 860 wgpu::ImageCopyTexture copySrc = 861 utils::CreateImageCopyTexture(nextWrappedTexture, 0, {0, 0, 0}); 862 wgpu::ImageCopyBuffer copyDst = 863 utils::CreateImageCopyBuffer(copyDstBuffer, 0, bytesPerRow); 864 865 wgpu::Extent3D copySize = {width, height, 1}; 866 867 wgpu::CommandEncoder encoder = device.CreateCommandEncoder(); 868 encoder.CopyTextureToBuffer(©Src, ©Dst, ©Size); 869 wgpu::CommandBuffer commands = encoder.Finish(); 870 queue.Submit(1, &commands); 871 } 872 873 // Check the image is not corrupted on |device| 874 EXPECT_BUFFER_U32_RANGE_EQ(reinterpret_cast<uint32_t*>(data.data()), copyDstBuffer, 0, 875 data.size() / 4); 876 877 IgnoreSignalSemaphore(nextWrappedTexture); 878 } 879 880 DAWN_INSTANTIATE_TEST(VulkanImageWrappingValidationTests, VulkanBackend()); 881 DAWN_INSTANTIATE_TEST(VulkanImageWrappingUsageTests, VulkanBackend()); 882 883 }} // namespace dawn_native::vulkan 884