• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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