• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2011 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <android/log.h>
18 #include <driver.h>
19 #include <gmock/gmock.h>
20 #include <gtest/gtest.h>
21 #include <media/NdkImageReader.h>
22 #include <vulkan/vulkan.h>
23 
24 #define LOGI(...) \
25     __android_log_print(ANDROID_LOG_INFO, "libvulkan_test", __VA_ARGS__)
26 #define LOGE(...) \
27     __android_log_print(ANDROID_LOG_ERROR, "libvulkan_test", __VA_ARGS__)
28 
29 #define VK_CHECK(result) ASSERT_EQ(VK_SUCCESS, result)
30 
31 namespace android {
32 
33 namespace libvulkantest {
34 
35 class AImageReaderVulkanSwapchainTest : public ::testing::Test {
36    public:
AImageReaderVulkanSwapchainTest()37     AImageReaderVulkanSwapchainTest() {}
38 
39     AImageReader* mReader = nullptr;
40     ANativeWindow* mWindow = nullptr;
41     VkInstance mVkInstance = VK_NULL_HANDLE;
42     VkPhysicalDevice mPhysicalDev = VK_NULL_HANDLE;
43     VkDevice mDevice = VK_NULL_HANDLE;
44     VkSurfaceKHR mSurface = VK_NULL_HANDLE;
45     VkQueue mPresentQueue = VK_NULL_HANDLE;
46     uint32_t mPresentQueueFamily = UINT32_MAX;
47     VkSwapchainKHR mSwapchain = VK_NULL_HANDLE;
48 
SetUp()49     void SetUp() override {}
50 
TearDown()51     void TearDown() override {}
52 
53     // ------------------------------------------------------
54     // Helper methods
55     // ------------------------------------------------------
56 
createVulkanInstance(std::vector<const char * > & layers)57     void createVulkanInstance(std::vector<const char*>& layers) {
58         const char* extensions[] = {
59             VK_KHR_SURFACE_EXTENSION_NAME,
60             VK_KHR_ANDROID_SURFACE_EXTENSION_NAME,
61             VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME,
62             VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME,
63         };
64 
65         VkApplicationInfo appInfo{};
66         appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
67         appInfo.pApplicationName = "AImageReader Vulkan Swapchain Test";
68         appInfo.applicationVersion = 1;
69         appInfo.pEngineName = "TestEngine";
70         appInfo.engineVersion = 1;
71         appInfo.apiVersion = VK_API_VERSION_1_0;
72 
73         VkInstanceCreateInfo instInfo{};
74         instInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
75         instInfo.pApplicationInfo = &appInfo;
76         instInfo.enabledExtensionCount =
77             sizeof(extensions) / sizeof(extensions[0]);
78         instInfo.ppEnabledExtensionNames = extensions;
79         instInfo.enabledLayerCount = layers.size();
80         instInfo.ppEnabledLayerNames = layers.data();
81         VkResult res = vkCreateInstance(&instInfo, nullptr, &mVkInstance);
82         VK_CHECK(res);
83         LOGE("Vulkan instance created");
84     }
85 
createAImageReader(int width,int height,int format,int maxImages)86     void createAImageReader(int width, int height, int format, int maxImages) {
87         media_status_t status =
88             AImageReader_new(width, height, format, maxImages, &mReader);
89         ASSERT_EQ(AMEDIA_OK, status) << "Failed to create AImageReader";
90         ASSERT_NE(nullptr, mReader) << "AImageReader is null";
91 
92         // Optionally set a listener
93         AImageReader_ImageListener listener{};
94         listener.context = this;
95         listener.onImageAvailable =
96             &AImageReaderVulkanSwapchainTest::onImageAvailable;
97         AImageReader_setImageListener(mReader, &listener);
98 
99         LOGI("AImageReader created with %dx%d, format=%d", width, height,
100              format);
101     }
102 
getANativeWindowFromReader()103     void getANativeWindowFromReader() {
104         ASSERT_NE(nullptr, mReader);
105 
106         media_status_t status = AImageReader_getWindow(mReader, &mWindow);
107         ASSERT_EQ(AMEDIA_OK, status)
108             << "Failed to get ANativeWindow from AImageReader";
109         ASSERT_NE(nullptr, mWindow) << "ANativeWindow is null";
110         LOGI("ANativeWindow obtained from AImageReader");
111     }
112 
createVulkanSurface()113     void createVulkanSurface() {
114         ASSERT_NE((VkInstance)VK_NULL_HANDLE, mVkInstance);
115         ASSERT_NE((ANativeWindow*)nullptr, mWindow);
116 
117         VkAndroidSurfaceCreateInfoKHR surfaceCreateInfo{};
118         surfaceCreateInfo.sType =
119             VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR;
120         surfaceCreateInfo.window = mWindow;
121 
122         VkResult res = vkCreateAndroidSurfaceKHR(
123             mVkInstance, &surfaceCreateInfo, nullptr, &mSurface);
124         VK_CHECK(res);
125         LOGI("Vulkan surface created from ANativeWindow");
126     }
127 
pickPhysicalDeviceAndQueueFamily()128     void pickPhysicalDeviceAndQueueFamily() {
129         ASSERT_NE((VkInstance)VK_NULL_HANDLE, mVkInstance);
130 
131         uint32_t deviceCount = 0;
132         vkEnumeratePhysicalDevices(mVkInstance, &deviceCount, nullptr);
133         ASSERT_GT(deviceCount, 0U) << "No Vulkan physical devices found!";
134 
135         std::vector<VkPhysicalDevice> devices(deviceCount);
136         vkEnumeratePhysicalDevices(mVkInstance, &deviceCount, devices.data());
137 
138         for (auto& dev : devices) {
139             uint32_t queueFamilyCount = 0;
140             vkGetPhysicalDeviceQueueFamilyProperties(dev, &queueFamilyCount,
141                                                      nullptr);
142             std::vector<VkQueueFamilyProperties> queueProps(queueFamilyCount);
143             vkGetPhysicalDeviceQueueFamilyProperties(dev, &queueFamilyCount,
144                                                      queueProps.data());
145 
146             for (uint32_t i = 0; i < queueFamilyCount; i++) {
147                 VkBool32 support = VK_FALSE;
148                 vkGetPhysicalDeviceSurfaceSupportKHR(dev, i, mSurface,
149                                                      &support);
150                 if (support == VK_TRUE) {
151                     // Found a queue family that can present
152                     mPhysicalDev = dev;
153                     mPresentQueueFamily = i;
154 
155                     LOGI(
156                         "Physical device found with queue family %u supporting "
157                         "present",
158                         i);
159                     return;
160                 }
161             }
162         }
163 
164         FAIL()
165             << "No physical device found that supports present to the surface!";
166     }
167 
createDeviceAndGetQueue(std::vector<const char * > & layers,std::vector<const char * > inExtensions={})168     void createDeviceAndGetQueue(std::vector<const char*>& layers,
169                                  std::vector<const char*> inExtensions = {}) {
170         ASSERT_NE((void*)VK_NULL_HANDLE, mPhysicalDev);
171         ASSERT_NE(UINT32_MAX, mPresentQueueFamily);
172 
173         float queuePriority = 1.0f;
174         VkDeviceQueueCreateInfo queueInfo{};
175         queueInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
176         queueInfo.queueFamilyIndex = mPresentQueueFamily;
177         queueInfo.queueCount = 1;
178         queueInfo.pQueuePriorities = &queuePriority;
179 
180         VkDeviceCreateInfo deviceInfo{};
181         deviceInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
182         deviceInfo.queueCreateInfoCount = 1;
183         deviceInfo.pQueueCreateInfos = &queueInfo;
184         deviceInfo.enabledLayerCount = layers.size();
185         deviceInfo.ppEnabledLayerNames = layers.data();
186 
187         std::vector<const char*> extensions = {
188             VK_KHR_SWAPCHAIN_EXTENSION_NAME,
189         };
190         for (auto extension : inExtensions) {
191             extensions.push_back(extension);
192         }
193         deviceInfo.enabledExtensionCount = extensions.size();
194         deviceInfo.ppEnabledExtensionNames = extensions.data();
195 
196         VkResult res =
197             vkCreateDevice(mPhysicalDev, &deviceInfo, nullptr, &mDevice);
198         VK_CHECK(res);
199         LOGI("Logical device created");
200 
201         vkGetDeviceQueue(mDevice, mPresentQueueFamily, 0, &mPresentQueue);
202         ASSERT_NE((VkQueue)VK_NULL_HANDLE, mPresentQueue);
203         LOGI("Acquired present-capable queue");
204     }
205 
createSwapchain()206     void createSwapchain() {
207         ASSERT_NE((VkDevice)VK_NULL_HANDLE, mDevice);
208         ASSERT_NE((VkSurfaceKHR)VK_NULL_HANDLE, mSurface);
209 
210         VkSurfaceCapabilitiesKHR surfaceCaps{};
211         VK_CHECK(vkGetPhysicalDeviceSurfaceCapabilitiesKHR(
212             mPhysicalDev, mSurface, &surfaceCaps));
213 
214         uint32_t formatCount = 0;
215         vkGetPhysicalDeviceSurfaceFormatsKHR(mPhysicalDev, mSurface,
216                                              &formatCount, nullptr);
217         ASSERT_GT(formatCount, 0U);
218         std::vector<VkSurfaceFormatKHR> formats(formatCount);
219         vkGetPhysicalDeviceSurfaceFormatsKHR(mPhysicalDev, mSurface,
220                                              &formatCount, formats.data());
221 
222         VkSurfaceFormatKHR chosenFormat = formats[0];
223         LOGI("Chosen surface format: %d", chosenFormat.format);
224 
225         uint32_t presentModeCount = 0;
226         vkGetPhysicalDeviceSurfacePresentModesKHR(mPhysicalDev, mSurface,
227                                                   &presentModeCount, nullptr);
228         ASSERT_GT(presentModeCount, 0U);
229         std::vector<VkPresentModeKHR> presentModes(presentModeCount);
230         vkGetPhysicalDeviceSurfacePresentModesKHR(
231             mPhysicalDev, mSurface, &presentModeCount, presentModes.data());
232 
233         VkPresentModeKHR chosenPresentMode = VK_PRESENT_MODE_FIFO_KHR;
234         for (auto mode : presentModes) {
235             if (mode == VK_PRESENT_MODE_FIFO_KHR) {
236                 chosenPresentMode = mode;
237                 break;
238             }
239         }
240         LOGI("Chosen present mode: %d", chosenPresentMode);
241 
242         VkExtent2D swapchainExtent{};
243         if (surfaceCaps.currentExtent.width == 0xFFFFFFFF) {
244             swapchainExtent.width = 640;   // fallback
245             swapchainExtent.height = 480;  // fallback
246         } else {
247             swapchainExtent = surfaceCaps.currentExtent;
248         }
249         LOGI("Swapchain extent: %d x %d", swapchainExtent.width,
250              swapchainExtent.height);
251 
252         uint32_t desiredImageCount = surfaceCaps.minImageCount + 1;
253         if (surfaceCaps.maxImageCount > 0 &&
254             desiredImageCount > surfaceCaps.maxImageCount) {
255             desiredImageCount = surfaceCaps.maxImageCount;
256         }
257 
258         VkSwapchainCreateInfoKHR swapchainInfo{};
259         swapchainInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
260         swapchainInfo.surface = mSurface;
261         swapchainInfo.minImageCount = desiredImageCount;
262         swapchainInfo.imageFormat = chosenFormat.format;
263         swapchainInfo.imageColorSpace = chosenFormat.colorSpace;
264         swapchainInfo.imageExtent = swapchainExtent;
265         swapchainInfo.imageArrayLayers = 1;
266         swapchainInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
267                                    VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
268         swapchainInfo.preTransform = surfaceCaps.currentTransform;
269         swapchainInfo.compositeAlpha = VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR;
270         swapchainInfo.presentMode = chosenPresentMode;
271         swapchainInfo.clipped = VK_TRUE;
272         swapchainInfo.oldSwapchain = VK_NULL_HANDLE;
273 
274         uint32_t queueFamilyIndices[] = {mPresentQueueFamily};
275         swapchainInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
276         swapchainInfo.queueFamilyIndexCount = 1;
277         swapchainInfo.pQueueFamilyIndices = queueFamilyIndices;
278 
279         VkResult res =
280             vkCreateSwapchainKHR(mDevice, &swapchainInfo, nullptr, &mSwapchain);
281         if (res == VK_SUCCESS) {
282             LOGI("Swapchain created successfully");
283 
284             uint32_t swapchainImageCount = 0;
285             vkGetSwapchainImagesKHR(mDevice, mSwapchain, &swapchainImageCount,
286                                     nullptr);
287             std::vector<VkImage> swapchainImages(swapchainImageCount);
288             vkGetSwapchainImagesKHR(mDevice, mSwapchain, &swapchainImageCount,
289                                     swapchainImages.data());
290 
291             LOGI("Swapchain has %u images", swapchainImageCount);
292         } else {
293             LOGI("Swapchain creation failed");
294         }
295     }
296 
297     // Image available callback (AImageReader)
onImageAvailable(void *,AImageReader * reader)298     static void onImageAvailable(void*, AImageReader* reader) {
299         LOGI("onImageAvailable callback triggered");
300         AImage* image = nullptr;
301         media_status_t status = AImageReader_acquireLatestImage(reader, &image);
302         if (status != AMEDIA_OK || !image) {
303             LOGE("Failed to acquire latest image");
304             return;
305         }
306         AImage_delete(image);
307         LOGI("Released acquired image");
308     }
309 
cleanUpSwapchainForTest()310     void cleanUpSwapchainForTest() {
311         if (mSwapchain != VK_NULL_HANDLE) {
312             vkDestroySwapchainKHR(mDevice, mSwapchain, nullptr);
313             mSwapchain = VK_NULL_HANDLE;
314         }
315         if (mDevice != VK_NULL_HANDLE) {
316             vkDestroyDevice(mDevice, nullptr);
317             mDevice = VK_NULL_HANDLE;
318         }
319         if (mSurface != VK_NULL_HANDLE) {
320             vkDestroySurfaceKHR(mVkInstance, mSurface, nullptr);
321             mSurface = VK_NULL_HANDLE;
322         }
323         if (mVkInstance != VK_NULL_HANDLE) {
324             vkDestroyInstance(mVkInstance, nullptr);
325             mVkInstance = VK_NULL_HANDLE;
326         }
327         if (mReader) {
328             // AImageReader_delete(mReader);
329             mReader = nullptr;
330         }
331         // Note: The ANativeWindow from AImageReader is implicitly
332         // managed by the reader, so we don't explicitly delete it.
333         mWindow = nullptr;
334     }
335 
buildSwapchianForTest(std::vector<const char * > & instanceLayers,std::vector<const char * > & deviceLayers)336     void buildSwapchianForTest(std::vector<const char*>& instanceLayers,
337                                std::vector<const char*>& deviceLayers) {
338         createVulkanInstance(instanceLayers);
339 
340         // the "atest libvulkan_test" command will execute this test as a binary
341         // (not apk) on the device. Consequently we can't render to the screen
342         // and need to work around this by using AImageReader*
343         createAImageReader(640, 480, AIMAGE_FORMAT_PRIVATE, 3);
344         getANativeWindowFromReader();
345         createVulkanSurface();
346         pickPhysicalDeviceAndQueueFamily();
347 
348         createDeviceAndGetQueue(deviceLayers);
349         createSwapchain();
350     }
351 };
352 
TEST_F(AImageReaderVulkanSwapchainTest,TestHelperMethods)353 TEST_F(AImageReaderVulkanSwapchainTest, TestHelperMethods) {
354     // Verify that the basic plumbing/helper functions of these tests is
355     // working. This doesn't directly test any of the layer code. It only
356     // verifies that we can successfully create a swapchain with an AImageReader
357 
358     std::vector<const char*> instanceLayers;
359     std::vector<const char*> deviceLayers;
360     buildSwapchianForTest(deviceLayers, instanceLayers);
361 
362     ASSERT_NE(mVkInstance, (VkInstance)VK_NULL_HANDLE);
363     ASSERT_NE(mPhysicalDev, (VkPhysicalDevice)VK_NULL_HANDLE);
364     ASSERT_NE(mDevice, (VkDevice)VK_NULL_HANDLE);
365     ASSERT_NE(mSurface, (VkSurfaceKHR)VK_NULL_HANDLE);
366     ASSERT_NE(mSwapchain, (VkSwapchainKHR)VK_NULL_HANDLE);
367     cleanUpSwapchainForTest();
368 }
369 
370 // Passing state in these tests requires global state. Wrap each test in an
371 // anonymous namespace to prevent conflicting names.
372 namespace {
373 
hookedGetPhysicalDeviceImageFormatProperties2KHR(VkPhysicalDevice,const VkPhysicalDeviceImageFormatInfo2 *,VkImageFormatProperties2 *)374 VKAPI_ATTR VkResult VKAPI_CALL hookedGetPhysicalDeviceImageFormatProperties2KHR(
375     VkPhysicalDevice,
376     const VkPhysicalDeviceImageFormatInfo2*,
377     VkImageFormatProperties2*) {
378     return VK_ERROR_SURFACE_LOST_KHR;
379 }
380 
381 static PFN_vkGetSwapchainGrallocUsage2ANDROID
382     pfnNextGetSwapchainGrallocUsage2ANDROID = nullptr;
383 
384 static bool g_grallocCalled = false;
385 
hookGetSwapchainGrallocUsage2ANDROID(VkDevice device,VkFormat format,VkImageUsageFlags imageUsage,VkSwapchainImageUsageFlagsANDROID swapchainImageUsage,uint64_t * grallocConsumerUsage,uint64_t * grallocProducerUsage)386 VKAPI_ATTR VkResult VKAPI_CALL hookGetSwapchainGrallocUsage2ANDROID(
387     VkDevice device,
388     VkFormat format,
389     VkImageUsageFlags imageUsage,
390     VkSwapchainImageUsageFlagsANDROID swapchainImageUsage,
391     uint64_t* grallocConsumerUsage,
392     uint64_t* grallocProducerUsage) {
393     g_grallocCalled = true;
394     if (pfnNextGetSwapchainGrallocUsage2ANDROID) {
395         return pfnNextGetSwapchainGrallocUsage2ANDROID(
396             device, format, imageUsage, swapchainImageUsage,
397             grallocConsumerUsage, grallocProducerUsage);
398     }
399 
400     return VK_ERROR_INITIALIZATION_FAILED;
401 }
402 
TEST_F(AImageReaderVulkanSwapchainTest,getProducerUsageFallbackTest1)403 TEST_F(AImageReaderVulkanSwapchainTest, getProducerUsageFallbackTest1) {
404     // BUG: 379230826
405     // Verify that getProducerUsage falls back to
406     // GetSwapchainGrallocUsage*ANDROID if GPDIFP2 fails
407     std::vector<const char*> instanceLayers = {};
408     std::vector<const char*> deviceLayers = {};
409     createVulkanInstance(instanceLayers);
410 
411     createAImageReader(640, 480, AIMAGE_FORMAT_PRIVATE, 3);
412     getANativeWindowFromReader();
413     createVulkanSurface();
414     pickPhysicalDeviceAndQueueFamily();
415 
416     createDeviceAndGetQueue(deviceLayers);
417     auto& pdev = vulkan::driver::GetData(mDevice).driver_physical_device;
418     auto& pdevDispatchTable = vulkan::driver::GetData(pdev).driver;
419     auto& deviceDispatchTable = vulkan::driver::GetData(mDevice).driver;
420 
421     ASSERT_NE(deviceDispatchTable.GetSwapchainGrallocUsage2ANDROID, nullptr);
422 
423     pdevDispatchTable.GetPhysicalDeviceImageFormatProperties2 =
424         hookedGetPhysicalDeviceImageFormatProperties2KHR;
425     deviceDispatchTable.GetSwapchainGrallocUsage2ANDROID =
426         hookGetSwapchainGrallocUsage2ANDROID;
427 
428     ASSERT_FALSE(g_grallocCalled);
429 
430     createSwapchain();
431 
432     ASSERT_TRUE(g_grallocCalled);
433 
434     ASSERT_NE(mVkInstance, (VkInstance)VK_NULL_HANDLE);
435     ASSERT_NE(mPhysicalDev, (VkPhysicalDevice)VK_NULL_HANDLE);
436     ASSERT_NE(mDevice, (VkDevice)VK_NULL_HANDLE);
437     ASSERT_NE(mSurface, (VkSurfaceKHR)VK_NULL_HANDLE);
438     cleanUpSwapchainForTest();
439 }
440 
441 }  // namespace
442 
443 // Passing state in these tests requires global state. Wrap each test in an
444 // anonymous namespace to prevent conflicting names.
445 namespace {
446 
447 static bool g_returnNotSupportedOnce = true;
448 
449 VKAPI_ATTR VkResult VKAPI_CALL
Hook_GetPhysicalDeviceImageFormatProperties2_NotSupportedOnce(VkPhysicalDevice,const VkPhysicalDeviceImageFormatInfo2 *,VkImageFormatProperties2 *)450 Hook_GetPhysicalDeviceImageFormatProperties2_NotSupportedOnce(
451     VkPhysicalDevice /*physicalDevice*/,
452     const VkPhysicalDeviceImageFormatInfo2* /*pImageFormatInfo*/,
453     VkImageFormatProperties2* /*pImageFormatProperties*/) {
454     if (g_returnNotSupportedOnce) {
455         g_returnNotSupportedOnce = false;
456         return VK_ERROR_FORMAT_NOT_SUPPORTED;
457     }
458     return VK_SUCCESS;
459 }
460 
TEST_F(AImageReaderVulkanSwapchainTest,SurfaceFormats2KHR_IgnoreNotSupported)461 TEST_F(AImageReaderVulkanSwapchainTest, SurfaceFormats2KHR_IgnoreNotSupported) {
462     // BUG: 357903074
463     // Verify that vkGetPhysicalDeviceSurfaceFormats2KHR properly
464     // ignores VK_ERROR_FORMAT_NOT_SUPPORTED and continues enumerating formats.
465     std::vector<const char*> instanceLayers;
466     createVulkanInstance(instanceLayers);
467     createAImageReader(640, 480, AIMAGE_FORMAT_PRIVATE, 3);
468     getANativeWindowFromReader();
469     createVulkanSurface();
470     pickPhysicalDeviceAndQueueFamily();
471 
472     auto& pdevDispatchTable = vulkan::driver::GetData(mPhysicalDev).driver;
473     pdevDispatchTable.GetPhysicalDeviceImageFormatProperties2 =
474         Hook_GetPhysicalDeviceImageFormatProperties2_NotSupportedOnce;
475 
476     PFN_vkGetPhysicalDeviceSurfaceFormats2KHR
477         pfnGetPhysicalDeviceSurfaceFormats2KHR =
478             reinterpret_cast<PFN_vkGetPhysicalDeviceSurfaceFormats2KHR>(
479                 vkGetInstanceProcAddr(mVkInstance,
480                                       "vkGetPhysicalDeviceSurfaceFormats2KHR"));
481     ASSERT_NE(nullptr, pfnGetPhysicalDeviceSurfaceFormats2KHR)
482         << "Could not get pointer to vkGetPhysicalDeviceSurfaceFormats2KHR";
483 
484     VkPhysicalDeviceSurfaceInfo2KHR surfaceInfo2{};
485     surfaceInfo2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SURFACE_INFO_2_KHR;
486     surfaceInfo2.pNext = nullptr;
487     surfaceInfo2.surface = mSurface;
488 
489     uint32_t formatCount = 0;
490     VkResult res = pfnGetPhysicalDeviceSurfaceFormats2KHR(
491         mPhysicalDev, &surfaceInfo2, &formatCount, nullptr);
492 
493     // If the loader never tries a second format, it might fail or 0-out the
494     // formatCount. The patch ensures it continues to the next format rather
495     // than bailing out on the first NOT_SUPPORTED.
496     ASSERT_EQ(VK_SUCCESS, res)
497         << "vkGetPhysicalDeviceSurfaceFormats2KHR failed unexpectedly";
498     ASSERT_GT(formatCount, 0U)
499         << "No surface formats found; the loader may have bailed early.";
500 
501     std::vector<VkSurfaceFormat2KHR> formats(formatCount);
502     for (auto& f : formats) {
503         f.sType = VK_STRUCTURE_TYPE_SURFACE_FORMAT_2_KHR;
504         f.pNext = nullptr;
505     }
506     res = pfnGetPhysicalDeviceSurfaceFormats2KHR(mPhysicalDev, &surfaceInfo2,
507                                                  &formatCount, formats.data());
508     ASSERT_EQ(VK_SUCCESS, res) << "Failed to retrieve surface formats";
509 
510     LOGI(
511         "SurfaceFormats2KHR_IgnoreNotSupported test: found %u formats after "
512         "ignoring NOT_SUPPORTED",
513         formatCount);
514 
515     cleanUpSwapchainForTest();
516 }
517 
518 }  // namespace
519 
520 namespace {
521 
TEST_F(AImageReaderVulkanSwapchainTest,MutableFormatSwapchainTest)522 TEST_F(AImageReaderVulkanSwapchainTest, MutableFormatSwapchainTest) {
523     // Test swapchain with mutable format extension
524     std::vector<const char*> instanceLayers;
525     std::vector<const char*> deviceLayers;
526     std::vector<const char*> deviceExtensions = {
527         VK_KHR_SWAPCHAIN_EXTENSION_NAME,
528         VK_KHR_SWAPCHAIN_MUTABLE_FORMAT_EXTENSION_NAME,
529         VK_KHR_MAINTENANCE2_EXTENSION_NAME,
530         VK_KHR_IMAGE_FORMAT_LIST_EXTENSION_NAME};
531 
532     createVulkanInstance(instanceLayers);
533     createAImageReader(640, 480, AIMAGE_FORMAT_PRIVATE, 3);
534     getANativeWindowFromReader();
535     createVulkanSurface();
536     pickPhysicalDeviceAndQueueFamily();
537     createDeviceAndGetQueue(deviceLayers, deviceExtensions);
538 
539     ASSERT_NE((VkDevice)VK_NULL_HANDLE, mDevice);
540     ASSERT_NE((VkSurfaceKHR)VK_NULL_HANDLE, mSurface);
541 
542     VkSurfaceCapabilitiesKHR surfaceCaps{};
543     VK_CHECK(vkGetPhysicalDeviceSurfaceCapabilitiesKHR(mPhysicalDev, mSurface,
544                                                        &surfaceCaps));
545 
546     uint32_t formatCount = 0;
547     vkGetPhysicalDeviceSurfaceFormatsKHR(mPhysicalDev, mSurface, &formatCount,
548                                          nullptr);
549     ASSERT_GT(formatCount, 0U);
550     std::vector<VkSurfaceFormatKHR> formats(formatCount);
551     vkGetPhysicalDeviceSurfaceFormatsKHR(mPhysicalDev, mSurface, &formatCount,
552                                          formats.data());
553 
554     VkFormat viewFormats[2] = {formats[0].format, formats[0].format};
555     if (formatCount > 1) {
556         viewFormats[1] = formats[1].format;
557     }
558 
559     VkImageFormatListCreateInfoKHR formatList{};
560     formatList.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO_KHR;
561     formatList.viewFormatCount = 2;
562     formatList.pViewFormats = viewFormats;
563 
564     VkSwapchainCreateInfoKHR swapchainInfo{};
565     swapchainInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
566     swapchainInfo.pNext = &formatList;
567     swapchainInfo.surface = mSurface;
568     swapchainInfo.minImageCount = surfaceCaps.minImageCount + 1;
569     swapchainInfo.imageFormat = formats[0].format;
570     swapchainInfo.imageColorSpace = formats[0].colorSpace;
571     swapchainInfo.imageExtent = surfaceCaps.currentExtent;
572     swapchainInfo.imageArrayLayers = 1;
573     swapchainInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
574     swapchainInfo.preTransform = surfaceCaps.currentTransform;
575     swapchainInfo.compositeAlpha = VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR;
576     swapchainInfo.presentMode = VK_PRESENT_MODE_FIFO_KHR;
577     swapchainInfo.clipped = VK_TRUE;
578 
579     swapchainInfo.flags = VK_SWAPCHAIN_CREATE_MUTABLE_FORMAT_BIT_KHR;
580 
581     uint32_t queueFamilyIndices[] = {mPresentQueueFamily};
582     swapchainInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
583     swapchainInfo.queueFamilyIndexCount = 1;
584     swapchainInfo.pQueueFamilyIndices = queueFamilyIndices;
585 
586     VkResult res =
587         vkCreateSwapchainKHR(mDevice, &swapchainInfo, nullptr, &mSwapchain);
588     if (res == VK_SUCCESS) {
589         LOGI("Mutable format swapchain created successfully");
590 
591         uint32_t imageCount = 0;
592         vkGetSwapchainImagesKHR(mDevice, mSwapchain, &imageCount, nullptr);
593         ASSERT_GT(imageCount, 0U);
594     } else {
595         LOGI(
596             "Mutable format swapchain creation failed (extension may not be "
597             "supported)");
598     }
599 
600     cleanUpSwapchainForTest();
601 }
602 
603 }  // namespace
604 
605 }  // namespace libvulkantest
606 
607 }  // namespace android
608