| // |
| // Copyright 2019 The ANGLE Project Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| // |
| |
| // VulkanExternalImageTest.cpp : Tests of images allocated externally using Vulkan. |
| |
| #include "test_utils/ANGLETest.h" |
| |
| #include "common/debug.h" |
| #include "test_utils/VulkanExternalHelper.h" |
| #include "test_utils/gl_raii.h" |
| |
| namespace angle |
| { |
| |
| namespace |
| { |
| |
| constexpr int kInvalidFd = -1; |
| |
| constexpr VkImageUsageFlags kDefaultImageUsageFlags = |
| VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | |
| VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | |
| VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT; |
| constexpr VkImageCreateFlags kDefaultImageCreateFlags = 0; |
| |
| constexpr VkImageUsageFlags kNoStorageImageUsageFlags = |
| kDefaultImageUsageFlags & ~VK_IMAGE_USAGE_STORAGE_BIT; |
| constexpr VkImageCreateFlags kMutableImageCreateFlags = |
| kDefaultImageCreateFlags | VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT; |
| |
| // List of VkFormat/internalformat combinations Chrome uses. |
| // This is compiled from the maps in |
| // components/viz/common/resources/resource_format_utils.cc. |
| const struct ImageFormatPair |
| { |
| VkFormat vkFormat; |
| GLenum internalFormat; |
| const char *requiredExtension; |
| } kChromeFormats[] = { |
| {VK_FORMAT_R8G8B8A8_UNORM, GL_RGBA8_OES}, // RGBA_8888 |
| {VK_FORMAT_B8G8R8A8_UNORM, GL_BGRA8_EXT}, // BGRA_8888 |
| {VK_FORMAT_R4G4B4A4_UNORM_PACK16, GL_RGBA4}, // RGBA_4444 |
| {VK_FORMAT_R16G16B16A16_SFLOAT, GL_RGBA16F_EXT}, // RGBA_F16 |
| {VK_FORMAT_R8_UNORM, GL_R8_EXT}, // RED_8 |
| {VK_FORMAT_R5G6B5_UNORM_PACK16, GL_RGB565}, // RGB_565 |
| {VK_FORMAT_R16_UNORM, GL_R16_EXT, "GL_EXT_texture_norm16"}, // R16_EXT |
| {VK_FORMAT_A2B10G10R10_UNORM_PACK32, GL_RGB10_A2_EXT}, // RGBA_1010102 |
| {VK_FORMAT_R8_UNORM, GL_ALPHA8_EXT}, // ALPHA_8 |
| {VK_FORMAT_R8_UNORM, GL_LUMINANCE8_EXT}, // LUMINANCE_8 |
| {VK_FORMAT_R8G8_UNORM, GL_RG8_EXT}, // RG_88 |
| |
| // TODO(spang): Chrome could use GL_RGBA8_OES here if we can solve a couple |
| // of validation comformance issues (see crbug.com/1058521). Or, we can add |
| // a new internalformat that's unambiguously R8G8B8X8 in ANGLE and use that. |
| {VK_FORMAT_R8G8B8A8_UNORM, GL_RGB8_OES}, // RGBX_8888 |
| }; |
| |
| struct OpaqueFdTraits |
| { |
| using Handle = int; |
| static Handle InvalidHandle() { return kInvalidFd; } |
| |
| static const char *MemoryObjectExtension() { return "GL_EXT_memory_object_fd"; } |
| static const char *SemaphoreExtension() { return "GL_EXT_semaphore_fd"; } |
| |
| static bool CanCreateSemaphore(const VulkanExternalHelper &helper) |
| { |
| return helper.canCreateSemaphoreOpaqueFd(); |
| } |
| |
| static VkResult CreateSemaphore(VulkanExternalHelper *helper, VkSemaphore *semaphore) |
| { |
| return helper->createSemaphoreOpaqueFd(semaphore); |
| } |
| |
| static VkResult ExportSemaphore(VulkanExternalHelper *helper, |
| VkSemaphore semaphore, |
| Handle *handle) |
| { |
| return helper->exportSemaphoreOpaqueFd(semaphore, handle); |
| } |
| |
| static void ImportSemaphore(GLuint semaphore, Handle handle) |
| { |
| glImportSemaphoreFdEXT(semaphore, GL_HANDLE_TYPE_OPAQUE_FD_EXT, handle); |
| } |
| |
| static bool CanCreateImage(const VulkanExternalHelper &helper, |
| VkFormat format, |
| VkImageType type, |
| VkImageTiling tiling, |
| VkImageCreateFlags createFlags, |
| VkImageUsageFlags usageFlags) |
| { |
| return helper.canCreateImageOpaqueFd(format, type, tiling, createFlags, usageFlags); |
| } |
| |
| static VkResult CreateImage2D(VulkanExternalHelper *helper, |
| VkFormat format, |
| VkImageCreateFlags createFlags, |
| VkImageUsageFlags usageFlags, |
| VkExtent3D extent, |
| VkImage *imageOut, |
| VkDeviceMemory *deviceMemoryOut, |
| VkDeviceSize *deviceMemorySizeOut) |
| { |
| return helper->createImage2DOpaqueFd(format, createFlags, usageFlags, extent, imageOut, |
| deviceMemoryOut, deviceMemorySizeOut); |
| } |
| |
| static VkResult ExportMemory(VulkanExternalHelper *helper, |
| VkDeviceMemory deviceMemory, |
| Handle *handle) |
| { |
| return helper->exportMemoryOpaqueFd(deviceMemory, handle); |
| } |
| |
| static void ImportMemory(GLuint memoryObject, GLuint64 size, Handle handle) |
| { |
| glImportMemoryFdEXT(memoryObject, size, GL_HANDLE_TYPE_OPAQUE_FD_EXT, handle); |
| } |
| }; |
| |
| struct FuchsiaTraits |
| { |
| using Handle = zx_handle_t; |
| |
| static Handle InvalidHandle() { return ZX_HANDLE_INVALID; } |
| |
| static const char *MemoryObjectExtension() { return "GL_ANGLE_memory_object_fuchsia"; } |
| static const char *SemaphoreExtension() { return "GL_ANGLE_semaphore_fuchsia"; } |
| |
| static bool CanCreateSemaphore(const VulkanExternalHelper &helper) |
| { |
| return helper.canCreateSemaphoreZirconEvent(); |
| } |
| |
| static VkResult CreateSemaphore(VulkanExternalHelper *helper, VkSemaphore *semaphore) |
| { |
| return helper->createSemaphoreZirconEvent(semaphore); |
| } |
| |
| static VkResult ExportSemaphore(VulkanExternalHelper *helper, |
| VkSemaphore semaphore, |
| Handle *handle) |
| { |
| return helper->exportSemaphoreZirconEvent(semaphore, handle); |
| } |
| |
| static void ImportSemaphore(GLuint semaphore, Handle handle) |
| { |
| glImportSemaphoreZirconHandleANGLE(semaphore, GL_HANDLE_TYPE_ZIRCON_EVENT_ANGLE, handle); |
| } |
| |
| static bool CanCreateImage(const VulkanExternalHelper &helper, |
| VkFormat format, |
| VkImageType type, |
| VkImageTiling tiling, |
| VkImageCreateFlags createFlags, |
| VkImageUsageFlags usageFlags) |
| { |
| return helper.canCreateImageZirconVmo(format, type, tiling, createFlags, usageFlags); |
| } |
| |
| static VkResult CreateImage2D(VulkanExternalHelper *helper, |
| VkFormat format, |
| VkImageCreateFlags createFlags, |
| VkImageUsageFlags usageFlags, |
| VkExtent3D extent, |
| VkImage *imageOut, |
| VkDeviceMemory *deviceMemoryOut, |
| VkDeviceSize *deviceMemorySizeOut) |
| { |
| return helper->createImage2DZirconVmo(format, createFlags, usageFlags, extent, imageOut, |
| deviceMemoryOut, deviceMemorySizeOut); |
| } |
| |
| static VkResult ExportMemory(VulkanExternalHelper *helper, |
| VkDeviceMemory deviceMemory, |
| Handle *handle) |
| { |
| return helper->exportMemoryZirconVmo(deviceMemory, handle); |
| } |
| |
| static void ImportMemory(GLuint memoryObject, GLuint64 size, Handle handle) |
| { |
| glImportMemoryZirconHandleANGLE(memoryObject, size, GL_HANDLE_TYPE_ZIRCON_VMO_ANGLE, |
| handle); |
| } |
| }; |
| |
| } // namespace |
| |
| class VulkanExternalImageTest : public ANGLETest |
| { |
| protected: |
| VulkanExternalImageTest() |
| { |
| setWindowWidth(1); |
| setWindowHeight(1); |
| setConfigRedBits(8); |
| setConfigGreenBits(8); |
| setConfigBlueBits(8); |
| setConfigAlphaBits(8); |
| } |
| |
| template <typename Traits> |
| void runShouldDrawTest(bool isSwiftshader, bool enableDebugLayers); |
| |
| template <typename Traits> |
| void runWaitSemaphoresRetainsContentTest(bool isSwiftshader, bool enableDebugLayers); |
| }; |
| |
| template <typename Traits> |
| void RunShouldImportMemoryTest(VkImageCreateFlags createFlags, |
| VkImageUsageFlags usageFlags, |
| bool isSwiftshader, |
| bool enableDebugLayers) |
| { |
| ASSERT(EnsureGLExtensionEnabled(Traits::MemoryObjectExtension())); |
| |
| VulkanExternalHelper helper; |
| helper.initialize(isSwiftshader, enableDebugLayers); |
| |
| VkFormat format = VK_FORMAT_R8G8B8A8_UNORM; |
| ANGLE_SKIP_TEST_IF(!Traits::CanCreateImage(helper, format, VK_IMAGE_TYPE_2D, |
| VK_IMAGE_TILING_OPTIMAL, createFlags, usageFlags)); |
| |
| VkImage image = VK_NULL_HANDLE; |
| VkDeviceMemory deviceMemory = VK_NULL_HANDLE; |
| VkDeviceSize deviceMemorySize = 0; |
| |
| VkExtent3D extent = {1, 1, 1}; |
| VkResult result = Traits::CreateImage2D(&helper, format, createFlags, usageFlags, extent, |
| &image, &deviceMemory, &deviceMemorySize); |
| EXPECT_EQ(result, VK_SUCCESS); |
| |
| typename Traits::Handle memoryHandle = Traits::InvalidHandle(); |
| result = Traits::ExportMemory(&helper, deviceMemory, &memoryHandle); |
| EXPECT_EQ(result, VK_SUCCESS); |
| EXPECT_NE(memoryHandle, Traits::InvalidHandle()); |
| |
| { |
| GLMemoryObject memoryObject; |
| GLint dedicatedMemory = GL_TRUE; |
| glMemoryObjectParameterivEXT(memoryObject, GL_DEDICATED_MEMORY_OBJECT_EXT, |
| &dedicatedMemory); |
| Traits::ImportMemory(memoryObject, deviceMemorySize, memoryHandle); |
| |
| // Test that after calling glImportMemoryFdEXT, the parameters of the memory object cannot |
| // be changed |
| dedicatedMemory = GL_FALSE; |
| glMemoryObjectParameterivEXT(memoryObject, GL_DEDICATED_MEMORY_OBJECT_EXT, |
| &dedicatedMemory); |
| EXPECT_GL_ERROR(GL_INVALID_OPERATION); |
| } |
| |
| EXPECT_GL_NO_ERROR(); |
| |
| vkDestroyImage(helper.getDevice(), image, nullptr); |
| vkFreeMemory(helper.getDevice(), deviceMemory, nullptr); |
| } |
| |
| // glImportMemoryFdEXT must be able to import a valid opaque fd. |
| TEST_P(VulkanExternalImageTest, ShouldImportMemoryOpaqueFd) |
| { |
| ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_memory_object_fd")); |
| RunShouldImportMemoryTest<OpaqueFdTraits>(kDefaultImageCreateFlags, kDefaultImageUsageFlags, |
| isSwiftshader(), enableDebugLayers()); |
| } |
| |
| // glImportMemoryZirconHandleANGLE must be able to import a valid vmo. |
| TEST_P(VulkanExternalImageTest, ShouldImportMemoryZirconVmo) |
| { |
| ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_ANGLE_memory_object_fuchsia")); |
| RunShouldImportMemoryTest<FuchsiaTraits>(kDefaultImageCreateFlags, kDefaultImageUsageFlags, |
| isSwiftshader(), enableDebugLayers()); |
| } |
| |
| template <typename Traits> |
| void RunShouldImportSemaphoreTest(bool isSwiftshader, bool enableDebugLayers) |
| { |
| ASSERT(EnsureGLExtensionEnabled(Traits::SemaphoreExtension())); |
| |
| VulkanExternalHelper helper; |
| helper.initialize(isSwiftshader, enableDebugLayers); |
| |
| ANGLE_SKIP_TEST_IF(!Traits::CanCreateSemaphore(helper)); |
| |
| VkSemaphore vkSemaphore = VK_NULL_HANDLE; |
| VkResult result = helper.createSemaphoreOpaqueFd(&vkSemaphore); |
| EXPECT_EQ(result, VK_SUCCESS); |
| |
| typename Traits::Handle semaphoreHandle = Traits::InvalidHandle(); |
| result = Traits::ExportSemaphore(&helper, vkSemaphore, &semaphoreHandle); |
| EXPECT_EQ(result, VK_SUCCESS); |
| EXPECT_NE(semaphoreHandle, Traits::InvalidHandle()); |
| |
| { |
| GLSemaphore glSemaphore; |
| Traits::ImportSemaphore(glSemaphore, semaphoreHandle); |
| } |
| |
| EXPECT_GL_NO_ERROR(); |
| |
| vkDestroySemaphore(helper.getDevice(), vkSemaphore, nullptr); |
| } |
| |
| // glImportSemaphoreFdEXT must be able to import a valid opaque fd. |
| TEST_P(VulkanExternalImageTest, ShouldImportSemaphoreOpaqueFd) |
| { |
| ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_semaphore_fd")); |
| RunShouldImportSemaphoreTest<OpaqueFdTraits>(isSwiftshader(), enableDebugLayers()); |
| } |
| |
| // glImportSemaphoreZirconHandleANGLE must be able to import a valid handle. |
| TEST_P(VulkanExternalImageTest, ShouldImportSemaphoreZirconEvent) |
| { |
| ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_ANGLE_semaphore_fuchsia")); |
| RunShouldImportSemaphoreTest<FuchsiaTraits>(isSwiftshader(), enableDebugLayers()); |
| } |
| |
| template <typename Traits> |
| void RunShouldClearTest(bool useMemoryObjectFlags, |
| VkImageCreateFlags createFlags, |
| VkImageUsageFlags usageFlags, |
| bool isSwiftshader, |
| bool enableDebugLayers) |
| { |
| ASSERT(EnsureGLExtensionEnabled(Traits::MemoryObjectExtension())); |
| |
| VulkanExternalHelper helper; |
| helper.initialize(isSwiftshader, enableDebugLayers); |
| |
| VkFormat format = VK_FORMAT_R8G8B8A8_UNORM; |
| ANGLE_SKIP_TEST_IF(!Traits::CanCreateImage(helper, format, VK_IMAGE_TYPE_2D, |
| VK_IMAGE_TILING_OPTIMAL, createFlags, usageFlags)); |
| |
| VkImage image = VK_NULL_HANDLE; |
| VkDeviceMemory deviceMemory = VK_NULL_HANDLE; |
| VkDeviceSize deviceMemorySize = 0; |
| |
| VkExtent3D extent = {1, 1, 1}; |
| VkResult result = Traits::CreateImage2D(&helper, format, createFlags, usageFlags, extent, |
| &image, &deviceMemory, &deviceMemorySize); |
| EXPECT_EQ(result, VK_SUCCESS); |
| |
| typename Traits::Handle memoryHandle = Traits::InvalidHandle(); |
| result = Traits::ExportMemory(&helper, deviceMemory, &memoryHandle); |
| EXPECT_EQ(result, VK_SUCCESS); |
| EXPECT_NE(memoryHandle, Traits::InvalidHandle()); |
| |
| { |
| GLMemoryObject memoryObject; |
| GLint dedicatedMemory = GL_TRUE; |
| glMemoryObjectParameterivEXT(memoryObject, GL_DEDICATED_MEMORY_OBJECT_EXT, |
| &dedicatedMemory); |
| Traits::ImportMemory(memoryObject, deviceMemorySize, memoryHandle); |
| |
| GLTexture texture; |
| glBindTexture(GL_TEXTURE_2D, texture); |
| if (useMemoryObjectFlags) |
| { |
| glTexStorageMemFlags2DANGLE(GL_TEXTURE_2D, 1, GL_RGBA8, 1, 1, memoryObject, 0, |
| createFlags, usageFlags); |
| } |
| else |
| { |
| glTexStorageMem2DEXT(GL_TEXTURE_2D, 1, GL_RGBA8, 1, 1, memoryObject, 0); |
| } |
| |
| GLFramebuffer framebuffer; |
| glBindFramebuffer(GL_FRAMEBUFFER, framebuffer); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0); |
| |
| glClearColor(0.5f, 0.5f, 0.5f, 0.5f); |
| glClear(GL_COLOR_BUFFER_BIT); |
| |
| EXPECT_PIXEL_NEAR(0, 0, 128, 128, 128, 128, 1.0); |
| } |
| |
| EXPECT_GL_NO_ERROR(); |
| |
| vkDestroyImage(helper.getDevice(), image, nullptr); |
| vkFreeMemory(helper.getDevice(), deviceMemory, nullptr); |
| } |
| |
| // Test creating and clearing a simple RGBA8 texture in an opaque fd. |
| TEST_P(VulkanExternalImageTest, ShouldClearOpaqueFdRGBA8) |
| { |
| ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_memory_object_fd")); |
| // http://anglebug.com/4630 |
| ANGLE_SKIP_TEST_IF(IsAndroid() && IsOpenGL() && (IsPixel2() || IsPixel2XL())); |
| RunShouldClearTest<OpaqueFdTraits>(false, kDefaultImageCreateFlags, kDefaultImageUsageFlags, |
| isSwiftshader(), enableDebugLayers()); |
| } |
| |
| // Test creating and clearing a simple RGBA8 texture in an opaque fd, using |
| // GL_ANGLE_memory_object_flags. |
| TEST_P(VulkanExternalImageTest, ShouldClearOpaqueWithFlagsFdRGBA8) |
| { |
| ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_memory_object_fd")); |
| ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_ANGLE_memory_object_flags")); |
| RunShouldClearTest<OpaqueFdTraits>(true, kDefaultImageCreateFlags, kDefaultImageUsageFlags, |
| isSwiftshader(), enableDebugLayers()); |
| } |
| |
| // Test creating and clearing a simple RGBA8 texture without STORAGE usage in an opaque fd. |
| TEST_P(VulkanExternalImageTest, ShouldClearNoStorageUsageOpaqueFdRGBA8) |
| { |
| ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_memory_object_fd")); |
| ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_ANGLE_memory_object_flags")); |
| RunShouldClearTest<OpaqueFdTraits>(true, kDefaultImageCreateFlags, kNoStorageImageUsageFlags, |
| isSwiftshader(), enableDebugLayers()); |
| } |
| |
| // Test creating and clearing a simple RGBA8 texture without STORAGE usage but with MUTABLE in an |
| // opaque fd. |
| TEST_P(VulkanExternalImageTest, ShouldClearMutableNoStorageUsageOpaqueFdRGBA8) |
| { |
| ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_memory_object_fd")); |
| ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_ANGLE_memory_object_flags")); |
| RunShouldClearTest<OpaqueFdTraits>(true, kMutableImageCreateFlags, kNoStorageImageUsageFlags, |
| isSwiftshader(), enableDebugLayers()); |
| } |
| |
| // Test creating and clearing a simple RGBA8 texture in a zircon vmo. |
| TEST_P(VulkanExternalImageTest, ShouldClearZirconVmoRGBA8) |
| { |
| ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_ANGLE_memory_object_fuchsia")); |
| RunShouldClearTest<FuchsiaTraits>(false, kDefaultImageCreateFlags, kDefaultImageUsageFlags, |
| isSwiftshader(), enableDebugLayers()); |
| } |
| |
| // Test creating and clearing a simple RGBA8 texture in a zircon vmo, using |
| // GL_ANGLE_memory_object_flags. |
| TEST_P(VulkanExternalImageTest, ShouldClearZirconWithFlagsVmoRGBA8) |
| { |
| ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_ANGLE_memory_object_fuchsia")); |
| ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_ANGLE_memory_object_flags")); |
| RunShouldClearTest<FuchsiaTraits>(true, kDefaultImageCreateFlags, kDefaultImageUsageFlags, |
| isSwiftshader(), enableDebugLayers()); |
| } |
| |
| // Test creating and clearing a simple RGBA8 texture without STORAGE usage in a zircon vmo. |
| TEST_P(VulkanExternalImageTest, ShouldClearNoStorageUsageZirconVmoRGBA8) |
| { |
| ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_ANGLE_memory_object_fuchsia")); |
| ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_ANGLE_memory_object_flags")); |
| RunShouldClearTest<FuchsiaTraits>(true, kDefaultImageCreateFlags, kNoStorageImageUsageFlags, |
| isSwiftshader(), enableDebugLayers()); |
| } |
| |
| // Test creating and clearing a simple RGBA8 texture without STORAGE usage but with MUTABLE in a |
| // zircon vmo. |
| TEST_P(VulkanExternalImageTest, ShouldClearMutableNoStorageUsageZirconVmoRGBA8) |
| { |
| ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_ANGLE_memory_object_fuchsia")); |
| ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_ANGLE_memory_object_flags")); |
| RunShouldClearTest<FuchsiaTraits>(true, kMutableImageCreateFlags, kNoStorageImageUsageFlags, |
| isSwiftshader(), enableDebugLayers()); |
| } |
| |
| template <typename Traits> |
| void RunTextureFormatCompatChromiumTest(bool useMemoryObjectFlags, |
| VkImageCreateFlags createFlags, |
| VkImageUsageFlags usageFlags, |
| bool isSwiftshader, |
| bool enableDebugLayers) |
| { |
| ASSERT(EnsureGLExtensionEnabled(Traits::MemoryObjectExtension())); |
| |
| VulkanExternalHelper helper; |
| helper.initialize(isSwiftshader, enableDebugLayers); |
| for (const ImageFormatPair &format : kChromeFormats) |
| { |
| // https://crbug.com/angleproject/5046 |
| if (format.vkFormat == VK_FORMAT_R4G4B4A4_UNORM_PACK16 && IsIntel()) |
| { |
| continue; |
| } |
| |
| if (!Traits::CanCreateImage(helper, format.vkFormat, VK_IMAGE_TYPE_2D, |
| VK_IMAGE_TILING_OPTIMAL, createFlags, usageFlags)) |
| { |
| continue; |
| } |
| |
| if (format.requiredExtension && !IsGLExtensionEnabled(format.requiredExtension)) |
| { |
| continue; |
| } |
| |
| VkImage image = VK_NULL_HANDLE; |
| VkDeviceMemory deviceMemory = VK_NULL_HANDLE; |
| VkDeviceSize deviceMemorySize = 0; |
| |
| VkExtent3D extent = {113, 211, 1}; |
| VkResult result = Traits::CreateImage2D(&helper, format.vkFormat, createFlags, usageFlags, |
| extent, &image, &deviceMemory, &deviceMemorySize); |
| EXPECT_EQ(result, VK_SUCCESS); |
| |
| typename Traits::Handle memoryHandle = Traits::InvalidHandle(); |
| result = Traits::ExportMemory(&helper, deviceMemory, &memoryHandle); |
| EXPECT_EQ(result, VK_SUCCESS); |
| EXPECT_NE(memoryHandle, Traits::InvalidHandle()); |
| |
| { |
| GLMemoryObject memoryObject; |
| GLint dedicatedMemory = GL_TRUE; |
| glMemoryObjectParameterivEXT(memoryObject, GL_DEDICATED_MEMORY_OBJECT_EXT, |
| &dedicatedMemory); |
| Traits::ImportMemory(memoryObject, deviceMemorySize, memoryHandle); |
| |
| GLTexture texture; |
| glBindTexture(GL_TEXTURE_2D, texture); |
| if (useMemoryObjectFlags) |
| { |
| glTexStorageMemFlags2DANGLE(GL_TEXTURE_2D, 1, format.internalFormat, extent.width, |
| extent.height, memoryObject, 0, createFlags, |
| usageFlags); |
| } |
| else |
| { |
| glTexStorageMem2DEXT(GL_TEXTURE_2D, 1, format.internalFormat, extent.width, |
| extent.height, memoryObject, 0); |
| } |
| } |
| |
| EXPECT_GL_NO_ERROR(); |
| |
| vkDestroyImage(helper.getDevice(), image, nullptr); |
| vkFreeMemory(helper.getDevice(), deviceMemory, nullptr); |
| } |
| } |
| |
| // Test all format combinations used by Chrome import successfully (opaque fd). |
| TEST_P(VulkanExternalImageTest, TextureFormatCompatChromiumFd) |
| { |
| ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_memory_object_fd")); |
| RunTextureFormatCompatChromiumTest<OpaqueFdTraits>(false, kDefaultImageCreateFlags, |
| kDefaultImageUsageFlags, isSwiftshader(), |
| enableDebugLayers()); |
| } |
| |
| // Test all format combinations used by Chrome import successfully (opaque fd), using |
| // GL_ANGLE_memory_object_flags. |
| TEST_P(VulkanExternalImageTest, TextureFormatCompatChromiumWithFlagsFd) |
| { |
| ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_memory_object_fd")); |
| ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_ANGLE_memory_object_flags")); |
| RunTextureFormatCompatChromiumTest<OpaqueFdTraits>(true, kDefaultImageCreateFlags, |
| kDefaultImageUsageFlags, isSwiftshader(), |
| enableDebugLayers()); |
| } |
| |
| // Test all format combinations used by Chrome import successfully (opaque fd), without STORAGE |
| // usage. |
| TEST_P(VulkanExternalImageTest, TextureFormatCompatChromiumNoStorageFd) |
| { |
| ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_memory_object_fd")); |
| ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_ANGLE_memory_object_flags")); |
| RunTextureFormatCompatChromiumTest<OpaqueFdTraits>(true, kDefaultImageCreateFlags, |
| kNoStorageImageUsageFlags, isSwiftshader(), |
| enableDebugLayers()); |
| } |
| |
| // Test all format combinations used by Chrome import successfully (opaque fd), without STORAGE |
| // usage but with MUTABLE. |
| TEST_P(VulkanExternalImageTest, TextureFormatCompatChromiumMutableNoStorageFd) |
| { |
| ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_memory_object_fd")); |
| ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_ANGLE_memory_object_flags")); |
| RunTextureFormatCompatChromiumTest<OpaqueFdTraits>(true, kMutableImageCreateFlags, |
| kNoStorageImageUsageFlags, isSwiftshader(), |
| enableDebugLayers()); |
| } |
| |
| // Test all format combinations used by Chrome import successfully (fuchsia). |
| TEST_P(VulkanExternalImageTest, TextureFormatCompatChromiumZirconVmo) |
| { |
| ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_ANGLE_memory_object_fuchsia")); |
| RunTextureFormatCompatChromiumTest<FuchsiaTraits>(false, kDefaultImageCreateFlags, |
| kDefaultImageUsageFlags, isSwiftshader(), |
| enableDebugLayers()); |
| } |
| |
| // Test all format combinations used by Chrome import successfully (fuchsia), using |
| // GL_ANGLE_memory_object_flags. |
| TEST_P(VulkanExternalImageTest, TextureFormatCompatChromiumWithFlagsZirconVmo) |
| { |
| ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_ANGLE_memory_object_fuchsia")); |
| ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_ANGLE_memory_object_flags")); |
| RunTextureFormatCompatChromiumTest<FuchsiaTraits>(true, kDefaultImageCreateFlags, |
| kDefaultImageUsageFlags, isSwiftshader(), |
| enableDebugLayers()); |
| } |
| |
| // Test all format combinations used by Chrome import successfully (fuchsia), without STORAGE usage. |
| TEST_P(VulkanExternalImageTest, TextureFormatCompatChromiumNoStorageZirconVmo) |
| { |
| ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_ANGLE_memory_object_fuchsia")); |
| ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_ANGLE_memory_object_flags")); |
| RunTextureFormatCompatChromiumTest<FuchsiaTraits>(true, kDefaultImageCreateFlags, |
| kNoStorageImageUsageFlags, isSwiftshader(), |
| enableDebugLayers()); |
| } |
| |
| // Test all format combinations used by Chrome import successfully (fuchsia), without STORAGE usage |
| // but with MUTABLE. |
| TEST_P(VulkanExternalImageTest, TextureFormatCompatChromiumMutableNoStorageZirconVmo) |
| { |
| ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_ANGLE_memory_object_fuchsia")); |
| ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_ANGLE_memory_object_flags")); |
| RunTextureFormatCompatChromiumTest<FuchsiaTraits>(true, kMutableImageCreateFlags, |
| kNoStorageImageUsageFlags, isSwiftshader(), |
| enableDebugLayers()); |
| } |
| |
| template <typename Traits> |
| void RunShouldClearWithSemaphoresTest(bool useMemoryObjectFlags, |
| VkImageCreateFlags createFlags, |
| VkImageUsageFlags usageFlags, |
| bool isSwiftshader, |
| bool enableDebugLayers) |
| { |
| ASSERT(EnsureGLExtensionEnabled(Traits::MemoryObjectExtension())); |
| ASSERT(EnsureGLExtensionEnabled(Traits::SemaphoreExtension())); |
| |
| VulkanExternalHelper helper; |
| helper.initialize(isSwiftshader, enableDebugLayers); |
| |
| VkFormat format = VK_FORMAT_R8G8B8A8_UNORM; |
| ANGLE_SKIP_TEST_IF(!Traits::CanCreateImage(helper, format, VK_IMAGE_TYPE_2D, |
| VK_IMAGE_TILING_OPTIMAL, createFlags, usageFlags)); |
| ANGLE_SKIP_TEST_IF(!Traits::CanCreateSemaphore(helper)); |
| |
| VkSemaphore vkAcquireSemaphore = VK_NULL_HANDLE; |
| VkResult result = Traits::CreateSemaphore(&helper, &vkAcquireSemaphore); |
| EXPECT_EQ(result, VK_SUCCESS); |
| EXPECT_TRUE(vkAcquireSemaphore != VK_NULL_HANDLE); |
| |
| VkSemaphore vkReleaseSemaphore = VK_NULL_HANDLE; |
| result = Traits::CreateSemaphore(&helper, &vkReleaseSemaphore); |
| EXPECT_EQ(result, VK_SUCCESS); |
| EXPECT_TRUE(vkReleaseSemaphore != VK_NULL_HANDLE); |
| |
| typename Traits::Handle acquireSemaphoreHandle = Traits::InvalidHandle(); |
| result = Traits::ExportSemaphore(&helper, vkAcquireSemaphore, &acquireSemaphoreHandle); |
| EXPECT_EQ(result, VK_SUCCESS); |
| EXPECT_NE(acquireSemaphoreHandle, Traits::InvalidHandle()); |
| |
| typename Traits::Handle releaseSemaphoreHandle = Traits::InvalidHandle(); |
| result = Traits::ExportSemaphore(&helper, vkReleaseSemaphore, &releaseSemaphoreHandle); |
| EXPECT_EQ(result, VK_SUCCESS); |
| EXPECT_NE(releaseSemaphoreHandle, Traits::InvalidHandle()); |
| |
| VkImage image = VK_NULL_HANDLE; |
| VkDeviceMemory deviceMemory = VK_NULL_HANDLE; |
| VkDeviceSize deviceMemorySize = 0; |
| |
| VkExtent3D extent = {1, 1, 1}; |
| result = Traits::CreateImage2D(&helper, format, createFlags, usageFlags, extent, &image, |
| &deviceMemory, &deviceMemorySize); |
| EXPECT_EQ(result, VK_SUCCESS); |
| |
| typename Traits::Handle memoryHandle = Traits::InvalidHandle(); |
| result = Traits::ExportMemory(&helper, deviceMemory, &memoryHandle); |
| EXPECT_EQ(result, VK_SUCCESS); |
| EXPECT_NE(memoryHandle, Traits::InvalidHandle()); |
| |
| { |
| GLMemoryObject memoryObject; |
| GLint dedicatedMemory = GL_TRUE; |
| glMemoryObjectParameterivEXT(memoryObject, GL_DEDICATED_MEMORY_OBJECT_EXT, |
| &dedicatedMemory); |
| Traits::ImportMemory(memoryObject, deviceMemorySize, memoryHandle); |
| |
| GLTexture texture; |
| glBindTexture(GL_TEXTURE_2D, texture); |
| if (useMemoryObjectFlags) |
| { |
| glTexStorageMemFlags2DANGLE(GL_TEXTURE_2D, 1, GL_RGBA8, 1, 1, memoryObject, 0, |
| createFlags, usageFlags); |
| } |
| else |
| { |
| glTexStorageMem2DEXT(GL_TEXTURE_2D, 1, GL_RGBA8, 1, 1, memoryObject, 0); |
| } |
| |
| GLSemaphore glAcquireSemaphore; |
| Traits::ImportSemaphore(glAcquireSemaphore, acquireSemaphoreHandle); |
| |
| helper.releaseImageAndSignalSemaphore(image, VK_IMAGE_LAYOUT_UNDEFINED, |
| VK_IMAGE_LAYOUT_GENERAL, vkAcquireSemaphore); |
| |
| const GLuint barrierTextures[] = { |
| texture, |
| }; |
| constexpr uint32_t textureBarriersCount = std::extent<decltype(barrierTextures)>(); |
| const GLenum textureSrcLayouts[] = { |
| GL_LAYOUT_GENERAL_EXT, |
| }; |
| constexpr uint32_t textureSrcLayoutsCount = std::extent<decltype(textureSrcLayouts)>(); |
| static_assert(textureBarriersCount == textureSrcLayoutsCount, |
| "barrierTextures and textureSrcLayouts must be the same length"); |
| glWaitSemaphoreEXT(glAcquireSemaphore, 0, nullptr, textureBarriersCount, barrierTextures, |
| textureSrcLayouts); |
| |
| GLFramebuffer framebuffer; |
| glBindFramebuffer(GL_FRAMEBUFFER, framebuffer); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0); |
| |
| glClearColor(0.5f, 0.5f, 0.5f, 0.5f); |
| glClear(GL_COLOR_BUFFER_BIT); |
| |
| GLSemaphore glReleaseSemaphore; |
| Traits::ImportSemaphore(glReleaseSemaphore, releaseSemaphoreHandle); |
| |
| const GLenum textureDstLayouts[] = { |
| GL_LAYOUT_TRANSFER_SRC_EXT, |
| }; |
| constexpr uint32_t textureDstLayoutsCount = std::extent<decltype(textureSrcLayouts)>(); |
| static_assert(textureBarriersCount == textureDstLayoutsCount, |
| "barrierTextures and textureDstLayouts must be the same length"); |
| glSignalSemaphoreEXT(glReleaseSemaphore, 0, nullptr, textureBarriersCount, barrierTextures, |
| textureDstLayouts); |
| |
| helper.waitSemaphoreAndAcquireImage(image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, |
| VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, |
| vkReleaseSemaphore); |
| uint8_t pixels[4]; |
| VkOffset3D offset = {}; |
| VkExtent3D extent = {1, 1, 1}; |
| helper.readPixels(image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, format, offset, extent, |
| pixels, sizeof(pixels)); |
| |
| EXPECT_NEAR(0x80, pixels[0], 1); |
| EXPECT_NEAR(0x80, pixels[1], 1); |
| EXPECT_NEAR(0x80, pixels[2], 1); |
| EXPECT_NEAR(0x80, pixels[3], 1); |
| } |
| |
| EXPECT_GL_NO_ERROR(); |
| |
| vkDeviceWaitIdle(helper.getDevice()); |
| vkDestroyImage(helper.getDevice(), image, nullptr); |
| vkDestroySemaphore(helper.getDevice(), vkAcquireSemaphore, nullptr); |
| vkDestroySemaphore(helper.getDevice(), vkReleaseSemaphore, nullptr); |
| vkFreeMemory(helper.getDevice(), deviceMemory, nullptr); |
| } |
| |
| // Test creating and clearing RGBA8 texture in opaque fd with acquire/release. |
| TEST_P(VulkanExternalImageTest, ShouldClearOpaqueFdWithSemaphores) |
| { |
| ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_memory_object_fd")); |
| ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_semaphore_fd")); |
| |
| // http://issuetracker.google.com/173004081 |
| ANGLE_SKIP_TEST_IF(IsVulkan() && IsIntel() && IsLinux() && isAsyncCommandQueueFeatureEnabled()); |
| |
| RunShouldClearWithSemaphoresTest<OpaqueFdTraits>(false, kDefaultImageCreateFlags, |
| kDefaultImageUsageFlags, isSwiftshader(), |
| enableDebugLayers()); |
| } |
| |
| // Test creating and clearing RGBA8 texture in opaque fd with acquire/release, using |
| // GL_ANGLE_memory_object_flags. |
| TEST_P(VulkanExternalImageTest, ShouldClearOpaqueFdWithSemaphoresWithFlags) |
| { |
| ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_memory_object_fd")); |
| ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_semaphore_fd")); |
| ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_ANGLE_memory_object_flags")); |
| |
| // http://issuetracker.google.com/173004081 |
| ANGLE_SKIP_TEST_IF(IsVulkan() && IsIntel() && IsLinux() && isAsyncCommandQueueFeatureEnabled()); |
| |
| RunShouldClearWithSemaphoresTest<OpaqueFdTraits>(true, kDefaultImageCreateFlags, |
| kDefaultImageUsageFlags, isSwiftshader(), |
| enableDebugLayers()); |
| } |
| |
| // Test creating and clearing RGBA8 texture without STORAGE usage in opaque fd with acquire/release. |
| TEST_P(VulkanExternalImageTest, ShouldClearOpaqueFdWithSemaphoresNoStorage) |
| { |
| ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_memory_object_fd")); |
| ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_semaphore_fd")); |
| ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_ANGLE_memory_object_flags")); |
| |
| // http://issuetracker.google.com/173004081 |
| ANGLE_SKIP_TEST_IF(IsVulkan() && IsIntel() && IsLinux() && isAsyncCommandQueueFeatureEnabled()); |
| |
| RunShouldClearWithSemaphoresTest<OpaqueFdTraits>(true, kDefaultImageCreateFlags, |
| kNoStorageImageUsageFlags, isSwiftshader(), |
| enableDebugLayers()); |
| } |
| |
| // Test creating and clearing RGBA8 texture without STORAGE usage but with MUTABLE in opaque fd with |
| // acquire/release. |
| TEST_P(VulkanExternalImageTest, ShouldClearOpaqueFdWithSemaphoresMutableNoStorage) |
| { |
| ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_memory_object_fd")); |
| ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_semaphore_fd")); |
| ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_ANGLE_memory_object_flags")); |
| |
| // http://issuetracker.google.com/173004081 |
| ANGLE_SKIP_TEST_IF(IsVulkan() && IsIntel() && IsLinux() && isAsyncCommandQueueFeatureEnabled()); |
| |
| RunShouldClearWithSemaphoresTest<OpaqueFdTraits>(true, kMutableImageCreateFlags, |
| kNoStorageImageUsageFlags, isSwiftshader(), |
| enableDebugLayers()); |
| } |
| |
| // Test creating and clearing RGBA8 texture in zircon vmo with acquire/release. |
| TEST_P(VulkanExternalImageTest, ShouldClearZirconVmoWithSemaphores) |
| { |
| ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_ANGLE_memory_object_fuchsia")); |
| ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_ANGLE_semaphore_fuchsia")); |
| RunShouldClearWithSemaphoresTest<FuchsiaTraits>(false, kDefaultImageCreateFlags, |
| kDefaultImageUsageFlags, isSwiftshader(), |
| enableDebugLayers()); |
| } |
| |
| // Test creating and clearing RGBA8 texture in zircon vmo with acquire/release, using |
| // GL_ANGLE_memory_object_flags. |
| TEST_P(VulkanExternalImageTest, ShouldClearZirconVmoWithSemaphoresWithFlags) |
| { |
| ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_ANGLE_memory_object_fuchsia")); |
| ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_ANGLE_semaphore_fuchsia")); |
| ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_ANGLE_memory_object_flags")); |
| RunShouldClearWithSemaphoresTest<FuchsiaTraits>(true, kDefaultImageCreateFlags, |
| kDefaultImageUsageFlags, isSwiftshader(), |
| enableDebugLayers()); |
| } |
| |
| // Test creating and clearing RGBA8 texture without STORAGE usage in zircon vmo with |
| // acquire/release. |
| TEST_P(VulkanExternalImageTest, ShouldClearZirconVmoWithSemaphoresNoStorage) |
| { |
| ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_ANGLE_memory_object_fuchsia")); |
| ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_ANGLE_semaphore_fuchsia")); |
| ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_ANGLE_memory_object_flags")); |
| RunShouldClearWithSemaphoresTest<FuchsiaTraits>(true, kDefaultImageCreateFlags, |
| kNoStorageImageUsageFlags, isSwiftshader(), |
| enableDebugLayers()); |
| } |
| |
| // Test creating and clearing RGBA8 texture without STORAGE usage but with MUTABLE in zircon vmo |
| // with acquire/release. |
| TEST_P(VulkanExternalImageTest, ShouldClearZirconVmoWithSemaphoresMutableNoStorage) |
| { |
| ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_ANGLE_memory_object_fuchsia")); |
| ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_ANGLE_semaphore_fuchsia")); |
| ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_ANGLE_memory_object_flags")); |
| RunShouldClearWithSemaphoresTest<FuchsiaTraits>(true, kMutableImageCreateFlags, |
| kNoStorageImageUsageFlags, isSwiftshader(), |
| enableDebugLayers()); |
| } |
| |
| template <typename Traits> |
| void VulkanExternalImageTest::runShouldDrawTest(bool isSwiftshader, bool enableDebugLayers) |
| { |
| ASSERT(EnsureGLExtensionEnabled(Traits::MemoryObjectExtension())); |
| ASSERT(EnsureGLExtensionEnabled(Traits::SemaphoreExtension())); |
| |
| VulkanExternalHelper helper; |
| helper.initialize(isSwiftshader, enableDebugLayers); |
| |
| VkFormat format = VK_FORMAT_R8G8B8A8_UNORM; |
| ANGLE_SKIP_TEST_IF(!Traits::CanCreateImage(helper, format, VK_IMAGE_TYPE_2D, |
| VK_IMAGE_TILING_OPTIMAL, kDefaultImageCreateFlags, |
| kDefaultImageUsageFlags)); |
| ANGLE_SKIP_TEST_IF(!Traits::CanCreateSemaphore(helper)); |
| |
| VkSemaphore vkAcquireSemaphore = VK_NULL_HANDLE; |
| VkResult result = Traits::CreateSemaphore(&helper, &vkAcquireSemaphore); |
| EXPECT_EQ(result, VK_SUCCESS); |
| EXPECT_TRUE(vkAcquireSemaphore != VK_NULL_HANDLE); |
| |
| VkSemaphore vkReleaseSemaphore = VK_NULL_HANDLE; |
| result = Traits::CreateSemaphore(&helper, &vkReleaseSemaphore); |
| EXPECT_EQ(result, VK_SUCCESS); |
| EXPECT_TRUE(vkReleaseSemaphore != VK_NULL_HANDLE); |
| |
| typename Traits::Handle acquireSemaphoreHandle = Traits::InvalidHandle(); |
| result = Traits::ExportSemaphore(&helper, vkAcquireSemaphore, &acquireSemaphoreHandle); |
| EXPECT_EQ(result, VK_SUCCESS); |
| EXPECT_NE(acquireSemaphoreHandle, Traits::InvalidHandle()); |
| |
| typename Traits::Handle releaseSemaphoreHandle = Traits::InvalidHandle(); |
| result = Traits::ExportSemaphore(&helper, vkReleaseSemaphore, &releaseSemaphoreHandle); |
| EXPECT_EQ(result, VK_SUCCESS); |
| EXPECT_NE(releaseSemaphoreHandle, Traits::InvalidHandle()); |
| |
| VkImage image = VK_NULL_HANDLE; |
| VkDeviceMemory deviceMemory = VK_NULL_HANDLE; |
| VkDeviceSize deviceMemorySize = 0; |
| |
| VkExtent3D extent = {1, 1, 1}; |
| result = |
| Traits::CreateImage2D(&helper, format, kDefaultImageCreateFlags, kDefaultImageUsageFlags, |
| extent, &image, &deviceMemory, &deviceMemorySize); |
| EXPECT_EQ(result, VK_SUCCESS); |
| |
| typename Traits::Handle memoryHandle = Traits::InvalidHandle(); |
| result = Traits::ExportMemory(&helper, deviceMemory, &memoryHandle); |
| EXPECT_EQ(result, VK_SUCCESS); |
| EXPECT_NE(memoryHandle, Traits::InvalidHandle()); |
| |
| { |
| GLMemoryObject memoryObject; |
| GLint dedicatedMemory = GL_TRUE; |
| glMemoryObjectParameterivEXT(memoryObject, GL_DEDICATED_MEMORY_OBJECT_EXT, |
| &dedicatedMemory); |
| Traits::ImportMemory(memoryObject, deviceMemorySize, memoryHandle); |
| |
| GLTexture texture; |
| glBindTexture(GL_TEXTURE_2D, texture); |
| glTexStorageMem2DEXT(GL_TEXTURE_2D, 1, GL_RGBA8, 1, 1, memoryObject, 0); |
| |
| GLSemaphore glAcquireSemaphore; |
| Traits::ImportSemaphore(glAcquireSemaphore, acquireSemaphoreHandle); |
| |
| // Transfer ownership to GL. |
| helper.releaseImageAndSignalSemaphore(image, VK_IMAGE_LAYOUT_UNDEFINED, |
| VK_IMAGE_LAYOUT_GENERAL, vkAcquireSemaphore); |
| |
| const GLuint barrierTextures[] = { |
| texture, |
| }; |
| constexpr uint32_t textureBarriersCount = std::extent<decltype(barrierTextures)>(); |
| const GLenum textureSrcLayouts[] = { |
| GL_LAYOUT_GENERAL_EXT, |
| }; |
| constexpr uint32_t textureSrcLayoutsCount = std::extent<decltype(textureSrcLayouts)>(); |
| static_assert(textureBarriersCount == textureSrcLayoutsCount, |
| "barrierTextures and textureSrcLayouts must be the same length"); |
| glWaitSemaphoreEXT(glAcquireSemaphore, 0, nullptr, textureBarriersCount, barrierTextures, |
| textureSrcLayouts); |
| |
| GLFramebuffer framebuffer; |
| glBindFramebuffer(GL_FRAMEBUFFER, framebuffer); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0); |
| EXPECT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| |
| // Make the texture red. |
| ANGLE_GL_PROGRAM(drawRed, essl1_shaders::vs::Simple(), essl1_shaders::fs::Red()); |
| drawQuad(drawRed, essl1_shaders::PositionAttrib(), 0.0f); |
| EXPECT_GL_NO_ERROR(); |
| |
| // Transfer ownership back to test. |
| GLSemaphore glReleaseSemaphore; |
| Traits::ImportSemaphore(glReleaseSemaphore, releaseSemaphoreHandle); |
| |
| const GLenum textureDstLayouts[] = { |
| GL_LAYOUT_TRANSFER_SRC_EXT, |
| }; |
| constexpr uint32_t textureDstLayoutsCount = std::extent<decltype(textureSrcLayouts)>(); |
| static_assert(textureBarriersCount == textureDstLayoutsCount, |
| "barrierTextures and textureDstLayouts must be the same length"); |
| glSignalSemaphoreEXT(glReleaseSemaphore, 0, nullptr, textureBarriersCount, barrierTextures, |
| textureDstLayouts); |
| |
| helper.waitSemaphoreAndAcquireImage(image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, |
| VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, |
| vkReleaseSemaphore); |
| |
| uint8_t pixels[4]; |
| VkOffset3D offset = {}; |
| VkExtent3D extent = {1, 1, 1}; |
| helper.readPixels(image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, format, offset, extent, |
| pixels, sizeof(pixels)); |
| |
| EXPECT_EQ(0xFF, pixels[0]); |
| EXPECT_EQ(0x00, pixels[1]); |
| EXPECT_EQ(0x00, pixels[2]); |
| EXPECT_EQ(0xFF, pixels[3]); |
| } |
| |
| EXPECT_GL_NO_ERROR(); |
| |
| vkDeviceWaitIdle(helper.getDevice()); |
| vkDestroyImage(helper.getDevice(), image, nullptr); |
| vkDestroySemaphore(helper.getDevice(), vkAcquireSemaphore, nullptr); |
| vkDestroySemaphore(helper.getDevice(), vkReleaseSemaphore, nullptr); |
| vkFreeMemory(helper.getDevice(), deviceMemory, nullptr); |
| } |
| |
| // Test drawing to RGBA8 texture in opaque fd with acquire/release. |
| TEST_P(VulkanExternalImageTest, ShouldDrawOpaqueFdWithSemaphores) |
| { |
| ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_memory_object_fd")); |
| ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_semaphore_fd")); |
| |
| // http://issuetracker.google.com/173004081 |
| ANGLE_SKIP_TEST_IF(IsVulkan() && IsIntel() && IsLinux() && isAsyncCommandQueueFeatureEnabled()); |
| |
| runShouldDrawTest<OpaqueFdTraits>(isSwiftshader(), enableDebugLayers()); |
| } |
| |
| // Test drawing to RGBA8 texture in zircon vmo with acquire/release multiple times. |
| TEST_P(VulkanExternalImageTest, ShouldDrawZirconVmoWithSemaphores) |
| { |
| ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_ANGLE_memory_object_fuchsia")); |
| ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_ANGLE_semaphore_fuchsia")); |
| runShouldDrawTest<FuchsiaTraits>(isSwiftshader(), enableDebugLayers()); |
| } |
| |
| template <typename Traits> |
| void VulkanExternalImageTest::runWaitSemaphoresRetainsContentTest(bool isSwiftshader, |
| bool enableDebugLayers) |
| { |
| ASSERT(EnsureGLExtensionEnabled(Traits::MemoryObjectExtension())); |
| ASSERT(EnsureGLExtensionEnabled(Traits::SemaphoreExtension())); |
| |
| VulkanExternalHelper helper; |
| helper.initialize(isSwiftshader, enableDebugLayers); |
| |
| VkFormat format = VK_FORMAT_R8G8B8A8_UNORM; |
| ANGLE_SKIP_TEST_IF(!Traits::CanCreateImage(helper, format, VK_IMAGE_TYPE_2D, |
| VK_IMAGE_TILING_OPTIMAL, kDefaultImageCreateFlags, |
| kDefaultImageUsageFlags)); |
| ANGLE_SKIP_TEST_IF(!Traits::CanCreateSemaphore(helper)); |
| |
| VkSemaphore vkAcquireSemaphore = VK_NULL_HANDLE; |
| VkResult result = Traits::CreateSemaphore(&helper, &vkAcquireSemaphore); |
| EXPECT_EQ(result, VK_SUCCESS); |
| EXPECT_TRUE(vkAcquireSemaphore != VK_NULL_HANDLE); |
| |
| VkSemaphore vkReleaseSemaphore = VK_NULL_HANDLE; |
| result = Traits::CreateSemaphore(&helper, &vkReleaseSemaphore); |
| EXPECT_EQ(result, VK_SUCCESS); |
| EXPECT_TRUE(vkReleaseSemaphore != VK_NULL_HANDLE); |
| |
| typename Traits::Handle acquireSemaphoreHandle = Traits::InvalidHandle(); |
| result = Traits::ExportSemaphore(&helper, vkAcquireSemaphore, &acquireSemaphoreHandle); |
| EXPECT_EQ(result, VK_SUCCESS); |
| EXPECT_NE(acquireSemaphoreHandle, Traits::InvalidHandle()); |
| |
| typename Traits::Handle releaseSemaphoreHandle = Traits::InvalidHandle(); |
| result = Traits::ExportSemaphore(&helper, vkReleaseSemaphore, &releaseSemaphoreHandle); |
| EXPECT_EQ(result, VK_SUCCESS); |
| EXPECT_NE(releaseSemaphoreHandle, Traits::InvalidHandle()); |
| |
| VkImage image = VK_NULL_HANDLE; |
| VkDeviceMemory deviceMemory = VK_NULL_HANDLE; |
| VkDeviceSize deviceMemorySize = 0; |
| |
| VkExtent3D extent = {1, 1, 1}; |
| result = |
| Traits::CreateImage2D(&helper, format, kDefaultImageCreateFlags, kDefaultImageUsageFlags, |
| extent, &image, &deviceMemory, &deviceMemorySize); |
| EXPECT_EQ(result, VK_SUCCESS); |
| |
| typename Traits::Handle memoryHandle = Traits::InvalidHandle(); |
| result = Traits::ExportMemory(&helper, deviceMemory, &memoryHandle); |
| EXPECT_EQ(result, VK_SUCCESS); |
| EXPECT_NE(memoryHandle, Traits::InvalidHandle()); |
| |
| { |
| GLMemoryObject memoryObject; |
| GLint dedicatedMemory = GL_TRUE; |
| glMemoryObjectParameterivEXT(memoryObject, GL_DEDICATED_MEMORY_OBJECT_EXT, |
| &dedicatedMemory); |
| Traits::ImportMemory(memoryObject, deviceMemorySize, memoryHandle); |
| |
| GLTexture texture; |
| glBindTexture(GL_TEXTURE_2D, texture); |
| glTexStorageMem2DEXT(GL_TEXTURE_2D, 1, GL_RGBA8, 1, 1, memoryObject, 0); |
| |
| GLSemaphore glAcquireSemaphore; |
| Traits::ImportSemaphore(glAcquireSemaphore, acquireSemaphoreHandle); |
| |
| // Transfer ownership to GL. |
| helper.releaseImageAndSignalSemaphore(image, VK_IMAGE_LAYOUT_UNDEFINED, |
| VK_IMAGE_LAYOUT_GENERAL, vkAcquireSemaphore); |
| |
| const GLuint barrierTextures[] = { |
| texture, |
| }; |
| constexpr uint32_t textureBarriersCount = std::extent<decltype(barrierTextures)>(); |
| const GLenum textureSrcLayouts[] = { |
| GL_LAYOUT_GENERAL_EXT, |
| }; |
| constexpr uint32_t textureSrcLayoutsCount = std::extent<decltype(textureSrcLayouts)>(); |
| static_assert(textureBarriersCount == textureSrcLayoutsCount, |
| "barrierTextures and textureSrcLayouts must be the same length"); |
| glWaitSemaphoreEXT(glAcquireSemaphore, 0, nullptr, textureBarriersCount, barrierTextures, |
| textureSrcLayouts); |
| |
| GLFramebuffer framebuffer; |
| glBindFramebuffer(GL_FRAMEBUFFER, framebuffer); |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0); |
| EXPECT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| |
| // Make the texture red. |
| ANGLE_GL_PROGRAM(drawRed, essl1_shaders::vs::Simple(), essl1_shaders::fs::Red()); |
| drawQuad(drawRed, essl1_shaders::PositionAttrib(), 0.0f); |
| EXPECT_GL_NO_ERROR(); |
| |
| // Transfer ownership back to test. |
| GLSemaphore glReleaseSemaphore; |
| Traits::ImportSemaphore(glReleaseSemaphore, releaseSemaphoreHandle); |
| |
| const GLenum textureDstLayouts[] = { |
| GL_LAYOUT_TRANSFER_SRC_EXT, |
| }; |
| constexpr uint32_t textureDstLayoutsCount = std::extent<decltype(textureSrcLayouts)>(); |
| static_assert(textureBarriersCount == textureDstLayoutsCount, |
| "barrierTextures and textureDstLayouts must be the same length"); |
| glSignalSemaphoreEXT(glReleaseSemaphore, 0, nullptr, textureBarriersCount, barrierTextures, |
| textureDstLayouts); |
| |
| helper.waitSemaphoreAndAcquireImage(image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, |
| VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, |
| vkReleaseSemaphore); |
| |
| // Transfer ownership to GL again, and make sure the contents are preserved. |
| helper.releaseImageAndSignalSemaphore(image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, |
| VK_IMAGE_LAYOUT_GENERAL, vkAcquireSemaphore); |
| glWaitSemaphoreEXT(glAcquireSemaphore, 0, nullptr, textureBarriersCount, barrierTextures, |
| textureSrcLayouts); |
| |
| // Blend green |
| ANGLE_GL_PROGRAM(drawGreen, essl1_shaders::vs::Simple(), essl1_shaders::fs::Green()); |
| glEnable(GL_BLEND); |
| glBlendFunc(GL_ONE, GL_ONE); |
| drawQuad(drawGreen, essl1_shaders::PositionAttrib(), 0.0f); |
| |
| // Transfer ownership back to test |
| glSignalSemaphoreEXT(glReleaseSemaphore, 0, nullptr, textureBarriersCount, barrierTextures, |
| textureDstLayouts); |
| helper.waitSemaphoreAndAcquireImage(image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, |
| VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, |
| vkReleaseSemaphore); |
| |
| uint8_t pixels[4]; |
| VkOffset3D offset = {}; |
| VkExtent3D extent = {1, 1, 1}; |
| helper.readPixels(image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, format, offset, extent, |
| pixels, sizeof(pixels)); |
| |
| EXPECT_EQ(0xFF, pixels[0]); |
| EXPECT_EQ(0xFF, pixels[1]); |
| EXPECT_EQ(0x00, pixels[2]); |
| EXPECT_EQ(0xFF, pixels[3]); |
| } |
| |
| EXPECT_GL_NO_ERROR(); |
| |
| vkDeviceWaitIdle(helper.getDevice()); |
| vkDestroyImage(helper.getDevice(), image, nullptr); |
| vkDestroySemaphore(helper.getDevice(), vkAcquireSemaphore, nullptr); |
| vkDestroySemaphore(helper.getDevice(), vkReleaseSemaphore, nullptr); |
| vkFreeMemory(helper.getDevice(), deviceMemory, nullptr); |
| } |
| |
| // Test drawing to RGBA8 texture in opaque fd with acquire/release multiple times. |
| TEST_P(VulkanExternalImageTest, WaitSemaphoresRetainsContentOpaqueFd) |
| { |
| ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_memory_object_fd")); |
| ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_semaphore_fd")); |
| |
| // http://issuetracker.google.com/173004081 |
| ANGLE_SKIP_TEST_IF(IsVulkan() && IsIntel() && IsLinux() && isAsyncCommandQueueFeatureEnabled()); |
| |
| runWaitSemaphoresRetainsContentTest<OpaqueFdTraits>(isSwiftshader(), enableDebugLayers()); |
| } |
| |
| // Test drawing to RGBA8 texture in zircon vmo with acquire/release multiple times. |
| TEST_P(VulkanExternalImageTest, WaitSemaphoresRetainsContentZirconVmo) |
| { |
| ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_ANGLE_memory_object_fuchsia")); |
| ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_ANGLE_semaphore_fuchsia")); |
| runWaitSemaphoresRetainsContentTest<FuchsiaTraits>(isSwiftshader(), enableDebugLayers()); |
| } |
| |
| // Support for Zircon handle types is mandatory on Fuchsia. |
| TEST_P(VulkanExternalImageTest, ShouldSupportExternalHandlesFuchsia) |
| { |
| ANGLE_SKIP_TEST_IF(!IsFuchsia()); |
| EXPECT_TRUE(EnsureGLExtensionEnabled("GL_ANGLE_memory_object_fuchsia")); |
| EXPECT_TRUE(EnsureGLExtensionEnabled("GL_ANGLE_semaphore_fuchsia")); |
| VulkanExternalHelper helper; |
| helper.initialize(isSwiftshader(), enableDebugLayers()); |
| EXPECT_TRUE(helper.canCreateSemaphoreZirconEvent()); |
| EXPECT_TRUE(helper.canCreateImageZirconVmo(VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_TYPE_2D, |
| VK_IMAGE_TILING_OPTIMAL, kDefaultImageCreateFlags, |
| kDefaultImageUsageFlags)); |
| } |
| |
| // Use this to select which configurations (e.g. which renderer, which GLES major version) these |
| // tests should be run against. |
| ANGLE_INSTANTIATE_TEST_ES2_AND_ES3(VulkanExternalImageTest); |
| |
| } // namespace angle |