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