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