1 //
2 // Copyright 2019 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6
7 // VulkanExternalImageTest.cpp : Tests of images allocated externally using Vulkan.
8
9 #include "test_utils/ANGLETest.h"
10
11 #include "common/debug.h"
12 #include "test_utils/VulkanExternalHelper.h"
13 #include "test_utils/gl_raii.h"
14
15 namespace angle
16 {
17
18 namespace
19 {
20
21 constexpr int kInvalidFd = -1;
22
23 // List of VkFormat/internalformat combinations Chrome uses.
24 // This is compiled from the maps in
25 // components/viz/common/resources/resource_format_utils.cc.
26 const struct ImageFormatPair
27 {
28 VkFormat vkFormat;
29 GLenum internalFormat;
30 const char *requiredExtension;
31 } kChromeFormats[] = {
32 {VK_FORMAT_R8G8B8A8_UNORM, GL_RGBA8_OES}, // RGBA_8888
33 {VK_FORMAT_B8G8R8A8_UNORM, GL_BGRA8_EXT}, // BGRA_8888
34 {VK_FORMAT_R4G4B4A4_UNORM_PACK16, GL_RGBA4}, // RGBA_4444
35 {VK_FORMAT_R16G16B16A16_SFLOAT, GL_RGBA16F_EXT}, // RGBA_F16
36 {VK_FORMAT_R8_UNORM, GL_R8_EXT}, // RED_8
37 {VK_FORMAT_R5G6B5_UNORM_PACK16, GL_RGB565}, // RGB_565
38 {VK_FORMAT_R16_UNORM, GL_R16_EXT, "GL_EXT_texture_norm16"}, // R16_EXT
39 {VK_FORMAT_A2B10G10R10_UNORM_PACK32, GL_RGB10_A2_EXT}, // RGBA_1010102
40 {VK_FORMAT_R8_UNORM, GL_ALPHA8_EXT}, // ALPHA_8
41 {VK_FORMAT_R8_UNORM, GL_LUMINANCE8_EXT}, // LUMINANCE_8
42 {VK_FORMAT_R8G8_UNORM, GL_RG8_EXT}, // RG_88
43
44 // TODO(spang): Chrome could use GL_RGBA8_OES here if we can solve a couple
45 // of validation comformance issues (see crbug.com/1058521). Or, we can add
46 // a new internalformat that's unambiguously R8G8B8X8 in ANGLE and use that.
47 {VK_FORMAT_R8G8B8A8_UNORM, GL_RGB8_OES}, // RGBX_8888
48 };
49
50 struct OpaqueFdTraits
51 {
52 using Handle = int;
InvalidHandleangle::__anonf4e4ee1c0111::OpaqueFdTraits53 static Handle InvalidHandle() { return kInvalidFd; }
54
MemoryObjectExtensionangle::__anonf4e4ee1c0111::OpaqueFdTraits55 static const char *MemoryObjectExtension() { return "GL_EXT_memory_object_fd"; }
SemaphoreExtensionangle::__anonf4e4ee1c0111::OpaqueFdTraits56 static const char *SemaphoreExtension() { return "GL_EXT_semaphore_fd"; }
57
CanCreateSemaphoreangle::__anonf4e4ee1c0111::OpaqueFdTraits58 static bool CanCreateSemaphore(const VulkanExternalHelper &helper)
59 {
60 return helper.canCreateSemaphoreOpaqueFd();
61 }
62
CreateSemaphoreangle::__anonf4e4ee1c0111::OpaqueFdTraits63 static VkResult CreateSemaphore(VulkanExternalHelper *helper, VkSemaphore *semaphore)
64 {
65 return helper->createSemaphoreOpaqueFd(semaphore);
66 }
67
ExportSemaphoreangle::__anonf4e4ee1c0111::OpaqueFdTraits68 static VkResult ExportSemaphore(VulkanExternalHelper *helper,
69 VkSemaphore semaphore,
70 Handle *handle)
71 {
72 return helper->exportSemaphoreOpaqueFd(semaphore, handle);
73 }
74
ImportSemaphoreangle::__anonf4e4ee1c0111::OpaqueFdTraits75 static void ImportSemaphore(GLuint semaphore, Handle handle)
76 {
77 glImportSemaphoreFdEXT(semaphore, GL_HANDLE_TYPE_OPAQUE_FD_EXT, handle);
78 }
79
CanCreateImageangle::__anonf4e4ee1c0111::OpaqueFdTraits80 static bool CanCreateImage(const VulkanExternalHelper &helper,
81 VkFormat format,
82 VkImageType type,
83 VkImageTiling tiling)
84 {
85 return helper.canCreateImageOpaqueFd(format, type, tiling);
86 }
87
CreateImage2Dangle::__anonf4e4ee1c0111::OpaqueFdTraits88 static VkResult CreateImage2D(VulkanExternalHelper *helper,
89 VkFormat format,
90 VkExtent3D extent,
91 VkImage *imageOut,
92 VkDeviceMemory *deviceMemoryOut,
93 VkDeviceSize *deviceMemorySizeOut)
94 {
95 return helper->createImage2DOpaqueFd(format, extent, imageOut, deviceMemoryOut,
96 deviceMemorySizeOut);
97 }
98
ExportMemoryangle::__anonf4e4ee1c0111::OpaqueFdTraits99 static VkResult ExportMemory(VulkanExternalHelper *helper,
100 VkDeviceMemory deviceMemory,
101 Handle *handle)
102 {
103 return helper->exportMemoryOpaqueFd(deviceMemory, handle);
104 }
105
ImportMemoryangle::__anonf4e4ee1c0111::OpaqueFdTraits106 static void ImportMemory(GLuint memoryObject, GLuint64 size, Handle handle)
107 {
108 glImportMemoryFdEXT(memoryObject, size, GL_HANDLE_TYPE_OPAQUE_FD_EXT, handle);
109 }
110 };
111
112 struct FuchsiaTraits
113 {
114 using Handle = zx_handle_t;
115
InvalidHandleangle::__anonf4e4ee1c0111::FuchsiaTraits116 static Handle InvalidHandle() { return ZX_HANDLE_INVALID; }
117
MemoryObjectExtensionangle::__anonf4e4ee1c0111::FuchsiaTraits118 static const char *MemoryObjectExtension() { return "GL_ANGLE_memory_object_fuchsia"; }
SemaphoreExtensionangle::__anonf4e4ee1c0111::FuchsiaTraits119 static const char *SemaphoreExtension() { return "GL_ANGLE_semaphore_fuchsia"; }
120
CanCreateSemaphoreangle::__anonf4e4ee1c0111::FuchsiaTraits121 static bool CanCreateSemaphore(const VulkanExternalHelper &helper)
122 {
123 return helper.canCreateSemaphoreZirconEvent();
124 }
125
CreateSemaphoreangle::__anonf4e4ee1c0111::FuchsiaTraits126 static VkResult CreateSemaphore(VulkanExternalHelper *helper, VkSemaphore *semaphore)
127 {
128 return helper->createSemaphoreZirconEvent(semaphore);
129 }
130
ExportSemaphoreangle::__anonf4e4ee1c0111::FuchsiaTraits131 static VkResult ExportSemaphore(VulkanExternalHelper *helper,
132 VkSemaphore semaphore,
133 Handle *handle)
134 {
135 return helper->exportSemaphoreZirconEvent(semaphore, handle);
136 }
137
ImportSemaphoreangle::__anonf4e4ee1c0111::FuchsiaTraits138 static void ImportSemaphore(GLuint semaphore, Handle handle)
139 {
140 glImportSemaphoreZirconHandleANGLE(semaphore, GL_HANDLE_TYPE_ZIRCON_EVENT_ANGLE, handle);
141 }
142
CanCreateImageangle::__anonf4e4ee1c0111::FuchsiaTraits143 static bool CanCreateImage(const VulkanExternalHelper &helper,
144 VkFormat format,
145 VkImageType type,
146 VkImageTiling tiling)
147 {
148 return helper.canCreateImageZirconVmo(format, type, tiling);
149 }
150
CreateImage2Dangle::__anonf4e4ee1c0111::FuchsiaTraits151 static VkResult CreateImage2D(VulkanExternalHelper *helper,
152 VkFormat format,
153 VkExtent3D extent,
154 VkImage *imageOut,
155 VkDeviceMemory *deviceMemoryOut,
156 VkDeviceSize *deviceMemorySizeOut)
157 {
158 return helper->createImage2DZirconVmo(format, extent, imageOut, deviceMemoryOut,
159 deviceMemorySizeOut);
160 }
161
ExportMemoryangle::__anonf4e4ee1c0111::FuchsiaTraits162 static VkResult ExportMemory(VulkanExternalHelper *helper,
163 VkDeviceMemory deviceMemory,
164 Handle *handle)
165 {
166 return helper->exportMemoryZirconVmo(deviceMemory, handle);
167 }
168
ImportMemoryangle::__anonf4e4ee1c0111::FuchsiaTraits169 static void ImportMemory(GLuint memoryObject, GLuint64 size, Handle handle)
170 {
171 glImportMemoryZirconHandleANGLE(memoryObject, size, GL_HANDLE_TYPE_ZIRCON_VMO_ANGLE,
172 handle);
173 }
174 };
175
176 } // namespace
177
178 class VulkanExternalImageTest : public ANGLETest
179 {
180 protected:
VulkanExternalImageTest()181 VulkanExternalImageTest()
182 {
183 setWindowWidth(1);
184 setWindowHeight(1);
185 setConfigRedBits(8);
186 setConfigGreenBits(8);
187 setConfigBlueBits(8);
188 setConfigAlphaBits(8);
189 }
190 };
191
192 template <typename Traits>
RunShouldImportMemoryTest(bool isSwiftshader,bool enableDebugLayers)193 void RunShouldImportMemoryTest(bool isSwiftshader, bool enableDebugLayers)
194 {
195 ASSERT(EnsureGLExtensionEnabled(Traits::MemoryObjectExtension()));
196
197 VulkanExternalHelper helper;
198 helper.initialize(isSwiftshader, enableDebugLayers);
199
200 VkFormat format = VK_FORMAT_R8G8B8A8_UNORM;
201 ANGLE_SKIP_TEST_IF(
202 !Traits::CanCreateImage(helper, format, VK_IMAGE_TYPE_2D, VK_IMAGE_TILING_OPTIMAL));
203
204 VkImage image = VK_NULL_HANDLE;
205 VkDeviceMemory deviceMemory = VK_NULL_HANDLE;
206 VkDeviceSize deviceMemorySize = 0;
207
208 VkExtent3D extent = {1, 1, 1};
209 VkResult result =
210 Traits::CreateImage2D(&helper, format, extent, &image, &deviceMemory, &deviceMemorySize);
211 EXPECT_EQ(result, VK_SUCCESS);
212
213 typename Traits::Handle memoryHandle = Traits::InvalidHandle();
214 result = Traits::ExportMemory(&helper, deviceMemory, &memoryHandle);
215 EXPECT_EQ(result, VK_SUCCESS);
216 EXPECT_NE(memoryHandle, Traits::InvalidHandle());
217
218 {
219 GLMemoryObject memoryObject;
220 GLint dedicatedMemory = GL_TRUE;
221 glMemoryObjectParameterivEXT(memoryObject, GL_DEDICATED_MEMORY_OBJECT_EXT,
222 &dedicatedMemory);
223 Traits::ImportMemory(memoryObject, deviceMemorySize, memoryHandle);
224
225 // Test that after calling glImportMemoryFdEXT, the parameters of the memory object cannot
226 // be changed
227 dedicatedMemory = GL_FALSE;
228 glMemoryObjectParameterivEXT(memoryObject, GL_DEDICATED_MEMORY_OBJECT_EXT,
229 &dedicatedMemory);
230 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
231 }
232
233 EXPECT_GL_NO_ERROR();
234
235 vkDestroyImage(helper.getDevice(), image, nullptr);
236 vkFreeMemory(helper.getDevice(), deviceMemory, nullptr);
237 }
238
239 // glImportMemoryFdEXT must be able to import a valid opaque fd.
TEST_P(VulkanExternalImageTest,ShouldImportMemoryOpaqueFd)240 TEST_P(VulkanExternalImageTest, ShouldImportMemoryOpaqueFd)
241 {
242 ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_memory_object_fd"));
243 RunShouldImportMemoryTest<OpaqueFdTraits>(isSwiftshader(), enableDebugLayers());
244 }
245
246 // glImportMemoryZirconHandleANGLE must be able to import a valid vmo.
TEST_P(VulkanExternalImageTest,ShouldImportMemoryZirconVmo)247 TEST_P(VulkanExternalImageTest, ShouldImportMemoryZirconVmo)
248 {
249 ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_ANGLE_memory_object_fuchsia"));
250 RunShouldImportMemoryTest<FuchsiaTraits>(isSwiftshader(), enableDebugLayers());
251 }
252
253 template <typename Traits>
RunShouldImportSemaphoreTest(bool isSwiftshader,bool enableDebugLayers)254 void RunShouldImportSemaphoreTest(bool isSwiftshader, bool enableDebugLayers)
255 {
256 ASSERT(EnsureGLExtensionEnabled(Traits::SemaphoreExtension()));
257
258 VulkanExternalHelper helper;
259 helper.initialize(isSwiftshader, enableDebugLayers);
260
261 ANGLE_SKIP_TEST_IF(!Traits::CanCreateSemaphore(helper));
262
263 VkSemaphore vkSemaphore = VK_NULL_HANDLE;
264 VkResult result = helper.createSemaphoreOpaqueFd(&vkSemaphore);
265 EXPECT_EQ(result, VK_SUCCESS);
266
267 typename Traits::Handle semaphoreHandle = Traits::InvalidHandle();
268 result = Traits::ExportSemaphore(&helper, vkSemaphore, &semaphoreHandle);
269 EXPECT_EQ(result, VK_SUCCESS);
270 EXPECT_NE(semaphoreHandle, Traits::InvalidHandle());
271
272 {
273 GLSemaphore glSemaphore;
274 Traits::ImportSemaphore(glSemaphore, semaphoreHandle);
275 }
276
277 EXPECT_GL_NO_ERROR();
278
279 vkDestroySemaphore(helper.getDevice(), vkSemaphore, nullptr);
280 }
281
282 // glImportSemaphoreFdEXT must be able to import a valid opaque fd.
TEST_P(VulkanExternalImageTest,ShouldImportSemaphoreOpaqueFd)283 TEST_P(VulkanExternalImageTest, ShouldImportSemaphoreOpaqueFd)
284 {
285 ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_semaphore_fd"));
286 RunShouldImportSemaphoreTest<OpaqueFdTraits>(isSwiftshader(), enableDebugLayers());
287 }
288
289 // glImportSemaphoreZirconHandleANGLE must be able to import a valid handle.
TEST_P(VulkanExternalImageTest,ShouldImportSemaphoreZirconEvent)290 TEST_P(VulkanExternalImageTest, ShouldImportSemaphoreZirconEvent)
291 {
292 ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_ANGLE_semaphore_fuchsia"));
293 RunShouldImportSemaphoreTest<FuchsiaTraits>(isSwiftshader(), enableDebugLayers());
294 }
295
296 template <typename Traits>
RunShouldClearTest(bool isSwiftshader,bool enableDebugLayers)297 void RunShouldClearTest(bool isSwiftshader, bool enableDebugLayers)
298 {
299 ASSERT(EnsureGLExtensionEnabled(Traits::MemoryObjectExtension()));
300
301 VulkanExternalHelper helper;
302 helper.initialize(isSwiftshader, enableDebugLayers);
303
304 VkFormat format = VK_FORMAT_R8G8B8A8_UNORM;
305 ANGLE_SKIP_TEST_IF(
306 !Traits::CanCreateImage(helper, format, VK_IMAGE_TYPE_2D, VK_IMAGE_TILING_OPTIMAL));
307
308 VkImage image = VK_NULL_HANDLE;
309 VkDeviceMemory deviceMemory = VK_NULL_HANDLE;
310 VkDeviceSize deviceMemorySize = 0;
311
312 VkExtent3D extent = {1, 1, 1};
313 VkResult result =
314 Traits::CreateImage2D(&helper, format, extent, &image, &deviceMemory, &deviceMemorySize);
315 EXPECT_EQ(result, VK_SUCCESS);
316
317 typename Traits::Handle memoryHandle = Traits::InvalidHandle();
318 result = Traits::ExportMemory(&helper, deviceMemory, &memoryHandle);
319 EXPECT_EQ(result, VK_SUCCESS);
320 EXPECT_NE(memoryHandle, Traits::InvalidHandle());
321
322 {
323 GLMemoryObject memoryObject;
324 GLint dedicatedMemory = GL_TRUE;
325 glMemoryObjectParameterivEXT(memoryObject, GL_DEDICATED_MEMORY_OBJECT_EXT,
326 &dedicatedMemory);
327 Traits::ImportMemory(memoryObject, deviceMemorySize, memoryHandle);
328
329 GLTexture texture;
330 glBindTexture(GL_TEXTURE_2D, texture);
331 glTexStorageMem2DEXT(GL_TEXTURE_2D, 1, GL_RGBA8, 1, 1, memoryObject, 0);
332
333 GLFramebuffer framebuffer;
334 glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
335 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
336
337 glClearColor(0.5f, 0.5f, 0.5f, 0.5f);
338 glClear(GL_COLOR_BUFFER_BIT);
339
340 EXPECT_PIXEL_NEAR(0, 0, 128, 128, 128, 128, 1.0);
341 }
342
343 EXPECT_GL_NO_ERROR();
344
345 vkDestroyImage(helper.getDevice(), image, nullptr);
346 vkFreeMemory(helper.getDevice(), deviceMemory, nullptr);
347 }
348
349 // Test creating and clearing a simple RGBA8 texture in a opaque fd.
TEST_P(VulkanExternalImageTest,ShouldClearOpaqueFdRGBA8)350 TEST_P(VulkanExternalImageTest, ShouldClearOpaqueFdRGBA8)
351 {
352 ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_memory_object_fd"));
353 // http://anglebug.com/4630
354 ANGLE_SKIP_TEST_IF(IsAndroid() && IsOpenGL() && (IsPixel2() || IsPixel2XL()));
355 RunShouldClearTest<OpaqueFdTraits>(isSwiftshader(), enableDebugLayers());
356 }
357
358 // Test creating and clearing a simple RGBA8 texture in a zircon vmo.
TEST_P(VulkanExternalImageTest,ShouldClearZirconVmoRGBA8)359 TEST_P(VulkanExternalImageTest, ShouldClearZirconVmoRGBA8)
360 {
361 ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_ANGLE_memory_object_fuchsia"));
362 RunShouldClearTest<FuchsiaTraits>(isSwiftshader(), enableDebugLayers());
363 }
364
365 template <typename Traits>
RunTextureFormatCompatChromiumTest(bool isSwiftshader,bool enableDebugLayers)366 void RunTextureFormatCompatChromiumTest(bool isSwiftshader, bool enableDebugLayers)
367 {
368 ASSERT(EnsureGLExtensionEnabled(Traits::MemoryObjectExtension()));
369
370 VulkanExternalHelper helper;
371 helper.initialize(isSwiftshader, enableDebugLayers);
372 for (const ImageFormatPair &format : kChromeFormats)
373 {
374 if (!Traits::CanCreateImage(helper, format.vkFormat, VK_IMAGE_TYPE_2D,
375 VK_IMAGE_TILING_OPTIMAL))
376 {
377 continue;
378 }
379
380 if (format.requiredExtension && !IsGLExtensionEnabled(format.requiredExtension))
381 {
382 continue;
383 }
384
385 VkImage image = VK_NULL_HANDLE;
386 VkDeviceMemory deviceMemory = VK_NULL_HANDLE;
387 VkDeviceSize deviceMemorySize = 0;
388
389 VkExtent3D extent = {113, 211, 1};
390 VkResult result = Traits::CreateImage2D(&helper, format.vkFormat, extent, &image,
391 &deviceMemory, &deviceMemorySize);
392 EXPECT_EQ(result, VK_SUCCESS);
393
394 typename Traits::Handle memoryHandle = Traits::InvalidHandle();
395 result = Traits::ExportMemory(&helper, deviceMemory, &memoryHandle);
396 EXPECT_EQ(result, VK_SUCCESS);
397 EXPECT_NE(memoryHandle, Traits::InvalidHandle());
398
399 {
400 GLMemoryObject memoryObject;
401 GLint dedicatedMemory = GL_TRUE;
402 glMemoryObjectParameterivEXT(memoryObject, GL_DEDICATED_MEMORY_OBJECT_EXT,
403 &dedicatedMemory);
404 Traits::ImportMemory(memoryObject, deviceMemorySize, memoryHandle);
405
406 GLTexture texture;
407 glBindTexture(GL_TEXTURE_2D, texture);
408 glTexStorageMem2DEXT(GL_TEXTURE_2D, 1, format.internalFormat, extent.width,
409 extent.height, memoryObject, 0);
410 }
411
412 EXPECT_GL_NO_ERROR();
413
414 vkDestroyImage(helper.getDevice(), image, nullptr);
415 vkFreeMemory(helper.getDevice(), deviceMemory, nullptr);
416 }
417 }
418
419 // Test all format combinations used by Chrome import successfully (opaque fd).
TEST_P(VulkanExternalImageTest,TextureFormatCompatChromiumFd)420 TEST_P(VulkanExternalImageTest, TextureFormatCompatChromiumFd)
421 {
422 ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_memory_object_fd"));
423 RunTextureFormatCompatChromiumTest<OpaqueFdTraits>(isSwiftshader(), enableDebugLayers());
424 }
425
426 // Test all format combinations used by Chrome import successfully (fuchsia).
TEST_P(VulkanExternalImageTest,TextureFormatCompatChromiumZirconVmo)427 TEST_P(VulkanExternalImageTest, TextureFormatCompatChromiumZirconVmo)
428 {
429 ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_ANGLE_memory_object_fuchsia"));
430 RunTextureFormatCompatChromiumTest<FuchsiaTraits>(isSwiftshader(), enableDebugLayers());
431 }
432
433 template <typename Traits>
RunShouldClearWithSemaphoresTest(bool isSwiftshader,bool enableDebugLayers)434 void RunShouldClearWithSemaphoresTest(bool isSwiftshader, bool enableDebugLayers)
435 {
436 ASSERT(EnsureGLExtensionEnabled(Traits::MemoryObjectExtension()));
437 ASSERT(EnsureGLExtensionEnabled(Traits::SemaphoreExtension()));
438
439 VulkanExternalHelper helper;
440 helper.initialize(isSwiftshader, enableDebugLayers);
441
442 VkFormat format = VK_FORMAT_R8G8B8A8_UNORM;
443 ANGLE_SKIP_TEST_IF(
444 !Traits::CanCreateImage(helper, format, VK_IMAGE_TYPE_2D, VK_IMAGE_TILING_OPTIMAL));
445 ANGLE_SKIP_TEST_IF(!Traits::CanCreateSemaphore(helper));
446
447 VkSemaphore vkAcquireSemaphore = VK_NULL_HANDLE;
448 VkResult result = Traits::CreateSemaphore(&helper, &vkAcquireSemaphore);
449 EXPECT_EQ(result, VK_SUCCESS);
450 EXPECT_TRUE(vkAcquireSemaphore != VK_NULL_HANDLE);
451
452 VkSemaphore vkReleaseSemaphore = VK_NULL_HANDLE;
453 result = Traits::CreateSemaphore(&helper, &vkReleaseSemaphore);
454 EXPECT_EQ(result, VK_SUCCESS);
455 EXPECT_TRUE(vkReleaseSemaphore != VK_NULL_HANDLE);
456
457 typename Traits::Handle acquireSemaphoreHandle = Traits::InvalidHandle();
458 result = Traits::ExportSemaphore(&helper, vkAcquireSemaphore, &acquireSemaphoreHandle);
459 EXPECT_EQ(result, VK_SUCCESS);
460 EXPECT_NE(acquireSemaphoreHandle, Traits::InvalidHandle());
461
462 typename Traits::Handle releaseSemaphoreHandle = Traits::InvalidHandle();
463 result = Traits::ExportSemaphore(&helper, vkReleaseSemaphore, &releaseSemaphoreHandle);
464 EXPECT_EQ(result, VK_SUCCESS);
465 EXPECT_NE(releaseSemaphoreHandle, Traits::InvalidHandle());
466
467 VkImage image = VK_NULL_HANDLE;
468 VkDeviceMemory deviceMemory = VK_NULL_HANDLE;
469 VkDeviceSize deviceMemorySize = 0;
470
471 VkExtent3D extent = {1, 1, 1};
472 result =
473 Traits::CreateImage2D(&helper, format, extent, &image, &deviceMemory, &deviceMemorySize);
474 EXPECT_EQ(result, VK_SUCCESS);
475
476 typename Traits::Handle memoryHandle = Traits::InvalidHandle();
477 result = Traits::ExportMemory(&helper, deviceMemory, &memoryHandle);
478 EXPECT_EQ(result, VK_SUCCESS);
479 EXPECT_NE(memoryHandle, Traits::InvalidHandle());
480
481 {
482 GLMemoryObject memoryObject;
483 GLint dedicatedMemory = GL_TRUE;
484 glMemoryObjectParameterivEXT(memoryObject, GL_DEDICATED_MEMORY_OBJECT_EXT,
485 &dedicatedMemory);
486 Traits::ImportMemory(memoryObject, deviceMemorySize, memoryHandle);
487
488 GLTexture texture;
489 glBindTexture(GL_TEXTURE_2D, texture);
490 glTexStorageMem2DEXT(GL_TEXTURE_2D, 1, GL_RGBA8, 1, 1, memoryObject, 0);
491
492 GLSemaphore glAcquireSemaphore;
493 Traits::ImportSemaphore(glAcquireSemaphore, acquireSemaphoreHandle);
494
495 helper.releaseImageAndSignalSemaphore(image, VK_IMAGE_LAYOUT_UNDEFINED,
496 VK_IMAGE_LAYOUT_GENERAL, vkAcquireSemaphore);
497
498 const GLuint barrierTextures[] = {
499 texture,
500 };
501 constexpr uint32_t textureBarriersCount = std::extent<decltype(barrierTextures)>();
502 const GLenum textureSrcLayouts[] = {
503 GL_LAYOUT_GENERAL_EXT,
504 };
505 constexpr uint32_t textureSrcLayoutsCount = std::extent<decltype(textureSrcLayouts)>();
506 static_assert(textureBarriersCount == textureSrcLayoutsCount,
507 "barrierTextures and textureSrcLayouts must be the same length");
508 glWaitSemaphoreEXT(glAcquireSemaphore, 0, nullptr, textureBarriersCount, barrierTextures,
509 textureSrcLayouts);
510
511 GLFramebuffer framebuffer;
512 glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
513 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
514
515 glClearColor(0.5f, 0.5f, 0.5f, 0.5f);
516 glClear(GL_COLOR_BUFFER_BIT);
517
518 GLSemaphore glReleaseSemaphore;
519 Traits::ImportSemaphore(glReleaseSemaphore, releaseSemaphoreHandle);
520
521 const GLenum textureDstLayouts[] = {
522 GL_LAYOUT_TRANSFER_SRC_EXT,
523 };
524 constexpr uint32_t textureDstLayoutsCount = std::extent<decltype(textureSrcLayouts)>();
525 static_assert(textureBarriersCount == textureDstLayoutsCount,
526 "barrierTextures and textureDstLayouts must be the same length");
527 glSignalSemaphoreEXT(glReleaseSemaphore, 0, nullptr, textureBarriersCount, barrierTextures,
528 textureDstLayouts);
529
530 helper.waitSemaphoreAndAcquireImage(image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
531 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
532 vkReleaseSemaphore);
533 uint8_t pixels[4];
534 VkOffset3D offset = {};
535 VkExtent3D extent = {1, 1, 1};
536 helper.readPixels(image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, format, offset, extent,
537 pixels, sizeof(pixels));
538
539 EXPECT_NEAR(0x80, pixels[0], 1);
540 EXPECT_NEAR(0x80, pixels[1], 1);
541 EXPECT_NEAR(0x80, pixels[2], 1);
542 EXPECT_NEAR(0x80, pixels[3], 1);
543 }
544
545 EXPECT_GL_NO_ERROR();
546
547 vkDeviceWaitIdle(helper.getDevice());
548 vkDestroyImage(helper.getDevice(), image, nullptr);
549 vkDestroySemaphore(helper.getDevice(), vkAcquireSemaphore, nullptr);
550 vkDestroySemaphore(helper.getDevice(), vkReleaseSemaphore, nullptr);
551 vkFreeMemory(helper.getDevice(), deviceMemory, nullptr);
552 }
553
554 // Test creating and clearing RGBA8 texture in opaque fd with acquire/release.
TEST_P(VulkanExternalImageTest,ShouldClearOpaqueFdWithSemaphores)555 TEST_P(VulkanExternalImageTest, ShouldClearOpaqueFdWithSemaphores)
556 {
557 ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_memory_object_fd"));
558 ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_semaphore_fd"));
559 RunShouldClearWithSemaphoresTest<OpaqueFdTraits>(isSwiftshader(), enableDebugLayers());
560 }
561
562 // Test creating and clearing RGBA8 texture in zircon vmo with acquire/release.
TEST_P(VulkanExternalImageTest,ShouldClearZirconVmoWithSemaphores)563 TEST_P(VulkanExternalImageTest, ShouldClearZirconVmoWithSemaphores)
564 {
565 ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_ANGLE_memory_object_fuchsia"));
566 ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_ANGLE_semaphore_fuchsia"));
567 RunShouldClearWithSemaphoresTest<FuchsiaTraits>(isSwiftshader(), enableDebugLayers());
568 }
569
570 // Support for Zircon handle types is mandatory on Fuchsia.
TEST_P(VulkanExternalImageTest,ShouldSupportExternalHandlesFuchsia)571 TEST_P(VulkanExternalImageTest, ShouldSupportExternalHandlesFuchsia)
572 {
573 ANGLE_SKIP_TEST_IF(!IsFuchsia());
574 EXPECT_TRUE(EnsureGLExtensionEnabled("GL_ANGLE_memory_object_fuchsia"));
575 EXPECT_TRUE(EnsureGLExtensionEnabled("GL_ANGLE_semaphore_fuchsia"));
576 VulkanExternalHelper helper;
577 helper.initialize(isSwiftshader(), enableDebugLayers());
578 EXPECT_TRUE(helper.canCreateSemaphoreZirconEvent());
579 EXPECT_TRUE(helper.canCreateImageZirconVmo(VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_TYPE_2D,
580 VK_IMAGE_TILING_OPTIMAL));
581 }
582
583 // Use this to select which configurations (e.g. which renderer, which GLES major version) these
584 // tests should be run against.
585 ANGLE_INSTANTIATE_TEST_ES2_AND_ES3(VulkanExternalImageTest);
586
587 } // namespace angle
588