xref: /aosp_15_r20/external/angle/src/tests/gl_tests/VulkanImageTest.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
1 //
2 // Copyright 2021 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 // VulkanImageTest.cpp : Tests of EGL_ANGLE_vulkan_image & GL_ANGLE_vulkan_image extensions.
8 
9 #include "test_utils/ANGLETest.h"
10 
11 #include "common/debug.h"
12 #include "test_utils/VulkanHelper.h"
13 #include "test_utils/angle_test_instantiate.h"
14 #include "test_utils/gl_raii.h"
15 
16 namespace angle
17 {
18 
19 constexpr GLuint kWidth  = 64u;
20 constexpr GLuint kHeight = 64u;
21 constexpr GLuint kWhite  = 0xffffffff;
22 constexpr GLuint kRed    = 0xff0000ff;
23 
24 class VulkanImageTest : public ANGLETest<>
25 {
26   protected:
VulkanImageTest()27     VulkanImageTest() { setRobustResourceInit(true); }
28 };
29 
30 class VulkanMemoryTest : public ANGLETest<>
31 {
32   protected:
VulkanMemoryTest()33     VulkanMemoryTest() { setRobustResourceInit(true); }
34 
35     bool compatibleMemorySizesForDeviceOOMTest(VkPhysicalDevice physicalDevice,
36                                                VkDeviceSize *totalDeviceMemorySizeOut);
37 
getPerfCounters()38     angle::VulkanPerfCounters getPerfCounters()
39     {
40         if (mIndexMap.empty())
41         {
42             mIndexMap = BuildCounterNameToIndexMap();
43         }
44 
45         return GetPerfCounters(mIndexMap);
46     }
47 
48     CounterNameToIndexMap mIndexMap;
49 };
50 
compatibleMemorySizesForDeviceOOMTest(VkPhysicalDevice physicalDevice,VkDeviceSize * totalDeviceMemorySizeOut)51 bool VulkanMemoryTest::compatibleMemorySizesForDeviceOOMTest(VkPhysicalDevice physicalDevice,
52                                                              VkDeviceSize *totalDeviceMemorySizeOut)
53 {
54     // Acquire the sizes and memory property flags for all available memory types. There should be
55     // at least one memory heap without the device local bit (VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT).
56     // Otherwise, the test should be skipped.
57     VkPhysicalDeviceMemoryProperties memoryProperties;
58     vkGetPhysicalDeviceMemoryProperties(physicalDevice, &memoryProperties);
59 
60     *totalDeviceMemorySizeOut                 = 0;
61     uint32_t heapsWithoutLocalDeviceMemoryBit = 0;
62     for (uint32_t i = 0; i < memoryProperties.memoryHeapCount; i++)
63     {
64         if ((memoryProperties.memoryHeaps[i].flags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) == 0)
65         {
66             heapsWithoutLocalDeviceMemoryBit++;
67         }
68         else
69         {
70             *totalDeviceMemorySizeOut += memoryProperties.memoryHeaps[i].size;
71         }
72     }
73 
74     bool isCompatible = heapsWithoutLocalDeviceMemoryBit != 0 && *totalDeviceMemorySizeOut != 0;
75     return isCompatible;
76 }
77 
78 // Check extensions with Vukan backend.
TEST_P(VulkanImageTest,HasVulkanImageExtensions)79 TEST_P(VulkanImageTest, HasVulkanImageExtensions)
80 {
81     ANGLE_SKIP_TEST_IF(!IsVulkan());
82 
83     EGLWindow *window  = getEGLWindow();
84     EGLDisplay display = window->getDisplay();
85 
86     EXPECT_TRUE(IsEGLClientExtensionEnabled("EGL_EXT_device_query"));
87     EXPECT_TRUE(IsEGLDisplayExtensionEnabled(display, "EGL_ANGLE_vulkan_image"));
88     EXPECT_TRUE(IsGLExtensionEnabled("GL_ANGLE_vulkan_image"));
89 
90     EGLAttrib result = 0;
91     EXPECT_EGL_TRUE(eglQueryDisplayAttribEXT(display, EGL_DEVICE_EXT, &result));
92 
93     EGLDeviceEXT device = reinterpret_cast<EGLDeviceEXT>(result);
94     EXPECT_NE(EGL_NO_DEVICE_EXT, device);
95     EXPECT_TRUE(IsEGLDeviceExtensionEnabled(device, "EGL_ANGLE_device_vulkan"));
96 }
97 
TEST_P(VulkanImageTest,DeviceVulkan)98 TEST_P(VulkanImageTest, DeviceVulkan)
99 {
100     ANGLE_SKIP_TEST_IF(!IsVulkan());
101 
102     EGLWindow *window  = getEGLWindow();
103     EGLDisplay display = window->getDisplay();
104 
105     EGLAttrib result = 0;
106     EXPECT_EGL_TRUE(eglQueryDisplayAttribEXT(display, EGL_DEVICE_EXT, &result));
107 
108     EGLDeviceEXT device = reinterpret_cast<EGLDeviceEXT>(result);
109     EXPECT_NE(EGL_NO_DEVICE_EXT, device);
110 
111     EXPECT_EGL_TRUE(eglQueryDeviceAttribEXT(device, EGL_VULKAN_INSTANCE_ANGLE, &result));
112     VkInstance instance = reinterpret_cast<VkInstance>(result);
113     EXPECT_NE(instance, static_cast<VkInstance>(VK_NULL_HANDLE));
114 
115     EXPECT_EGL_TRUE(eglQueryDeviceAttribEXT(device, EGL_VULKAN_PHYSICAL_DEVICE_ANGLE, &result));
116     VkPhysicalDevice physical_device = reinterpret_cast<VkPhysicalDevice>(result);
117     EXPECT_NE(physical_device, static_cast<VkPhysicalDevice>(VK_NULL_HANDLE));
118 
119     EXPECT_EGL_TRUE(eglQueryDeviceAttribEXT(device, EGL_VULKAN_DEVICE_ANGLE, &result));
120     VkDevice vk_device = reinterpret_cast<VkDevice>(result);
121     EXPECT_NE(vk_device, static_cast<VkDevice>(VK_NULL_HANDLE));
122 
123     EXPECT_EGL_TRUE(eglQueryDeviceAttribEXT(device, EGL_VULKAN_QUEUE_ANGLE, &result));
124     VkQueue queue = reinterpret_cast<VkQueue>(result);
125     EXPECT_NE(queue, static_cast<VkQueue>(VK_NULL_HANDLE));
126 
127     EXPECT_EGL_TRUE(eglQueryDeviceAttribEXT(device, EGL_VULKAN_QUEUE_FAMILIY_INDEX_ANGLE, &result));
128 
129     {
130         EXPECT_EGL_TRUE(
131             eglQueryDeviceAttribEXT(device, EGL_VULKAN_DEVICE_EXTENSIONS_ANGLE, &result));
132         const char *const *extensions = reinterpret_cast<const char *const *>(result);
133         EXPECT_NE(extensions, nullptr);
134         int extension_count = 0;
135         while (extensions[extension_count])
136         {
137             extension_count++;
138         }
139         EXPECT_NE(extension_count, 0);
140     }
141 
142     {
143         EXPECT_EGL_TRUE(
144             eglQueryDeviceAttribEXT(device, EGL_VULKAN_INSTANCE_EXTENSIONS_ANGLE, &result));
145         const char *const *extensions = reinterpret_cast<const char *const *>(result);
146         EXPECT_NE(extensions, nullptr);
147         int extension_count = 0;
148         while (extensions[extension_count])
149         {
150             extension_count++;
151         }
152         EXPECT_NE(extension_count, 0);
153     }
154 
155     EXPECT_EGL_TRUE(eglQueryDeviceAttribEXT(device, EGL_VULKAN_FEATURES_ANGLE, &result));
156     const VkPhysicalDeviceFeatures2 *features =
157         reinterpret_cast<const VkPhysicalDeviceFeatures2 *>(result);
158     EXPECT_NE(features, nullptr);
159     EXPECT_EQ(features->sType, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2);
160 
161     EXPECT_EGL_TRUE(eglQueryDeviceAttribEXT(device, EGL_VULKAN_GET_INSTANCE_PROC_ADDR, &result));
162     PFN_vkGetInstanceProcAddr get_instance_proc_addr =
163         reinterpret_cast<PFN_vkGetInstanceProcAddr>(result);
164     EXPECT_NE(get_instance_proc_addr, nullptr);
165 }
166 
TEST_P(VulkanImageTest,ExportVKImage)167 TEST_P(VulkanImageTest, ExportVKImage)
168 {
169     EGLWindow *window  = getEGLWindow();
170     EGLDisplay display = window->getDisplay();
171     ANGLE_SKIP_TEST_IF(!IsEGLDisplayExtensionEnabled(display, "EGL_ANGLE_vulkan_image"));
172 
173     GLTexture texture;
174     glBindTexture(GL_TEXTURE_2D, texture);
175     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kWidth, kHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
176     glBindTexture(GL_TEXTURE_2D, 0);
177     EXPECT_GL_NO_ERROR();
178 
179     EGLContext context   = window->getContext();
180     EGLImageKHR eglImage = eglCreateImageKHR(
181         display, context, EGL_GL_TEXTURE_2D_KHR,
182         reinterpret_cast<EGLClientBuffer>(static_cast<uintptr_t>(texture)), nullptr);
183     EXPECT_NE(eglImage, EGL_NO_IMAGE_KHR);
184 
185     VkImage vkImage        = VK_NULL_HANDLE;
186     VkImageCreateInfo info = {};
187     EXPECT_EGL_TRUE(eglExportVkImageANGLE(display, eglImage, &vkImage, &info));
188     EXPECT_NE(vkImage, static_cast<VkImage>(VK_NULL_HANDLE));
189     EXPECT_EQ(info.sType, VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO);
190     EXPECT_EQ(info.pNext, nullptr);
191     EXPECT_EQ(info.imageType, VK_IMAGE_TYPE_2D);
192     EXPECT_EQ(info.format, VK_FORMAT_R8G8B8A8_UNORM);
193     EXPECT_EQ(info.extent.width, kWidth);
194     EXPECT_EQ(info.extent.height, kHeight);
195     EXPECT_EQ(info.extent.depth, 1u);
196     EXPECT_EQ(info.queueFamilyIndexCount, 0u);
197     EXPECT_EQ(info.pQueueFamilyIndices, nullptr);
198     EXPECT_EQ(info.initialLayout, VK_IMAGE_LAYOUT_UNDEFINED);
199 
200     EXPECT_EGL_TRUE(eglDestroyImageKHR(display, eglImage));
201 }
202 
203 // Check pixels after glTexImage2D
TEST_P(VulkanImageTest,PixelTestTexImage2D)204 TEST_P(VulkanImageTest, PixelTestTexImage2D)
205 {
206     EGLWindow *window  = getEGLWindow();
207     EGLDisplay display = window->getDisplay();
208 
209     ANGLE_SKIP_TEST_IF(!IsEGLDisplayExtensionEnabled(display, "EGL_ANGLE_vulkan_image"));
210 
211     VulkanHelper helper;
212     helper.initializeFromANGLE();
213 
214     constexpr GLuint kColor = 0xafbfcfdf;
215 
216     GLTexture texture;
217 
218     {
219         glBindTexture(GL_TEXTURE_2D, texture);
220         std::vector<GLuint> pixels(kWidth * kHeight, kColor);
221         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kWidth, kHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE,
222                      pixels.data());
223         glBindTexture(GL_TEXTURE_2D, 0);
224     }
225 
226     EGLContext context   = window->getContext();
227     EGLImageKHR eglImage = eglCreateImageKHR(
228         display, context, EGL_GL_TEXTURE_2D_KHR,
229         reinterpret_cast<EGLClientBuffer>(static_cast<uintptr_t>(texture)), nullptr);
230     EXPECT_NE(eglImage, EGL_NO_IMAGE_KHR);
231 
232     VkImage vkImage        = VK_NULL_HANDLE;
233     VkImageCreateInfo info = {};
234     EXPECT_EGL_TRUE(eglExportVkImageANGLE(display, eglImage, &vkImage, &info));
235     EXPECT_NE(vkImage, static_cast<VkImage>(VK_NULL_HANDLE));
236 
237     GLuint textures[1] = {texture};
238     GLenum layouts[1]  = {GL_NONE};
239     glReleaseTexturesANGLE(1, textures, layouts);
240     EXPECT_EQ(layouts[0], static_cast<GLenum>(GL_LAYOUT_TRANSFER_DST_EXT));
241 
242     {
243         std::vector<GLuint> pixels(kWidth * kHeight);
244         helper.readPixels(vkImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, info.format, {},
245                           info.extent, pixels.data(), pixels.size() * sizeof(GLuint));
246         EXPECT_EQ(pixels, std::vector<GLuint>(kWidth * kHeight, kColor));
247     }
248 
249     layouts[0] = GL_LAYOUT_TRANSFER_SRC_EXT;
250     glAcquireTexturesANGLE(1, textures, layouts);
251 
252     EXPECT_GL_NO_ERROR();
253     EXPECT_EGL_TRUE(eglDestroyImageKHR(display, eglImage));
254 }
255 
256 // Check pixels after glClear
TEST_P(VulkanImageTest,PixelTestClear)257 TEST_P(VulkanImageTest, PixelTestClear)
258 {
259     EGLWindow *window  = getEGLWindow();
260     EGLDisplay display = window->getDisplay();
261 
262     ANGLE_SKIP_TEST_IF(!IsEGLDisplayExtensionEnabled(display, "EGL_ANGLE_vulkan_image"));
263 
264     VulkanHelper helper;
265     helper.initializeFromANGLE();
266 
267     GLTexture texture;
268     glBindTexture(GL_TEXTURE_2D, texture);
269     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kWidth, kHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
270     glBindTexture(GL_TEXTURE_2D, 0);
271 
272     EGLContext context   = window->getContext();
273     EGLImageKHR eglImage = eglCreateImageKHR(
274         display, context, EGL_GL_TEXTURE_2D_KHR,
275         reinterpret_cast<EGLClientBuffer>(static_cast<uintptr_t>(texture)), nullptr);
276     EXPECT_NE(eglImage, EGL_NO_IMAGE_KHR);
277 
278     VkImage vkImage        = VK_NULL_HANDLE;
279     VkImageCreateInfo info = {};
280     EXPECT_EGL_TRUE(eglExportVkImageANGLE(display, eglImage, &vkImage, &info));
281     EXPECT_NE(vkImage, static_cast<VkImage>(VK_NULL_HANDLE));
282 
283     GLFramebuffer framebuffer;
284     glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
285     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
286     EXPECT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
287 
288     glViewport(0, 0, kWidth, kHeight);
289     // clear framebuffer with white color.
290     glClearColor(1.f, 1.f, 1.f, 1.f);
291     glClear(GL_COLOR_BUFFER_BIT);
292 
293     GLuint textures[1] = {texture};
294     GLenum layouts[1]  = {GL_NONE};
295     glReleaseTexturesANGLE(1, textures, layouts);
296     EXPECT_EQ(layouts[0], static_cast<GLenum>(GL_LAYOUT_TRANSFER_DST_EXT));
297 
298     std::vector<GLuint> pixels(kWidth * kHeight);
299     helper.readPixels(vkImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, info.format, {}, info.extent,
300                       pixels.data(), pixels.size() * sizeof(GLuint));
301     EXPECT_EQ(pixels, std::vector<GLuint>(kWidth * kHeight, kWhite));
302 
303     layouts[0] = GL_LAYOUT_TRANSFER_SRC_EXT;
304     glAcquireTexturesANGLE(1, textures, layouts);
305 
306     // clear framebuffer with red color.
307     glClearColor(1.f, 0.f, 0.f, 1.f);
308     glClear(GL_COLOR_BUFFER_BIT);
309 
310     glReleaseTexturesANGLE(1, textures, layouts);
311     EXPECT_EQ(layouts[0], static_cast<GLenum>(GL_LAYOUT_TRANSFER_DST_EXT));
312 
313     helper.readPixels(vkImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, info.format, {}, info.extent,
314                       pixels.data(), pixels.size() * sizeof(GLuint));
315     EXPECT_EQ(pixels, std::vector<GLuint>(kWidth * kHeight, kRed));
316 
317     layouts[0] = GL_LAYOUT_TRANSFER_SRC_EXT;
318     glAcquireTexturesANGLE(1, textures, layouts);
319 
320     EXPECT_GL_NO_ERROR();
321     EXPECT_EGL_TRUE(eglDestroyImageKHR(display, eglImage));
322     glBindFramebuffer(GL_FRAMEBUFFER, 0);
323 }
324 
325 // Check pixels after GL draw.
TEST_P(VulkanImageTest,PixelTestDrawQuad)326 TEST_P(VulkanImageTest, PixelTestDrawQuad)
327 {
328     EGLWindow *window  = getEGLWindow();
329     EGLDisplay display = window->getDisplay();
330 
331     ANGLE_SKIP_TEST_IF(!IsEGLDisplayExtensionEnabled(display, "EGL_ANGLE_vulkan_image"));
332 
333     VulkanHelper helper;
334     helper.initializeFromANGLE();
335 
336     GLTexture texture;
337     glBindTexture(GL_TEXTURE_2D, texture);
338     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kWidth, kHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
339     glBindTexture(GL_TEXTURE_2D, 0);
340 
341     EGLContext context   = window->getContext();
342     EGLImageKHR eglImage = eglCreateImageKHR(
343         display, context, EGL_GL_TEXTURE_2D_KHR,
344         reinterpret_cast<EGLClientBuffer>(static_cast<uintptr_t>(texture)), nullptr);
345     EXPECT_NE(eglImage, EGL_NO_IMAGE_KHR);
346 
347     GLFramebuffer framebuffer;
348     glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
349     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
350     EXPECT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
351 
352     glViewport(0, 0, kWidth, kHeight);
353     // clear framebuffer with black color.
354     glClearColor(0.f, 0.f, 0.f, 0.f);
355     glClear(GL_COLOR_BUFFER_BIT);
356 
357     // draw red quad
358     ANGLE_GL_PROGRAM(drawRed, essl1_shaders::vs::Simple(), essl1_shaders::fs::Red());
359     drawQuad(drawRed, essl1_shaders::PositionAttrib(), 0.5f);
360 
361     GLuint textures[1] = {texture};
362     GLenum layouts[1]  = {GL_NONE};
363     glReleaseTexturesANGLE(1, textures, layouts);
364     EXPECT_EQ(layouts[0], static_cast<GLenum>(GL_LAYOUT_COLOR_ATTACHMENT_EXT));
365 
366     VkImage vkImage        = VK_NULL_HANDLE;
367     VkImageCreateInfo info = {};
368     EXPECT_EGL_TRUE(eglExportVkImageANGLE(display, eglImage, &vkImage, &info));
369     EXPECT_NE(vkImage, static_cast<VkImage>(VK_NULL_HANDLE));
370 
371     std::vector<GLuint> pixels(kWidth * kHeight);
372     helper.readPixels(vkImage, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, info.format, {},
373                       info.extent, pixels.data(), pixels.size() * sizeof(GLuint));
374     EXPECT_EQ(pixels, std::vector<GLuint>(kWidth * kHeight, kRed));
375 
376     layouts[0] = GL_LAYOUT_TRANSFER_SRC_EXT;
377     glAcquireTexturesANGLE(1, textures, layouts);
378 
379     EXPECT_GL_NO_ERROR();
380     EXPECT_EGL_TRUE(eglDestroyImageKHR(display, eglImage));
381     glBindFramebuffer(GL_FRAMEBUFFER, 0);
382 }
383 
384 // Test importing VkImage with eglCreateImageKHR
TEST_P(VulkanImageTest,ClientBuffer)385 TEST_P(VulkanImageTest, ClientBuffer)
386 {
387     EGLWindow *window  = getEGLWindow();
388     EGLDisplay display = window->getDisplay();
389 
390     ANGLE_SKIP_TEST_IF(!IsEGLDisplayExtensionEnabled(display, "EGL_ANGLE_vulkan_image"));
391 
392     VulkanHelper helper;
393     helper.initializeFromANGLE();
394 
395     constexpr VkImageUsageFlags kDefaultImageUsageFlags =
396         VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT |
397         VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT |
398         VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
399 
400     VkImage vkImage                   = VK_NULL_HANDLE;
401     VkDeviceMemory vkDeviceMemory     = VK_NULL_HANDLE;
402     VkDeviceSize deviceSize           = 0u;
403     VkImageCreateInfo imageCreateInfo = {};
404 
405     VkResult result = VK_SUCCESS;
406     result          = helper.createImage2D(VK_FORMAT_R8G8B8A8_UNORM, 0, kDefaultImageUsageFlags,
407                                            {kWidth, kHeight, 1}, &vkImage, &vkDeviceMemory, &deviceSize,
408                                            &imageCreateInfo);
409     EXPECT_EQ(result, VK_SUCCESS);
410     EXPECT_EQ(imageCreateInfo.sType, VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO);
411 
412     uint64_t info    = reinterpret_cast<uint64_t>(&imageCreateInfo);
413     EGLint attribs[] = {
414         EGL_VULKAN_IMAGE_CREATE_INFO_HI_ANGLE,
415         static_cast<EGLint>((info >> 32) & 0xffffffff),
416         EGL_VULKAN_IMAGE_CREATE_INFO_LO_ANGLE,
417         static_cast<EGLint>(info & 0xffffffff),
418         EGL_NONE,
419     };
420     EGLImageKHR eglImage = eglCreateImageKHR(display, EGL_NO_CONTEXT, EGL_VULKAN_IMAGE_ANGLE,
421                                              reinterpret_cast<EGLClientBuffer>(&vkImage), attribs);
422     EXPECT_NE(eglImage, EGL_NO_IMAGE_KHR);
423 
424     GLTexture texture;
425     glBindTexture(GL_TEXTURE_2D, texture);
426     glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, eglImage);
427 
428     GLuint textures[1] = {texture};
429     GLenum layouts[1]  = {GL_NONE};
430     glAcquireTexturesANGLE(1, textures, layouts);
431 
432     GLFramebuffer framebuffer;
433     glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
434     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
435     EXPECT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
436 
437     glViewport(0, 0, kWidth, kHeight);
438     // clear framebuffer with white color.
439     glClearColor(1.f, 1.f, 1.f, 1.f);
440     glClear(GL_COLOR_BUFFER_BIT);
441 
442     textures[0] = texture;
443     layouts[0]  = GL_NONE;
444     glReleaseTexturesANGLE(1, textures, layouts);
445     EXPECT_EQ(layouts[0], static_cast<GLenum>(GL_LAYOUT_TRANSFER_DST_EXT));
446 
447     std::vector<GLuint> pixels(kWidth * kHeight);
448     helper.readPixels(vkImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, imageCreateInfo.format, {},
449                       imageCreateInfo.extent, pixels.data(), pixels.size() * sizeof(GLuint));
450     EXPECT_EQ(pixels, std::vector<GLuint>(kWidth * kHeight, kWhite));
451 
452     layouts[0] = GL_LAYOUT_TRANSFER_SRC_EXT;
453     glAcquireTexturesANGLE(1, textures, layouts);
454 
455     // clear framebuffer with red color.
456     glClearColor(1.f, 0.f, 0.f, 1.f);
457     glClear(GL_COLOR_BUFFER_BIT);
458 
459     glReleaseTexturesANGLE(1, textures, layouts);
460     EXPECT_EQ(layouts[0], static_cast<GLenum>(GL_LAYOUT_TRANSFER_DST_EXT));
461 
462     helper.readPixels(vkImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, imageCreateInfo.format, {},
463                       imageCreateInfo.extent, pixels.data(), pixels.size() * sizeof(GLuint));
464     EXPECT_EQ(pixels, std::vector<GLuint>(kWidth * kHeight, kRed));
465 
466     EXPECT_GL_NO_ERROR();
467     glBindFramebuffer(GL_FRAMEBUFFER, 0);
468     framebuffer.reset();
469     texture.reset();
470 
471     glFinish();
472 
473     EXPECT_EGL_TRUE(eglDestroyImageKHR(display, eglImage));
474     vkDestroyImage(helper.getDevice(), vkImage, nullptr);
475     vkFreeMemory(helper.getDevice(), vkDeviceMemory, nullptr);
476 }
477 
478 // Test importing VkImage with eglCreateImageKHR and drawing to make sure no errors occur in setting
479 // up the framebuffer, including an imageless framebuffer.
TEST_P(VulkanImageTest,ClientBufferWithDraw)480 TEST_P(VulkanImageTest, ClientBufferWithDraw)
481 {
482     EGLWindow *window  = getEGLWindow();
483     EGLDisplay display = window->getDisplay();
484 
485     ANGLE_SKIP_TEST_IF(!IsEGLDisplayExtensionEnabled(display, "EGL_ANGLE_vulkan_image"));
486 
487     VulkanHelper helper;
488     helper.initializeFromANGLE();
489 
490     constexpr VkImageUsageFlags kDefaultImageUsageFlags =
491         VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT |
492         VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT |
493         VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
494 
495     VkImage vkImage                   = VK_NULL_HANDLE;
496     VkDeviceMemory vkDeviceMemory     = VK_NULL_HANDLE;
497     VkDeviceSize deviceSize           = 0u;
498     VkImageCreateInfo imageCreateInfo = {};
499 
500     VkResult result = VK_SUCCESS;
501     result          = helper.createImage2D(VK_FORMAT_R8G8B8A8_UNORM, 0, kDefaultImageUsageFlags,
502                                            {kWidth, kHeight, 1}, &vkImage, &vkDeviceMemory, &deviceSize,
503                                            &imageCreateInfo);
504     EXPECT_EQ(result, VK_SUCCESS);
505     EXPECT_EQ(imageCreateInfo.sType, VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO);
506 
507     uint64_t info    = reinterpret_cast<uint64_t>(&imageCreateInfo);
508     EGLint attribs[] = {
509         EGL_VULKAN_IMAGE_CREATE_INFO_HI_ANGLE,
510         static_cast<EGLint>((info >> 32) & 0xffffffff),
511         EGL_VULKAN_IMAGE_CREATE_INFO_LO_ANGLE,
512         static_cast<EGLint>(info & 0xffffffff),
513         EGL_NONE,
514     };
515     EGLImageKHR eglImage = eglCreateImageKHR(display, EGL_NO_CONTEXT, EGL_VULKAN_IMAGE_ANGLE,
516                                              reinterpret_cast<EGLClientBuffer>(&vkImage), attribs);
517     EXPECT_NE(eglImage, EGL_NO_IMAGE_KHR);
518 
519     GLTexture texture;
520     glBindTexture(GL_TEXTURE_2D, texture);
521     glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, eglImage);
522 
523     GLuint textures[1] = {texture};
524     GLenum layouts[1]  = {GL_NONE};
525     glAcquireTexturesANGLE(1, textures, layouts);
526 
527     GLFramebuffer framebuffer;
528     glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
529     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
530     EXPECT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
531 
532     ANGLE_GL_PROGRAM(drawGreen, essl1_shaders::vs::Simple(), essl1_shaders::fs::Green());
533     drawQuad(drawGreen, essl1_shaders::PositionAttrib(), 0.5f);
534 
535     EXPECT_GL_NO_ERROR();
536     glBindFramebuffer(GL_FRAMEBUFFER, 0);
537     framebuffer.reset();
538     texture.reset();
539 
540     glFinish();
541 
542     EXPECT_EGL_TRUE(eglDestroyImageKHR(display, eglImage));
543     vkDestroyImage(helper.getDevice(), vkImage, nullptr);
544     vkFreeMemory(helper.getDevice(), vkDeviceMemory, nullptr);
545 }
546 
547 // Test that when VMA image suballocation is used, image memory can be allocated from the system in
548 // case the device memory runs out.
TEST_P(VulkanMemoryTest,AllocateVMAImageWhenDeviceOOM)549 TEST_P(VulkanMemoryTest, AllocateVMAImageWhenDeviceOOM)
550 {
551     ANGLE_SKIP_TEST_IF(!getEGLWindow()->isFeatureEnabled(Feature::UseVmaForImageSuballocation));
552 
553     GLPerfMonitor monitor;
554     glBeginPerfMonitorAMD(monitor);
555 
556     VulkanHelper helper;
557     helper.initializeFromANGLE();
558     uint64_t expectedAllocationFallbacks =
559         getPerfCounters().deviceMemoryImageAllocationFallbacks + 1;
560     uint64_t expectedAllocationFallbacksAfterLastTexture =
561         getPerfCounters().deviceMemoryImageAllocationFallbacks + 2;
562 
563     VkDeviceSize totalDeviceLocalMemoryHeapSize = 0;
564     ANGLE_SKIP_TEST_IF(!compatibleMemorySizesForDeviceOOMTest(helper.getPhysicalDevice(),
565                                                               &totalDeviceLocalMemoryHeapSize));
566 
567     // Device memory is the first choice for image memory allocation. However, in case it runs out,
568     // memory should be allocated from the system if available. Therefore, we want to make sure that
569     // we can still allocate image memory even if the device memory is full.
570     constexpr VkDeviceSize kTextureWidth  = 2048;
571     constexpr VkDeviceSize kTextureHeight = 2048;
572     constexpr VkDeviceSize kTextureSize   = kTextureWidth * kTextureHeight * 4;
573     VkDeviceSize textureCount             = (totalDeviceLocalMemoryHeapSize / kTextureSize) + 1;
574 
575     std::vector<GLTexture> textures;
576     textures.resize(textureCount);
577     for (uint32_t i = 0; i < textureCount; i++)
578     {
579         glBindTexture(GL_TEXTURE_2D, textures[i]);
580         glTexStorage2DEXT(GL_TEXTURE_2D, 1, GL_RGBA8, kTextureWidth, kTextureHeight);
581         glDrawArrays(GL_POINTS, 0, 1);
582         EXPECT_GL_NO_ERROR();
583 
584         // This process only needs to continue until the allocation is no longer on the device.
585         if (getPerfCounters().deviceMemoryImageAllocationFallbacks == expectedAllocationFallbacks)
586         {
587             break;
588         }
589     }
590     EXPECT_EQ(getPerfCounters().deviceMemoryImageAllocationFallbacks, expectedAllocationFallbacks);
591 
592     // Verify that the texture allocated on the system memory can attach to a framebuffer correctly.
593     GLTexture texture;
594     std::vector<GLColor> textureColor(kTextureWidth * kTextureHeight, GLColor::magenta);
595     glBindTexture(GL_TEXTURE_2D, texture);
596     glTexStorage2DEXT(GL_TEXTURE_2D, 1, GL_RGBA8, kTextureWidth, kTextureHeight);
597     glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kTextureWidth, kTextureHeight, GL_RGBA,
598                     GL_UNSIGNED_BYTE, textureColor.data());
599     EXPECT_EQ(getPerfCounters().deviceMemoryImageAllocationFallbacks,
600               expectedAllocationFallbacksAfterLastTexture);
601 
602     glEndPerfMonitorAMD(monitor);
603 
604     GLFramebuffer fbo;
605     glBindFramebuffer(GL_FRAMEBUFFER, fbo);
606     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
607     EXPECT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
608     EXPECT_PIXEL_RECT_EQ(0, 0, kWidth, kHeight, GLColor::magenta);
609 }
610 
611 // Test that when VMA image suballocation is used, it is possible to free space for a new image on
612 // the device by freeing garbage memory from a 2D texture array.
TEST_P(VulkanMemoryTest,AllocateVMAImageAfterFreeing2DArrayGarbageWhenDeviceOOM)613 TEST_P(VulkanMemoryTest, AllocateVMAImageAfterFreeing2DArrayGarbageWhenDeviceOOM)
614 {
615     ANGLE_SKIP_TEST_IF(!getEGLWindow()->isFeatureEnabled(Feature::UseVmaForImageSuballocation));
616 
617     GLPerfMonitor monitor;
618     glBeginPerfMonitorAMD(monitor);
619 
620     VulkanHelper helper;
621     helper.initializeFromANGLE();
622     uint64_t expectedAllocationFallbacks =
623         getPerfCounters().deviceMemoryImageAllocationFallbacks + 1;
624 
625     VkPhysicalDeviceMemoryProperties memoryProperties;
626     vkGetPhysicalDeviceMemoryProperties(helper.getPhysicalDevice(), &memoryProperties);
627 
628     VkDeviceSize totalDeviceLocalMemoryHeapSize = 0;
629     ANGLE_SKIP_TEST_IF(!compatibleMemorySizesForDeviceOOMTest(helper.getPhysicalDevice(),
630                                                               &totalDeviceLocalMemoryHeapSize));
631 
632     // Use a 2D texture array to allocate some of the available device memory and draw with it.
633     GLuint texture2DArray;
634     constexpr VkDeviceSize kTextureWidth  = 512;
635     constexpr VkDeviceSize kTextureHeight = 512;
636     VkDeviceSize texture2DArrayLayerCount = 10;
637     glGenTextures(1, &texture2DArray);
638 
639     glBindTexture(GL_TEXTURE_2D_ARRAY, texture2DArray);
640     glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA, kTextureWidth, kTextureHeight,
641                  static_cast<GLsizei>(texture2DArrayLayerCount), 0, GL_RGBA, GL_UNSIGNED_BYTE,
642                  nullptr);
643     glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
644     glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
645     glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
646     glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
647 
648     for (size_t i = 0; i < texture2DArrayLayerCount; i++)
649     {
650         std::vector<GLColor> textureColor(kTextureWidth * kTextureHeight, GLColor::green);
651         glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, static_cast<GLint>(i), kTextureWidth,
652                         kTextureHeight, 1, GL_RGBA, GL_UNSIGNED_BYTE, textureColor.data());
653     }
654 
655     ANGLE_GL_PROGRAM(drawTex2DArray, essl1_shaders::vs::Texture2DArray(),
656                      essl1_shaders::fs::Texture2DArray());
657     drawQuad(drawTex2DArray, essl1_shaders::PositionAttrib(), 0.5f);
658 
659     // Fill up the device memory until we start allocating on the system memory.
660     // Device memory is the first choice for image memory allocation. However, in case it runs out,
661     // memory should be allocated from the system if available.
662     std::vector<GLTexture> textures2D;
663     constexpr VkDeviceSize kTextureSize = kTextureWidth * kTextureHeight * 4;
664     VkDeviceSize texture2DCount         = (totalDeviceLocalMemoryHeapSize / kTextureSize) + 1;
665     textures2D.resize(texture2DCount);
666 
667     for (uint32_t i = 0; i < texture2DCount; i++)
668     {
669         glBindTexture(GL_TEXTURE_2D, textures2D[i]);
670         glTexStorage2DEXT(GL_TEXTURE_2D, 1, GL_RGBA8, kTextureWidth, kTextureHeight);
671         EXPECT_GL_NO_ERROR();
672 
673         // This process only needs to continue until the allocation is no longer on the device.
674         if (getPerfCounters().deviceMemoryImageAllocationFallbacks == expectedAllocationFallbacks)
675         {
676             break;
677         }
678     }
679     EXPECT_EQ(getPerfCounters().deviceMemoryImageAllocationFallbacks, expectedAllocationFallbacks);
680 
681     // Wait until GPU finishes execution.
682     GLsync sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
683     glWaitSync(sync, 0, GL_TIMEOUT_IGNORED);
684     EXPECT_GL_NO_ERROR();
685 
686     // Delete the 2D array texture. This frees the memory due to context flushing from the memory
687     // allocation fallbacks.
688     glDeleteTextures(1, &texture2DArray);
689 
690     // The next texture should be allocated on the device, which will only be possible after freeing
691     // the garbage.
692     GLTexture lastTexture;
693     std::vector<GLColor> lastTextureColor(kTextureWidth * kTextureHeight, GLColor::blue);
694     glBindTexture(GL_TEXTURE_2D, lastTexture);
695     glTexStorage2DEXT(GL_TEXTURE_2D, 1, GL_RGBA8, kTextureWidth, kTextureHeight);
696     glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kTextureWidth, kTextureHeight, GL_RGBA,
697                     GL_UNSIGNED_BYTE, lastTextureColor.data());
698     EXPECT_EQ(getPerfCounters().deviceMemoryImageAllocationFallbacks, expectedAllocationFallbacks);
699 
700     glEndPerfMonitorAMD(monitor);
701 
702     GLFramebuffer fbo;
703     glBindFramebuffer(GL_FRAMEBUFFER, fbo);
704     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, lastTexture, 0);
705     EXPECT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
706     EXPECT_PIXEL_RECT_EQ(0, 0, kWidth, kHeight, GLColor::blue);
707 }
708 
709 // Test that when VMA image suballocation is used, it is possible to free space for a new image on
710 // the device by freeing finished garbage memory from a 2D texture.
TEST_P(VulkanMemoryTest,AllocateVMAImageAfterFreeingFinished2DGarbageWhenDeviceOOM)711 TEST_P(VulkanMemoryTest, AllocateVMAImageAfterFreeingFinished2DGarbageWhenDeviceOOM)
712 {
713     ANGLE_SKIP_TEST_IF(!getEGLWindow()->isFeatureEnabled(Feature::UseVmaForImageSuballocation));
714 
715     GLPerfMonitor monitor;
716     glBeginPerfMonitorAMD(monitor);
717 
718     VulkanHelper helper;
719     helper.initializeFromANGLE();
720     uint64_t expectedAllocationFallbacks =
721         getPerfCounters().deviceMemoryImageAllocationFallbacks + 1;
722 
723     VkDeviceSize totalDeviceLocalMemoryHeapSize = 0;
724     ANGLE_SKIP_TEST_IF(!compatibleMemorySizesForDeviceOOMTest(helper.getPhysicalDevice(),
725                                                               &totalDeviceLocalMemoryHeapSize));
726 
727     // Use a large 2D texture to allocate some of the available device memory and draw with it.
728     GLuint largeTexture;
729     constexpr VkDeviceSize kLargeTextureWidth  = 2048;
730     constexpr VkDeviceSize kLargeTextureHeight = 2048;
731     std::vector<GLColor> firstTextureColor(kLargeTextureWidth * kLargeTextureHeight,
732                                            GLColor::green);
733     glGenTextures(1, &largeTexture);
734     glBindTexture(GL_TEXTURE_2D, largeTexture);
735     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kLargeTextureWidth, kLargeTextureHeight, 0, GL_RGBA,
736                  GL_UNSIGNED_BYTE, nullptr);
737     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
738     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
739     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
740     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
741     glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kLargeTextureWidth, kLargeTextureHeight, GL_RGBA,
742                     GL_UNSIGNED_BYTE, firstTextureColor.data());
743 
744     ANGLE_GL_PROGRAM(drawTex2D, essl1_shaders::vs::Texture2D(), essl1_shaders::fs::Texture2D());
745     drawQuad(drawTex2D, essl1_shaders::PositionAttrib(), 0.5f);
746 
747     // Fill up the device memory until we start allocating on the system memory.
748     // Device memory is the first choice for image memory allocation. However, in case it runs out,
749     // memory should be allocated from the system if available.
750     std::vector<GLTexture> textures2D;
751     constexpr VkDeviceSize kTextureWidth  = 512;
752     constexpr VkDeviceSize kTextureHeight = 512;
753     constexpr VkDeviceSize kTextureSize   = kTextureWidth * kTextureHeight * 4;
754     VkDeviceSize texture2DCount           = (totalDeviceLocalMemoryHeapSize / kTextureSize) + 1;
755     textures2D.resize(texture2DCount);
756 
757     for (uint32_t i = 0; i < texture2DCount; i++)
758     {
759         glBindTexture(GL_TEXTURE_2D, textures2D[i]);
760         glTexStorage2DEXT(GL_TEXTURE_2D, 1, GL_RGBA8, kTextureWidth, kTextureHeight);
761         EXPECT_GL_NO_ERROR();
762 
763         // This process only needs to continue until the allocation is no longer on the device.
764         if (getPerfCounters().deviceMemoryImageAllocationFallbacks == expectedAllocationFallbacks)
765         {
766             break;
767         }
768     }
769     EXPECT_EQ(getPerfCounters().deviceMemoryImageAllocationFallbacks, expectedAllocationFallbacks);
770 
771     // Wait until GPU finishes execution.
772     GLsync syncOne = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
773     glWaitSync(syncOne, 0, GL_TIMEOUT_IGNORED);
774     EXPECT_GL_NO_ERROR();
775 
776     // Delete the large 2D texture. It should free the memory due to context flushing performed
777     // during memory allocation fallbacks. Then we allocate and draw with this texture again.
778     glDeleteTextures(1, &largeTexture);
779 
780     glBindTexture(GL_TEXTURE_2D, largeTexture);
781     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kLargeTextureWidth, kLargeTextureHeight, 0, GL_RGBA,
782                  GL_UNSIGNED_BYTE, nullptr);
783     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
784     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
785     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
786     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
787     glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kLargeTextureWidth, kLargeTextureHeight, GL_RGBA,
788                     GL_UNSIGNED_BYTE, firstTextureColor.data());
789 
790     drawQuad(drawTex2D, essl1_shaders::PositionAttrib(), 0.5f);
791 
792     // Wait until GPU finishes execution one more time.
793     GLsync syncTwo = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
794     glWaitSync(syncTwo, 0, GL_TIMEOUT_IGNORED);
795     EXPECT_GL_NO_ERROR();
796 
797     // Delete the large 2D texture. Even though it is marked as deallocated, the device memory is
798     // not freed from the garbage yet.
799     glDeleteTextures(1, &largeTexture);
800 
801     // The next texture should be allocated on the device, which will only be possible after freeing
802     // the garbage from the finished commands. There should be no context flushing.
803     uint64_t expectedSubmitCalls = getPerfCounters().commandQueueSubmitCallsTotal;
804     GLTexture lastTexture;
805     std::vector<GLColor> textureColor(kLargeTextureWidth * kLargeTextureWidth, GLColor::red);
806     glBindTexture(GL_TEXTURE_2D, lastTexture);
807     glTexStorage2DEXT(GL_TEXTURE_2D, 1, GL_RGBA8, kLargeTextureWidth, kLargeTextureWidth);
808     glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kLargeTextureWidth, kLargeTextureWidth, GL_RGBA,
809                     GL_UNSIGNED_BYTE, textureColor.data());
810     EXPECT_EQ(getPerfCounters().deviceMemoryImageAllocationFallbacks, expectedAllocationFallbacks);
811     EXPECT_EQ(getPerfCounters().commandQueueSubmitCallsTotal, expectedSubmitCalls);
812 
813     glEndPerfMonitorAMD(monitor);
814 
815     GLFramebuffer fbo;
816     glBindFramebuffer(GL_FRAMEBUFFER, fbo);
817     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, lastTexture, 0);
818     EXPECT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
819     EXPECT_PIXEL_RECT_EQ(0, 0, kWidth, kHeight, GLColor::red);
820 }
821 
822 // Test that when VMA image suballocation is used, it is possible to free space for a new buffer on
823 // the device by freeing garbage memory from a 2D texture.
TEST_P(VulkanMemoryTest,AllocateBufferAfterFreeing2DGarbageWhenDeviceOOM)824 TEST_P(VulkanMemoryTest, AllocateBufferAfterFreeing2DGarbageWhenDeviceOOM)
825 {
826     ANGLE_SKIP_TEST_IF(!getEGLWindow()->isFeatureEnabled(Feature::UseVmaForImageSuballocation));
827 
828     GLPerfMonitor monitor;
829     glBeginPerfMonitorAMD(monitor);
830 
831     VulkanHelper helper;
832     helper.initializeFromANGLE();
833     uint64_t expectedAllocationFallbacks =
834         getPerfCounters().deviceMemoryImageAllocationFallbacks + 1;
835 
836     VkDeviceSize totalDeviceLocalMemoryHeapSize = 0;
837     ANGLE_SKIP_TEST_IF(!compatibleMemorySizesForDeviceOOMTest(helper.getPhysicalDevice(),
838                                                               &totalDeviceLocalMemoryHeapSize));
839 
840     // Use a large 2D texture to allocate some of the available device memory and draw with it.
841     GLuint firstTexture;
842     constexpr VkDeviceSize kFirstTextureWidth  = 2048;
843     constexpr VkDeviceSize kFirstTextureHeight = 2048;
844     glGenTextures(1, &firstTexture);
845 
846     glBindTexture(GL_TEXTURE_2D, firstTexture);
847     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kFirstTextureWidth, kFirstTextureHeight, 0, GL_RGBA,
848                  GL_UNSIGNED_BYTE, nullptr);
849     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
850     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
851     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
852     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
853 
854     {
855         std::vector<GLColor> firstTextureColor(kFirstTextureWidth * kFirstTextureHeight,
856                                                GLColor::green);
857         glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kFirstTextureWidth, kFirstTextureHeight, GL_RGBA,
858                         GL_UNSIGNED_BYTE, firstTextureColor.data());
859     }
860 
861     ANGLE_GL_PROGRAM(drawTex2D, essl1_shaders::vs::Texture2D(), essl1_shaders::fs::Texture2D());
862     drawQuad(drawTex2D, essl1_shaders::PositionAttrib(), 0.5f);
863 
864     // Fill up the device memory until we start allocating on the system memory.
865     // Device memory is the first choice for image memory allocation. However, in case it runs out,
866     // memory should be allocated from the system if available.
867     std::vector<GLTexture> textures2D;
868     constexpr VkDeviceSize kTextureWidth  = 512;
869     constexpr VkDeviceSize kTextureHeight = 512;
870     constexpr VkDeviceSize kTextureSize   = kTextureWidth * kTextureHeight * 4;
871     VkDeviceSize texture2DCount           = (totalDeviceLocalMemoryHeapSize / kTextureSize) + 1;
872     textures2D.resize(texture2DCount);
873 
874     for (uint32_t i = 0; i < texture2DCount; i++)
875     {
876         glBindTexture(GL_TEXTURE_2D, textures2D[i]);
877         glTexStorage2DEXT(GL_TEXTURE_2D, 1, GL_RGBA8, kTextureWidth, kTextureHeight);
878         EXPECT_GL_NO_ERROR();
879 
880         // This process only needs to continue until the allocation is no longer on the device.
881         if (getPerfCounters().deviceMemoryImageAllocationFallbacks == expectedAllocationFallbacks)
882         {
883             break;
884         }
885     }
886     EXPECT_EQ(getPerfCounters().deviceMemoryImageAllocationFallbacks, expectedAllocationFallbacks);
887 
888     glEndPerfMonitorAMD(monitor);
889 
890     // Wait until GPU finishes execution.
891     GLsync sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
892     glWaitSync(sync, 0, GL_TIMEOUT_IGNORED);
893     EXPECT_GL_NO_ERROR();
894 
895     // Delete the 2D array texture. This frees the memory due to context flushing from the memory
896     // allocation fallbacks.
897     glDeleteTextures(1, &firstTexture);
898 
899     // The buffer should be allocated on the device, which will only be possible after freeing the
900     // garbage.
901     GLBuffer lastBuffer;
902     constexpr VkDeviceSize kBufferSize = kTextureWidth * kTextureHeight * 4;
903     std::vector<uint8_t> bufferData(kBufferSize, 255);
904     glBindBuffer(GL_ARRAY_BUFFER, lastBuffer);
905     glBufferData(GL_ARRAY_BUFFER, kBufferSize, bufferData.data(), GL_STATIC_DRAW);
906     EXPECT_GL_NO_ERROR();
907 }
908 
909 // Use this to select which configurations (e.g. which renderer, which GLES major version) these
910 // tests should be run against.
911 ANGLE_INSTANTIATE_TEST_ES2_AND_ES3(VulkanImageTest);
912 ANGLE_INSTANTIATE_TEST_ES3(VulkanMemoryTest);
913 
914 }  // namespace angle
915