1 /*-------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2016 Google Inc.
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 *//*!
20 * \file
21 * \brief VkSwapchain Tests
22 *//*--------------------------------------------------------------------*/
23
24 #include "vktWsiSwapchainTests.hpp"
25
26 #include "vktTestCaseUtil.hpp"
27 #include "vktTestGroupUtil.hpp"
28 #include "vktCustomInstancesDevices.hpp"
29 #include "vktNativeObjectsUtil.hpp"
30
31 #include "vkDefs.hpp"
32 #include "vkPlatform.hpp"
33 #include "vkStrUtil.hpp"
34 #include "vkRef.hpp"
35 #include "vkRefUtil.hpp"
36 #include "vkQueryUtil.hpp"
37 #include "vkMemUtil.hpp"
38 #include "vkDeviceUtil.hpp"
39 #include "vkPrograms.hpp"
40 #include "vkTypeUtil.hpp"
41 #include "vkWsiPlatform.hpp"
42 #include "vkWsiUtil.hpp"
43 #include "vkAllocationCallbackUtil.hpp"
44 #include "vkCmdUtil.hpp"
45 #include "vkObjTypeImpl.inl"
46 #include "vkObjUtil.hpp"
47
48 #include "tcuCommandLine.hpp"
49 #include "tcuTestLog.hpp"
50 #include "tcuFormatUtil.hpp"
51 #include "tcuPlatform.hpp"
52 #include "tcuResultCollector.hpp"
53
54 #include "deUniquePtr.hpp"
55 #include "deStringUtil.hpp"
56 #include "deArrayUtil.hpp"
57 #include "deSharedPtr.hpp"
58
59 #include <limits>
60 #include <algorithm>
61 #include <iterator>
62
63 #if (DE_OS == DE_OS_ANDROID)
64 #include <thread>
65 #include <chrono>
66 #endif
67
68 namespace vkt
69 {
70 namespace wsi
71 {
72
73 namespace
74 {
75
76 using namespace vk;
77 using namespace vk::wsi;
78
79 using tcu::Maybe;
80 using tcu::TestLog;
81 using tcu::UVec2;
82
83 using de::MovePtr;
84 using de::SharedPtr;
85 using de::UniquePtr;
86
87 using std::string;
88 using std::vector;
89
90 typedef vector<VkExtensionProperties> Extensions;
91
checkAllSupported(const Extensions & supportedExtensions,const vector<string> & requiredExtensions)92 void checkAllSupported(const Extensions &supportedExtensions, const vector<string> &requiredExtensions)
93 {
94 for (vector<string>::const_iterator requiredExtName = requiredExtensions.begin();
95 requiredExtName != requiredExtensions.end(); ++requiredExtName)
96 {
97 if (!isExtensionStructSupported(supportedExtensions, RequiredExtension(*requiredExtName)))
98 TCU_THROW(NotSupportedError, (*requiredExtName + " is not supported").c_str());
99 }
100 }
101
createInstanceWithWsi(Context & context,const Extensions & supportedExtensions,Type wsiType,const vector<string> extraExtensions,const VkAllocationCallbacks * pAllocator=DE_NULL)102 CustomInstance createInstanceWithWsi(Context &context, const Extensions &supportedExtensions, Type wsiType,
103 const vector<string> extraExtensions,
104 const VkAllocationCallbacks *pAllocator = DE_NULL)
105 {
106 vector<string> extensions = extraExtensions;
107
108 extensions.push_back("VK_KHR_surface");
109 extensions.push_back(getExtensionName(wsiType));
110 if (isDisplaySurface(wsiType))
111 extensions.push_back("VK_KHR_display");
112
113 // VK_EXT_swapchain_colorspace adds new surface formats. Driver can enumerate
114 // the formats regardless of whether VK_EXT_swapchain_colorspace was enabled,
115 // but using them without enabling the extension is not allowed. Thus we have
116 // two options:
117 //
118 // 1) Filter out non-core formats to stay within valid usage.
119 //
120 // 2) Enable VK_EXT_swapchain colorspace if advertised by the driver.
121 //
122 // We opt for (2) as it provides basic coverage for the extension as a bonus.
123 if (isExtensionStructSupported(supportedExtensions, RequiredExtension("VK_EXT_swapchain_colorspace")))
124 extensions.push_back("VK_EXT_swapchain_colorspace");
125
126 checkAllSupported(supportedExtensions, extensions);
127
128 return vkt::createCustomInstanceWithExtensions(context, extensions, pAllocator);
129 }
130
getDeviceFeaturesForWsi(void)131 VkPhysicalDeviceFeatures getDeviceFeaturesForWsi(void)
132 {
133 VkPhysicalDeviceFeatures features;
134 deMemset(&features, 0, sizeof(features));
135 return features;
136 }
137
createDeviceWithWsi(const PlatformInterface & vkp,uint32_t apiVersion,VkInstance instance,const InstanceInterface & vki,VkPhysicalDevice physicalDevice,const Extensions & supportedExtensions,const vector<string> & additionalExtensions,const vector<uint32_t> & queueFamilyIndices,bool validationEnabled,const VkAllocationCallbacks * pAllocator=DE_NULL)138 Move<VkDevice> createDeviceWithWsi(const PlatformInterface &vkp, uint32_t apiVersion, VkInstance instance,
139 const InstanceInterface &vki, VkPhysicalDevice physicalDevice,
140 const Extensions &supportedExtensions, const vector<string> &additionalExtensions,
141 const vector<uint32_t> &queueFamilyIndices, bool validationEnabled,
142 const VkAllocationCallbacks *pAllocator = DE_NULL)
143 {
144 const float queuePriorities[] = {1.0f};
145 vector<VkDeviceQueueCreateInfo> queueInfos;
146
147 for (const auto familyIndex : queueFamilyIndices)
148 {
149 const VkDeviceQueueCreateInfo info = {
150 VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
151 nullptr,
152 (VkDeviceQueueCreateFlags)0,
153 familyIndex,
154 DE_LENGTH_OF_ARRAY(queuePriorities),
155 &queuePriorities[0],
156 };
157
158 queueInfos.push_back(info);
159 }
160
161 vector<string> extensions;
162 extensions.push_back("VK_KHR_swapchain");
163 extensions.insert(end(extensions), begin(additionalExtensions), end(additionalExtensions));
164
165 for (const auto &extName : extensions)
166 {
167 if (!isCoreDeviceExtension(apiVersion, extName) &&
168 !isExtensionStructSupported(supportedExtensions, RequiredExtension(extName)))
169 TCU_THROW(NotSupportedError, extName + " is not supported");
170 }
171
172 const void *pNext = nullptr;
173 const VkPhysicalDeviceFeatures features = getDeviceFeaturesForWsi();
174
175 VkDevicePrivateDataCreateInfoEXT pdci = initVulkanStructure();
176 pdci.privateDataSlotRequestCount = 4u;
177
178 VkPhysicalDevicePrivateDataFeaturesEXT privateDataFeatures = initVulkanStructure(&pdci);
179 privateDataFeatures.privateData = VK_TRUE;
180
181 if (de::contains(begin(extensions), end(extensions), "VK_EXT_private_data"))
182 {
183 pNext = &privateDataFeatures;
184 }
185
186 // Convert from std::vector<std::string> to std::vector<const char*>.
187 std::vector<const char *> extensionsChar;
188 extensionsChar.reserve(extensions.size());
189 std::transform(begin(extensions), end(extensions), std::back_inserter(extensionsChar),
190 [](const std::string &s) { return s.c_str(); });
191
192 const VkDeviceCreateInfo deviceParams = {VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
193 pNext,
194 (VkDeviceCreateFlags)0,
195 static_cast<uint32_t>(queueInfos.size()),
196 queueInfos.data(),
197 0u, // enabledLayerCount
198 nullptr, // ppEnabledLayerNames
199 static_cast<uint32_t>(extensionsChar.size()), // enabledExtensionCount
200 extensionsChar.data(), // ppEnabledExtensionNames
201 &features};
202
203 return createCustomDevice(validationEnabled, vkp, instance, vki, physicalDevice, &deviceParams, pAllocator);
204 }
205
createDeviceWithWsi(const PlatformInterface & vkp,uint32_t apiVersion,VkInstance instance,const InstanceInterface & vki,VkPhysicalDevice physicalDevice,const Extensions & supportedExtensions,const vector<string> & additionalExtensions,const uint32_t queueFamilyIndex,bool validationEnabled,const VkAllocationCallbacks * pAllocator=DE_NULL)206 Move<VkDevice> createDeviceWithWsi(const PlatformInterface &vkp, uint32_t apiVersion, VkInstance instance,
207 const InstanceInterface &vki, VkPhysicalDevice physicalDevice,
208 const Extensions &supportedExtensions, const vector<string> &additionalExtensions,
209 const uint32_t queueFamilyIndex, bool validationEnabled,
210 const VkAllocationCallbacks *pAllocator = DE_NULL)
211 {
212 return createDeviceWithWsi(vkp, apiVersion, instance, vki, physicalDevice, supportedExtensions,
213 additionalExtensions, vector<uint32_t>(1u, queueFamilyIndex), validationEnabled,
214 pAllocator);
215 }
216
217 struct InstanceHelper
218 {
219 const vector<VkExtensionProperties> supportedExtensions;
220 const CustomInstance instance;
221 const InstanceDriver &vki;
222
InstanceHelpervkt::wsi::__anon88b80f900111::InstanceHelper223 InstanceHelper(Context &context, Type wsiType, const VkAllocationCallbacks *pAllocator = DE_NULL)
224 : supportedExtensions(enumerateInstanceExtensionProperties(context.getPlatformInterface(), DE_NULL))
225 , instance(createInstanceWithWsi(context, supportedExtensions, wsiType, vector<string>(), pAllocator))
226 , vki(instance.getDriver())
227 {
228 }
229
InstanceHelpervkt::wsi::__anon88b80f900111::InstanceHelper230 InstanceHelper(Context &context, Type wsiType, const vector<string> &extensions,
231 const VkAllocationCallbacks *pAllocator = DE_NULL)
232 : supportedExtensions(enumerateInstanceExtensionProperties(context.getPlatformInterface(), DE_NULL))
233 , instance(createInstanceWithWsi(context, supportedExtensions, wsiType, extensions, pAllocator))
234 , vki(instance.getDriver())
235 {
236 }
237 };
238
239 struct DeviceHelper
240 {
241 const VkPhysicalDevice physicalDevice;
242 const uint32_t queueFamilyIndex;
243 const Unique<VkDevice> device;
244 const DeviceDriver vkd;
245 const VkQueue queue;
246
DeviceHelpervkt::wsi::__anon88b80f900111::DeviceHelper247 DeviceHelper(Context &context, const InstanceInterface &vki, VkInstance instance,
248 const vector<VkSurfaceKHR> &surface, const vector<string> &additionalExtensions = vector<string>(),
249 const VkAllocationCallbacks *pAllocator = DE_NULL)
250 : physicalDevice(chooseDevice(vki, instance, context.getTestContext().getCommandLine()))
251 , queueFamilyIndex(chooseQueueFamilyIndex(vki, physicalDevice, surface))
252 , device(createDeviceWithWsi(context.getPlatformInterface(), context.getUsedApiVersion(), instance, vki,
253 physicalDevice, enumerateDeviceExtensionProperties(vki, physicalDevice, DE_NULL),
254 additionalExtensions, queueFamilyIndex,
255 context.getTestContext().getCommandLine().isValidationEnabled(), pAllocator))
256 , vkd(context.getPlatformInterface(), instance, *device, context.getUsedApiVersion(),
257 context.getTestContext().getCommandLine())
258 , queue(getDeviceQueue(vkd, *device, queueFamilyIndex, 0))
259 {
260 }
261
262 // Single-surface shortcut.
DeviceHelpervkt::wsi::__anon88b80f900111::DeviceHelper263 DeviceHelper(Context &context, const InstanceInterface &vki, VkInstance instance, VkSurfaceKHR surface,
264 const vector<string> &additionalExtensions = vector<string>(),
265 const VkAllocationCallbacks *pAllocator = DE_NULL)
266 : DeviceHelper(context, vki, instance, vector<VkSurfaceKHR>(1u, surface), additionalExtensions, pAllocator)
267 {
268 }
269 };
270
271 // Similar to the one above with no queues and multiple queue families.
272 struct MultiQueueDeviceHelper
273 {
274 const VkPhysicalDevice physicalDevice;
275 const vector<uint32_t> queueFamilyIndices;
276 const Unique<VkDevice> device;
277 const DeviceDriver vkd;
278
MultiQueueDeviceHelpervkt::wsi::__anon88b80f900111::MultiQueueDeviceHelper279 MultiQueueDeviceHelper(Context &context, const InstanceInterface &vki, VkInstance instance,
280 const vector<VkSurfaceKHR> &surface,
281 const vector<string> &additionalExtensions = vector<string>(),
282 const VkAllocationCallbacks *pAllocator = DE_NULL)
283 : physicalDevice(chooseDevice(vki, instance, context.getTestContext().getCommandLine()))
284 , queueFamilyIndices(getCompatibleQueueFamilyIndices(vki, physicalDevice, surface))
285 , device(createDeviceWithWsi(context.getPlatformInterface(), context.getUsedApiVersion(), instance, vki,
286 physicalDevice, enumerateDeviceExtensionProperties(vki, physicalDevice, DE_NULL),
287 additionalExtensions, queueFamilyIndices,
288 context.getTestContext().getCommandLine().isValidationEnabled(), pAllocator))
289 , vkd(context.getPlatformInterface(), instance, *device, context.getUsedApiVersion(),
290 context.getTestContext().getCommandLine())
291 {
292 }
293
294 // Single-surface shortcut.
MultiQueueDeviceHelpervkt::wsi::__anon88b80f900111::MultiQueueDeviceHelper295 MultiQueueDeviceHelper(Context &context, const InstanceInterface &vki, VkInstance instance, VkSurfaceKHR surface,
296 const vector<string> additionalExtensions = vector<string>(),
297 const VkAllocationCallbacks *pAllocator = DE_NULL)
298 : MultiQueueDeviceHelper(context, vki, instance, vector<VkSurfaceKHR>(1u, surface), additionalExtensions,
299 pAllocator)
300 {
301 }
302 };
303
304 enum TestDimension
305 {
306 TEST_DIMENSION_MIN_IMAGE_COUNT = 0, //!< Test all supported image counts
307 TEST_DIMENSION_IMAGE_FORMAT, //!< Test all supported formats
308 TEST_DIMENSION_IMAGE_EXTENT, //!< Test various (supported) extents
309 TEST_DIMENSION_IMAGE_ARRAY_LAYERS,
310 TEST_DIMENSION_IMAGE_USAGE,
311 TEST_DIMENSION_IMAGE_SHARING_MODE,
312 TEST_DIMENSION_PRE_TRANSFORM,
313 TEST_DIMENSION_COMPOSITE_ALPHA,
314 TEST_DIMENSION_PRESENT_MODE,
315 TEST_DIMENSION_CLIPPED,
316 TEST_DIMENSION_EXCLUSIVE_NONZERO, //!< Test VK_SHARING_MODE_EXCLUSIVE and a nonzero queue count.
317
318 TEST_DIMENSION_LAST
319 };
320
getTestDimensionName(TestDimension dimension)321 const char *getTestDimensionName(TestDimension dimension)
322 {
323 static const char *const s_names[] = {
324 "min_image_count", "image_format", "image_extent", "image_array_layers", "image_usage",
325 "image_sharing_mode", "pre_transform", "composite_alpha", "present_mode", "clipped",
326 "exclusive_nonzero_queues",
327 };
328 static_assert(static_cast<int>(de::arrayLength(s_names)) == TEST_DIMENSION_LAST,
329 "Array of names does not provide a 1:1 mapping to TestDimension");
330 return de::getSizedArrayElement<TEST_DIMENSION_LAST>(s_names, dimension);
331 }
332
333 struct TestParameters
334 {
335 Type wsiType;
336 TestDimension dimension;
337
TestParametersvkt::wsi::__anon88b80f900111::TestParameters338 TestParameters(Type wsiType_, TestDimension dimension_) : wsiType(wsiType_), dimension(dimension_)
339 {
340 }
341
TestParametersvkt::wsi::__anon88b80f900111::TestParameters342 TestParameters(void) : wsiType(TYPE_LAST), dimension(TEST_DIMENSION_LAST)
343 {
344 }
345 };
346
generateSwapchainParameterCases(const InstanceInterface & vki,VkPhysicalDevice physicalDevice,Type wsiType,TestDimension dimension,const VkSurfaceCapabilitiesKHR & capabilities,const vector<VkSurfaceFormatKHR> & formats,const vector<VkPresentModeKHR> & presentModes)347 vector<VkSwapchainCreateInfoKHR> generateSwapchainParameterCases(const InstanceInterface &vki,
348 VkPhysicalDevice physicalDevice, Type wsiType,
349 TestDimension dimension,
350 const VkSurfaceCapabilitiesKHR &capabilities,
351 const vector<VkSurfaceFormatKHR> &formats,
352 const vector<VkPresentModeKHR> &presentModes)
353 {
354 const PlatformProperties &platformProperties = getPlatformProperties(wsiType);
355 vector<VkSwapchainCreateInfoKHR> cases;
356 const VkSurfaceTransformFlagBitsKHR defaultTransform =
357 (capabilities.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) ?
358 VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR :
359 capabilities.currentTransform;
360 const VkSwapchainCreateInfoKHR baseParameters = {
361 VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
362 DE_NULL,
363 (VkSwapchainCreateFlagsKHR)0,
364 (VkSurfaceKHR)0,
365 capabilities.minImageCount,
366 formats[0].format,
367 formats[0].colorSpace,
368 (platformProperties.swapchainExtent == PlatformProperties::SWAPCHAIN_EXTENT_SETS_WINDOW_SIZE ?
369 capabilities.minImageExtent :
370 capabilities.currentExtent),
371 1u, // imageArrayLayers
372 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
373 VK_SHARING_MODE_EXCLUSIVE,
374 0u,
375 nullptr,
376 defaultTransform,
377 VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
378 VK_PRESENT_MODE_FIFO_KHR,
379 VK_FALSE, // clipped
380 (VkSwapchainKHR)0 // oldSwapchain
381 };
382
383 switch (dimension)
384 {
385 case TEST_DIMENSION_MIN_IMAGE_COUNT:
386 {
387 const uint32_t maxImageCountToTest =
388 de::clamp(16u, capabilities.minImageCount,
389 (capabilities.maxImageCount > 0) ? capabilities.maxImageCount : capabilities.minImageCount + 16u);
390
391 for (uint32_t imageCount = capabilities.minImageCount; imageCount <= maxImageCountToTest; ++imageCount)
392 {
393 cases.push_back(baseParameters);
394 cases.back().minImageCount = imageCount;
395 }
396
397 break;
398 }
399
400 case TEST_DIMENSION_IMAGE_FORMAT:
401 {
402 for (vector<VkSurfaceFormatKHR>::const_iterator curFmt = formats.begin(); curFmt != formats.end(); ++curFmt)
403 {
404 cases.push_back(baseParameters);
405 cases.back().imageFormat = curFmt->format;
406 cases.back().imageColorSpace = curFmt->colorSpace;
407 }
408
409 break;
410 }
411
412 case TEST_DIMENSION_IMAGE_EXTENT:
413 {
414 static const VkExtent2D s_testSizes[] = {
415 {1, 1}, {16, 32}, {32, 16}, {632, 231}, {117, 998},
416 };
417
418 if (platformProperties.swapchainExtent == PlatformProperties::SWAPCHAIN_EXTENT_SETS_WINDOW_SIZE ||
419 platformProperties.swapchainExtent == PlatformProperties::SWAPCHAIN_EXTENT_SCALED_TO_WINDOW_SIZE)
420 {
421 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(s_testSizes); ++ndx)
422 {
423 cases.push_back(baseParameters);
424 cases.back().imageExtent.width = de::clamp(s_testSizes[ndx].width, capabilities.minImageExtent.width,
425 capabilities.maxImageExtent.width);
426 cases.back().imageExtent.height = de::clamp(s_testSizes[ndx].height, capabilities.minImageExtent.height,
427 capabilities.maxImageExtent.height);
428 }
429 }
430
431 if (platformProperties.swapchainExtent != PlatformProperties::SWAPCHAIN_EXTENT_SETS_WINDOW_SIZE)
432 {
433 cases.push_back(baseParameters);
434 cases.back().imageExtent = capabilities.currentExtent;
435 }
436
437 if (platformProperties.swapchainExtent != PlatformProperties::SWAPCHAIN_EXTENT_MUST_MATCH_WINDOW_SIZE)
438 {
439 cases.push_back(baseParameters);
440 cases.back().imageExtent = capabilities.minImageExtent;
441
442 cases.push_back(baseParameters);
443 cases.back().imageExtent = capabilities.maxImageExtent;
444 }
445
446 break;
447 }
448
449 case TEST_DIMENSION_IMAGE_ARRAY_LAYERS:
450 {
451 const uint32_t maxLayers = de::min(capabilities.maxImageArrayLayers, 16u);
452
453 for (uint32_t numLayers = 1; numLayers <= maxLayers; ++numLayers)
454 {
455 cases.push_back(baseParameters);
456 cases.back().imageArrayLayers = numLayers;
457 }
458
459 break;
460 }
461
462 case TEST_DIMENSION_IMAGE_USAGE:
463 {
464 for (uint32_t flags = 1u; flags <= capabilities.supportedUsageFlags; ++flags)
465 {
466 VkImageFormatProperties imageProps;
467
468 if ((flags & ~capabilities.supportedUsageFlags) == 0)
469 {
470 if (vki.getPhysicalDeviceImageFormatProperties(physicalDevice, baseParameters.imageFormat,
471 VK_IMAGE_TYPE_2D, VK_IMAGE_TILING_OPTIMAL, flags,
472 (VkImageCreateFlags)0u, &imageProps) != VK_SUCCESS)
473 continue;
474
475 cases.push_back(baseParameters);
476 cases.back().imageUsage = flags;
477 }
478 }
479
480 break;
481 }
482
483 case TEST_DIMENSION_IMAGE_SHARING_MODE:
484 {
485 #if 0
486 // Skipping since this matches the base parameters.
487 cases.push_back(baseParameters);
488 cases.back().imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
489 #endif
490
491 cases.push_back(baseParameters);
492 cases.back().imageSharingMode = VK_SHARING_MODE_CONCURRENT;
493
494 break;
495 }
496
497 case TEST_DIMENSION_PRE_TRANSFORM:
498 {
499 for (uint32_t transform = 1u; transform <= capabilities.supportedTransforms; transform = transform << 1u)
500 {
501 if ((transform & capabilities.supportedTransforms) != 0)
502 {
503 cases.push_back(baseParameters);
504 cases.back().preTransform = (VkSurfaceTransformFlagBitsKHR)transform;
505 }
506 }
507
508 break;
509 }
510
511 case TEST_DIMENSION_COMPOSITE_ALPHA:
512 {
513 for (uint32_t alphaMode = 1u; alphaMode <= capabilities.supportedCompositeAlpha; alphaMode = alphaMode << 1u)
514 {
515 if ((alphaMode & capabilities.supportedCompositeAlpha) != 0)
516 {
517 cases.push_back(baseParameters);
518 cases.back().compositeAlpha = (VkCompositeAlphaFlagBitsKHR)alphaMode;
519 }
520 }
521
522 break;
523 }
524
525 case TEST_DIMENSION_PRESENT_MODE:
526 {
527 for (vector<VkPresentModeKHR>::const_iterator curMode = presentModes.begin(); curMode != presentModes.end();
528 ++curMode)
529 {
530 cases.push_back(baseParameters);
531 cases.back().presentMode = *curMode;
532 }
533
534 break;
535 }
536
537 case TEST_DIMENSION_CLIPPED:
538 {
539 cases.push_back(baseParameters);
540 cases.back().clipped = VK_FALSE;
541
542 cases.push_back(baseParameters);
543 cases.back().clipped = VK_TRUE;
544
545 break;
546 }
547
548 case TEST_DIMENSION_EXCLUSIVE_NONZERO:
549 {
550 // Test the implementation doesn't attempt to do anything with the queue index array in exclusive sharing mode.
551 cases.push_back(baseParameters);
552 cases.back().queueFamilyIndexCount = 2u;
553
554 break;
555 }
556
557 default:
558 DE_FATAL("Impossible");
559 }
560
561 DE_ASSERT(!cases.empty());
562 return cases;
563 }
564
generateSwapchainParameterCases(Type wsiType,TestDimension dimension,const InstanceInterface & vki,VkPhysicalDevice physicalDevice,VkSurfaceKHR surface)565 vector<VkSwapchainCreateInfoKHR> generateSwapchainParameterCases(Type wsiType, TestDimension dimension,
566 const InstanceInterface &vki,
567 VkPhysicalDevice physicalDevice, VkSurfaceKHR surface)
568 {
569 const VkSurfaceCapabilitiesKHR capabilities = getPhysicalDeviceSurfaceCapabilities(vki, physicalDevice, surface);
570 const vector<VkSurfaceFormatKHR> formats = getPhysicalDeviceSurfaceFormats(vki, physicalDevice, surface);
571 const vector<VkPresentModeKHR> presentModes = getPhysicalDeviceSurfacePresentModes(vki, physicalDevice, surface);
572
573 return generateSwapchainParameterCases(vki, physicalDevice, wsiType, dimension, capabilities, formats,
574 presentModes);
575 }
576
createSwapchainTest(Context & context,TestParameters params)577 tcu::TestStatus createSwapchainTest(Context &context, TestParameters params)
578 {
579 tcu::TestLog &log = context.getTestContext().getLog();
580 const InstanceHelper instHelper(context, params.wsiType);
581 const NativeObjects native(context, instHelper.supportedExtensions, params.wsiType);
582 const Unique<VkSurfaceKHR> surface(createSurface(instHelper.vki, instHelper.instance, params.wsiType,
583 native.getDisplay(), native.getWindow(),
584 context.getTestContext().getCommandLine()));
585 const MultiQueueDeviceHelper devHelper(context, instHelper.vki, instHelper.instance, *surface);
586 const vector<VkSwapchainCreateInfoKHR> cases(generateSwapchainParameterCases(
587 params.wsiType, params.dimension, instHelper.vki, devHelper.physicalDevice, *surface));
588 const VkSurfaceCapabilitiesKHR capabilities(
589 getPhysicalDeviceSurfaceCapabilities(instHelper.vki, devHelper.physicalDevice, *surface));
590
591 for (size_t caseNdx = 0; caseNdx < cases.size(); ++caseNdx)
592 {
593 std::ostringstream subcase;
594 subcase << "Sub-case " << (caseNdx + 1) << " / " << cases.size() << ": ";
595
596 VkSwapchainCreateInfoKHR curParams = cases[caseNdx];
597
598 if (curParams.imageSharingMode == VK_SHARING_MODE_CONCURRENT)
599 {
600 const auto numFamilies = static_cast<uint32_t>(devHelper.queueFamilyIndices.size());
601 if (numFamilies < 2u)
602 TCU_THROW(NotSupportedError, "Only " + de::toString(numFamilies) +
603 " queue families available for VK_SHARING_MODE_CONCURRENT");
604
605 curParams.queueFamilyIndexCount = numFamilies;
606 curParams.pQueueFamilyIndices = devHelper.queueFamilyIndices.data();
607 }
608
609 // Overwrite surface.
610 curParams.surface = *surface;
611
612 log << TestLog::Message << subcase.str() << curParams << TestLog::EndMessage;
613
614 // The Vulkan 1.1.87 spec contains the following VU for VkSwapchainCreateInfoKHR:
615 //
616 // * imageFormat, imageUsage, imageExtent, and imageArrayLayers must be supported for VK_IMAGE_TYPE_2D
617 // VK_IMAGE_TILING_OPTIMAL images as reported by vkGetPhysicalDeviceImageFormatProperties.
618 VkImageFormatProperties properties;
619 const VkResult propertiesResult = instHelper.vki.getPhysicalDeviceImageFormatProperties(
620 devHelper.physicalDevice, curParams.imageFormat, VK_IMAGE_TYPE_2D, VK_IMAGE_TILING_OPTIMAL,
621 curParams.imageUsage,
622 0, // flags
623 &properties);
624
625 log << TestLog::Message << subcase.str() << "vkGetPhysicalDeviceImageFormatProperties => "
626 << getResultStr(propertiesResult) << TestLog::EndMessage;
627
628 switch (propertiesResult)
629 {
630 case VK_SUCCESS:
631 {
632 // The maxExtents case might not be able to create the requested surface due to insufficient
633 // memory, so in this case *only* we handle the OOM exception.
634 if (params.dimension == TEST_DIMENSION_IMAGE_EXTENT &&
635 capabilities.maxImageExtent.width == curParams.imageExtent.width &&
636 capabilities.maxImageExtent.height == curParams.imageExtent.height)
637 {
638 try
639 {
640 const Unique<VkSwapchainKHR> swapchain(
641 createSwapchainKHR(devHelper.vkd, *devHelper.device, &curParams));
642
643 log << TestLog::Message << subcase.str() << "Creating swapchain succeeded" << TestLog::EndMessage;
644 }
645 catch (const OutOfMemoryError &e)
646 {
647 log << TestLog::Message << subcase.str() << "vkCreateSwapchainKHR with maxImageExtent encountered "
648 << e.getError() << TestLog::EndMessage;
649 }
650 }
651 else
652 {
653 const Unique<VkSwapchainKHR> swapchain(
654 createSwapchainKHR(devHelper.vkd, *devHelper.device, &curParams));
655
656 log << TestLog::Message << subcase.str() << "Creating swapchain succeeded" << TestLog::EndMessage;
657 }
658 }
659 break;
660 case VK_ERROR_FORMAT_NOT_SUPPORTED:
661 log << TestLog::Message << subcase.str()
662 << "Skip because vkGetPhysicalDeviceImageFormatProperties returned VK_ERROR_FORMAT_NOT_SUPPORTED"
663 << TestLog::EndMessage;
664 break;
665 default:
666 log << TestLog::Message << subcase.str()
667 << "Fail because vkGetPhysicalDeviceImageFormatProperties returned " << getResultStr(propertiesResult)
668 << TestLog::EndMessage;
669 return tcu::TestStatus::fail("Unexpected result from vkGetPhysicalDeviceImageFormatProperties");
670 }
671 }
672
673 return tcu::TestStatus::pass("No sub-case failed");
674 }
675
676 template <typename T>
HandleToInt(T t)677 static uint64_t HandleToInt(T t)
678 {
679 return t.getInternal();
680 }
681
createSwapchainPrivateDataTest(Context & context,TestParameters params)682 tcu::TestStatus createSwapchainPrivateDataTest(Context &context, TestParameters params)
683 {
684 if (!context.getPrivateDataFeatures().privateData)
685 TCU_THROW(NotSupportedError, "privateData not supported");
686
687 tcu::TestLog &log = context.getTestContext().getLog();
688 const InstanceHelper instHelper(context, params.wsiType);
689 const NativeObjects native(context, instHelper.supportedExtensions, params.wsiType);
690 const Unique<VkSurfaceKHR> surface(createSurface(instHelper.vki, instHelper.instance, params.wsiType,
691 native.getDisplay(), native.getWindow(),
692 context.getTestContext().getCommandLine()));
693 const vector<string> extraExts(1u, "VK_EXT_private_data");
694 const MultiQueueDeviceHelper devHelper(context, instHelper.vki, instHelper.instance, *surface, extraExts);
695 const vector<VkSwapchainCreateInfoKHR> cases(generateSwapchainParameterCases(
696 params.wsiType, params.dimension, instHelper.vki, devHelper.physicalDevice, *surface));
697
698 for (size_t caseNdx = 0; caseNdx < cases.size(); ++caseNdx)
699 {
700 std::ostringstream subcase;
701 subcase << "Sub-case " << (caseNdx + 1) << " / " << cases.size() << ": ";
702
703 VkSwapchainCreateInfoKHR curParams = cases[caseNdx];
704
705 if (curParams.imageSharingMode == VK_SHARING_MODE_CONCURRENT)
706 {
707 const uint32_t numFamilies = static_cast<uint32_t>(devHelper.queueFamilyIndices.size());
708 if (numFamilies < 2u)
709 TCU_THROW(NotSupportedError, "Only " + de::toString(numFamilies) +
710 " queue families available for VK_SHARING_MODE_CONCURRENT");
711 curParams.queueFamilyIndexCount = numFamilies;
712 }
713 else
714 {
715 // Take only the first queue.
716 if (devHelper.queueFamilyIndices.empty())
717 TCU_THROW(NotSupportedError, "No queue families compatible with the given surface");
718 curParams.queueFamilyIndexCount = 1u;
719 }
720 curParams.pQueueFamilyIndices = devHelper.queueFamilyIndices.data();
721 curParams.surface = *surface;
722
723 log << TestLog::Message << subcase.str() << curParams << TestLog::EndMessage;
724
725 // The Vulkan 1.1.87 spec contains the following VU for VkSwapchainCreateInfoKHR:
726 //
727 // * imageFormat, imageUsage, imageExtent, and imageArrayLayers must be supported for VK_IMAGE_TYPE_2D
728 // VK_IMAGE_TILING_OPTIMAL images as reported by vkGetPhysicalDeviceImageFormatProperties.
729 VkImageFormatProperties properties;
730 const VkResult propertiesResult = instHelper.vki.getPhysicalDeviceImageFormatProperties(
731 devHelper.physicalDevice, curParams.imageFormat, VK_IMAGE_TYPE_2D, VK_IMAGE_TILING_OPTIMAL,
732 curParams.imageUsage,
733 0, // flags
734 &properties);
735
736 log << TestLog::Message << subcase.str() << "vkGetPhysicalDeviceImageFormatProperties => "
737 << getResultStr(propertiesResult) << TestLog::EndMessage;
738
739 switch (propertiesResult)
740 {
741 case VK_SUCCESS:
742 {
743 const Unique<VkSwapchainKHR> swapchain(createSwapchainKHR(devHelper.vkd, *devHelper.device, &curParams));
744
745 const int numSlots = 100;
746 typedef Unique<VkPrivateDataSlotEXT> PrivateDataSlotUp;
747 typedef SharedPtr<PrivateDataSlotUp> PrivateDataSlotSp;
748 vector<PrivateDataSlotSp> slots;
749
750 const VkPrivateDataSlotCreateInfoEXT createInfo = {
751 VK_STRUCTURE_TYPE_PRIVATE_DATA_SLOT_CREATE_INFO_EXT, // VkStructureType sType;
752 DE_NULL, // const void* pNext;
753 0u, // VkPrivateDataSlotCreateFlagsEXT flags;
754 };
755
756 for (int i = 0; i < numSlots; ++i)
757 {
758 Move<VkPrivateDataSlotEXT> s =
759 createPrivateDataSlot(devHelper.vkd, *devHelper.device, &createInfo, DE_NULL);
760 slots.push_back(PrivateDataSlotSp(new PrivateDataSlotUp(s)));
761 }
762
763 // Based on code in vktApiObjectManagementTests.cpp
764 for (int r = 0; r < 3; ++r)
765 {
766 uint64_t data;
767
768 for (int i = 0; i < numSlots; ++i)
769 {
770 data = 1234;
771 devHelper.vkd.getPrivateData(*devHelper.device, getObjectType<VkSwapchainKHR>(),
772 HandleToInt(swapchain.get()), **slots[i], &data);
773 // Don't test default value of zero on Android, due to spec erratum
774 if (params.wsiType != TYPE_ANDROID)
775 {
776 if (data != 0)
777 return tcu::TestStatus::fail("Expected initial value of zero");
778 }
779 }
780
781 for (int i = 0; i < numSlots; ++i)
782 VK_CHECK(devHelper.vkd.setPrivateData(*devHelper.device, getObjectType<VkSwapchainKHR>(),
783 HandleToInt(swapchain.get()), **slots[i], i * i * i + 1));
784
785 for (int i = 0; i < numSlots; ++i)
786 {
787 data = 1234;
788 devHelper.vkd.getPrivateData(*devHelper.device, getObjectType<VkSwapchainKHR>(),
789 HandleToInt(swapchain.get()), **slots[i], &data);
790 if (data != (uint64_t)(i * i * i + 1))
791 return tcu::TestStatus::fail("Didn't read back set value");
792 }
793
794 // Destroy and realloc slots for the next iteration
795 slots.clear();
796 for (int i = 0; i < numSlots; ++i)
797 {
798 Move<VkPrivateDataSlotEXT> s =
799 createPrivateDataSlot(devHelper.vkd, *devHelper.device, &createInfo, DE_NULL);
800 slots.push_back(PrivateDataSlotSp(new PrivateDataSlotUp(s)));
801 }
802 }
803 }
804 break;
805 case VK_ERROR_FORMAT_NOT_SUPPORTED:
806 log << TestLog::Message << subcase.str()
807 << "Skip because vkGetPhysicalDeviceImageFormatProperties returned VK_ERROR_FORMAT_NOT_SUPPORTED"
808 << TestLog::EndMessage;
809 break;
810 default:
811 log << TestLog::Message << subcase.str()
812 << "Fail because vkGetPhysicalDeviceImageFormatProperties returned " << getResultStr(propertiesResult)
813 << TestLog::EndMessage;
814 return tcu::TestStatus::fail("Unexpected result from vkGetPhysicalDeviceImageFormatProperties");
815 }
816 }
817
818 return tcu::TestStatus::pass("No sub-case failed");
819 }
820
createSwapchainSimulateOOMTest(Context & context,TestParameters params)821 tcu::TestStatus createSwapchainSimulateOOMTest(Context &context, TestParameters params)
822 {
823 const size_t maxCases = 300u;
824 const uint32_t maxAllocs = 1024u;
825
826 tcu::TestLog &log = context.getTestContext().getLog();
827 tcu::ResultCollector results(log);
828
829 AllocationCallbackRecorder allocationRecorder(getSystemAllocator());
830 DeterministicFailAllocator failingAllocator(allocationRecorder.getCallbacks(),
831 DeterministicFailAllocator::MODE_DO_NOT_COUNT, 0);
832 {
833 const InstanceHelper instHelper(context, params.wsiType, failingAllocator.getCallbacks());
834 const NativeObjects native(context, instHelper.supportedExtensions, params.wsiType);
835 const Unique<VkSurfaceKHR> surface(
836 createSurface(instHelper.vki, instHelper.instance, params.wsiType, native.getDisplay(), native.getWindow(),
837 context.getTestContext().getCommandLine(), failingAllocator.getCallbacks()));
838 std::vector<std::string> additionalExtensions;
839 // If driver supports VK_PRESENT_MODE_FIFO_LATEST_READY_EXT and it will used, VK_EXT_present_mode_fifo_latest_ready must be enabled
840 if (context.isDeviceFunctionalitySupported("VK_EXT_present_mode_fifo_latest_ready"))
841 {
842 additionalExtensions.push_back("VK_EXT_present_mode_fifo_latest_ready");
843 }
844 const DeviceHelper devHelper(context, instHelper.vki, instHelper.instance, *surface, additionalExtensions,
845 failingAllocator.getCallbacks());
846 const vector<VkSwapchainCreateInfoKHR> allCases(generateSwapchainParameterCases(
847 params.wsiType, params.dimension, instHelper.vki, devHelper.physicalDevice, *surface));
848 const VkSurfaceCapabilitiesKHR capabilities(
849 getPhysicalDeviceSurfaceCapabilities(instHelper.vki, devHelper.physicalDevice, *surface));
850
851 if (maxCases < allCases.size())
852 log << TestLog::Message << "Note: Will only test first " << maxCases << " cases out of total of "
853 << allCases.size() << " parameter combinations" << TestLog::EndMessage;
854
855 for (size_t caseNdx = 0; caseNdx < de::min(maxCases, allCases.size()); ++caseNdx)
856 {
857 log << TestLog::Message << "Testing parameter case " << caseNdx << ": " << allCases[caseNdx]
858 << TestLog::EndMessage;
859
860 for (uint32_t numPassingAllocs = 0; numPassingAllocs <= maxAllocs; ++numPassingAllocs)
861 {
862 bool gotOOM = false;
863 VkSwapchainCreateInfoKHR curParams = allCases[caseNdx];
864 curParams.surface = *surface;
865 curParams.queueFamilyIndexCount = 1u;
866 curParams.pQueueFamilyIndices = &devHelper.queueFamilyIndex;
867
868 failingAllocator.reset(DeterministicFailAllocator::MODE_COUNT_AND_FAIL, numPassingAllocs);
869
870 log << TestLog::Message << "Testing with " << numPassingAllocs << " first allocations succeeding"
871 << TestLog::EndMessage;
872
873 try
874 {
875 // With concurrent sharing mode, at least two queues are needed.
876 if (curParams.imageSharingMode == VK_SHARING_MODE_CONCURRENT)
877 continue;
878
879 #if (DE_OS == DE_OS_ANDROID)
880 // Give some extra time to deallocate memory from previous createSwapchainKHR calls with large dimensions on Android.
881 // 15ms was decided to be the safest amount of time, otherwise test may crash with an OOM issue.
882 constexpr uint32_t sleepInMs = 15;
883
884 if (params.dimension == TEST_DIMENSION_MIN_IMAGE_COUNT)
885 {
886 std::this_thread::sleep_for(std::chrono::milliseconds(sleepInMs));
887 }
888 #endif
889
890 const Unique<VkSwapchainKHR> swapchain(createSwapchainKHR(
891 devHelper.vkd, *devHelper.device, &curParams, failingAllocator.getCallbacks()));
892 }
893 catch (const OutOfMemoryError &e)
894 {
895 log << TestLog::Message << "Got " << e.getError() << TestLog::EndMessage;
896 gotOOM = true;
897 }
898
899 if (!gotOOM)
900 {
901 log << TestLog::Message << "Creating swapchain succeeded!" << TestLog::EndMessage;
902
903 if (numPassingAllocs == 0)
904 results.addResult(QP_TEST_RESULT_QUALITY_WARNING, "Allocation callbacks were not used");
905
906 break;
907 }
908 else if (numPassingAllocs == maxAllocs)
909 {
910 // The maxExtents case might not be able to create the requested surface due to insufficient
911 // memory, so in this case *only* we allow the OOM exception upto maxAllocs.
912 if (params.dimension == TEST_DIMENSION_IMAGE_EXTENT &&
913 capabilities.maxImageExtent.width == curParams.imageExtent.width &&
914 capabilities.maxImageExtent.height == curParams.imageExtent.height)
915 break;
916
917 results.addResult(QP_TEST_RESULT_QUALITY_WARNING,
918 "Creating swapchain did not succeed, callback limit exceeded");
919 }
920 }
921
922 context.getTestContext().touchWatchdog();
923 }
924 }
925
926 if (!validateAndLog(log, allocationRecorder, 0u))
927 results.fail("Detected invalid system allocation callback");
928
929 return tcu::TestStatus(results.getResult(), results.getMessage());
930 }
931
testImageSwapchainCreateInfo(Context & context,Type wsiType)932 tcu::TestStatus testImageSwapchainCreateInfo(Context &context, Type wsiType)
933 {
934 const tcu::UVec2 desiredSize(256, 256);
935 const InstanceHelper instHelper(context, wsiType, vector<string>(1, string("VK_KHR_device_group_creation")));
936 const NativeObjects native(context, instHelper.supportedExtensions, wsiType, 1u, tcu::just(desiredSize));
937 const Unique<VkSurfaceKHR> surface(createSurface(instHelper.vki, instHelper.instance, wsiType, native.getDisplay(),
938 native.getWindow(), context.getTestContext().getCommandLine()));
939 const DeviceHelper devHelper(context, instHelper.vki, instHelper.instance, *surface,
940 vector<string>(1u, "VK_KHR_bind_memory2"));
941 const Extensions &deviceExtensions =
942 enumerateDeviceExtensionProperties(instHelper.vki, devHelper.physicalDevice, DE_NULL);
943
944 // structures this tests checks were added in revision 69
945 if (!isExtensionStructSupported(deviceExtensions, RequiredExtension("VK_KHR_swapchain", 69)))
946 TCU_THROW(NotSupportedError, "Required extension revision is not supported");
947
948 const VkSurfaceCapabilitiesKHR capabilities =
949 getPhysicalDeviceSurfaceCapabilities(instHelper.vki, devHelper.physicalDevice, *surface);
950 const vector<VkSurfaceFormatKHR> formats =
951 getPhysicalDeviceSurfaceFormats(instHelper.vki, devHelper.physicalDevice, *surface);
952 const PlatformProperties &platformProperties = getPlatformProperties(wsiType);
953 const VkSurfaceTransformFlagBitsKHR transform =
954 (capabilities.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) ?
955 VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR :
956 capabilities.currentTransform;
957 const uint32_t desiredImageCount = 2;
958 const VkSwapchainCreateInfoKHR swapchainInfo = {
959 VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
960 DE_NULL,
961 (VkSwapchainCreateFlagsKHR)0,
962 *surface,
963 de::clamp(desiredImageCount, capabilities.minImageCount,
964 capabilities.maxImageCount > 0 ? capabilities.maxImageCount :
965 capabilities.minImageCount + desiredImageCount),
966 formats[0].format,
967 formats[0].colorSpace,
968 (platformProperties.swapchainExtent == PlatformProperties::SWAPCHAIN_EXTENT_MUST_MATCH_WINDOW_SIZE ?
969 capabilities.currentExtent :
970 vk::makeExtent2D(desiredSize.x(), desiredSize.y())),
971 1u,
972 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
973 VK_SHARING_MODE_EXCLUSIVE,
974 0u,
975 (const uint32_t *)DE_NULL,
976 transform,
977 VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
978 VK_PRESENT_MODE_FIFO_KHR,
979 VK_FALSE, // clipped
980 (VkSwapchainKHR)0 // oldSwapchain
981 };
982
983 const Unique<VkSwapchainKHR> swapchain(createSwapchainKHR(devHelper.vkd, *devHelper.device, &swapchainInfo));
984 uint32_t numImages = 0;
985 VK_CHECK(devHelper.vkd.getSwapchainImagesKHR(*devHelper.device, *swapchain, &numImages, DE_NULL));
986 if (numImages == 0)
987 return tcu::TestStatus::pass("Pass");
988
989 VkImageSwapchainCreateInfoKHR imageSwapchainCreateInfo = {VK_STRUCTURE_TYPE_IMAGE_SWAPCHAIN_CREATE_INFO_KHR,
990 DE_NULL, *swapchain};
991
992 VkImageCreateInfo imageCreateInfo = {
993 VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
994 &imageSwapchainCreateInfo,
995 (VkImageCreateFlags)0u, // flags
996 VK_IMAGE_TYPE_2D, // imageType
997 formats[0].format, // format
998 {
999 // extent
1000 desiredSize.x(), // width
1001 desiredSize.y(), // height
1002 1u // depth
1003 },
1004 1u, // mipLevels
1005 1u, // arrayLayers
1006 VK_SAMPLE_COUNT_1_BIT, // samples
1007 VK_IMAGE_TILING_OPTIMAL, // tiling
1008 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, // usage
1009 VK_SHARING_MODE_EXCLUSIVE, // sharingMode
1010 0u, // queueFamilyIndexCount
1011 DE_NULL, // pQueueFamilyIndices
1012 VK_IMAGE_LAYOUT_UNDEFINED // initialLayout
1013 };
1014
1015 typedef vk::Unique<VkImage> UniqueImage;
1016 typedef de::SharedPtr<UniqueImage> ImageSp;
1017
1018 std::vector<ImageSp> images(numImages);
1019 std::vector<VkBindImageMemorySwapchainInfoKHR> bindImageMemorySwapchainInfo(numImages);
1020 std::vector<VkBindImageMemoryInfo> bindImageMemoryInfos(numImages);
1021
1022 for (uint32_t idx = 0; idx < numImages; ++idx)
1023 {
1024 // Create image
1025 images[idx] = ImageSp(new UniqueImage(createImage(devHelper.vkd, *devHelper.device, &imageCreateInfo)));
1026
1027 VkBindImageMemorySwapchainInfoKHR bimsInfo = {VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_SWAPCHAIN_INFO_KHR, DE_NULL,
1028 *swapchain, idx};
1029 bindImageMemorySwapchainInfo[idx] = bimsInfo;
1030
1031 VkBindImageMemoryInfo bimInfo = {
1032 VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO, &bindImageMemorySwapchainInfo[idx], **images[idx],
1033 DE_NULL, // If the pNext chain includes an instance of VkBindImageMemorySwapchainInfoKHR, memory must be VK_NULL_HANDLE
1034 0u // If swapchain <in VkBindImageMemorySwapchainInfoKHR> is not NULL, the swapchain and imageIndex are used to determine the memory that the image is bound to, instead of memory and memoryOffset.
1035 };
1036
1037 bindImageMemoryInfos[idx] = bimInfo;
1038 }
1039
1040 VK_CHECK(devHelper.vkd.bindImageMemory2(*devHelper.device, numImages, &bindImageMemoryInfos[0]));
1041
1042 return tcu::TestStatus::pass("Pass");
1043 }
1044
1045 struct GroupParameters
1046 {
1047 typedef FunctionInstance1<TestParameters>::Function Function;
1048
1049 Type wsiType;
1050 Function function;
1051
GroupParametersvkt::wsi::__anon88b80f900111::GroupParameters1052 GroupParameters(Type wsiType_, Function function_) : wsiType(wsiType_), function(function_)
1053 {
1054 }
1055
GroupParametersvkt::wsi::__anon88b80f900111::GroupParameters1056 GroupParameters(void) : wsiType(TYPE_LAST), function((Function)DE_NULL)
1057 {
1058 }
1059 };
1060
populateSwapchainGroup(tcu::TestCaseGroup * testGroup,GroupParameters params)1061 void populateSwapchainGroup(tcu::TestCaseGroup *testGroup, GroupParameters params)
1062 {
1063 for (int dimensionNdx = 0; dimensionNdx < TEST_DIMENSION_LAST; ++dimensionNdx)
1064 {
1065 const TestDimension testDimension = (TestDimension)dimensionNdx;
1066
1067 addFunctionCase(testGroup, getTestDimensionName(testDimension), params.function,
1068 TestParameters(params.wsiType, testDimension));
1069 }
1070
1071 addFunctionCase(testGroup, "image_swapchain_create_info", testImageSwapchainCreateInfo, params.wsiType);
1072 }
1073
populateSwapchainPrivateDataGroup(tcu::TestCaseGroup * testGroup,GroupParameters params)1074 void populateSwapchainPrivateDataGroup(tcu::TestCaseGroup *testGroup, GroupParameters params)
1075 {
1076 for (int dimensionNdx = 0; dimensionNdx < TEST_DIMENSION_LAST; ++dimensionNdx)
1077 {
1078 const TestDimension testDimension = (TestDimension)dimensionNdx;
1079 if (testDimension == TEST_DIMENSION_IMAGE_EXTENT)
1080 continue;
1081
1082 addFunctionCase(testGroup, getTestDimensionName(testDimension), params.function,
1083 TestParameters(params.wsiType, testDimension));
1084 }
1085 }
1086
getBasicSwapchainParameters(Type wsiType,const InstanceInterface & vki,VkPhysicalDevice physicalDevice,VkSurfaceKHR surface,const tcu::UVec2 & desiredSize,uint32_t desiredImageCount)1087 VkSwapchainCreateInfoKHR getBasicSwapchainParameters(Type wsiType, const InstanceInterface &vki,
1088 VkPhysicalDevice physicalDevice, VkSurfaceKHR surface,
1089 const tcu::UVec2 &desiredSize, uint32_t desiredImageCount)
1090 {
1091 const VkSurfaceCapabilitiesKHR capabilities = getPhysicalDeviceSurfaceCapabilities(vki, physicalDevice, surface);
1092 const vector<VkSurfaceFormatKHR> formats = getPhysicalDeviceSurfaceFormats(vki, physicalDevice, surface);
1093 const PlatformProperties &platformProperties = getPlatformProperties(wsiType);
1094 const VkSurfaceTransformFlagBitsKHR transform =
1095 (capabilities.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) ?
1096 VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR :
1097 capabilities.currentTransform;
1098 const VkSwapchainCreateInfoKHR parameters = {
1099 VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
1100 DE_NULL,
1101 (VkSwapchainCreateFlagsKHR)0,
1102 surface,
1103 de::clamp(desiredImageCount, capabilities.minImageCount,
1104 capabilities.maxImageCount > 0 ? capabilities.maxImageCount :
1105 capabilities.minImageCount + desiredImageCount),
1106 formats[0].format,
1107 formats[0].colorSpace,
1108 (platformProperties.swapchainExtent == PlatformProperties::SWAPCHAIN_EXTENT_MUST_MATCH_WINDOW_SIZE ?
1109 capabilities.currentExtent :
1110 vk::makeExtent2D(desiredSize.x(), desiredSize.y())),
1111 1u, // imageArrayLayers
1112 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
1113 VK_SHARING_MODE_EXCLUSIVE,
1114 0u,
1115 (const uint32_t *)DE_NULL,
1116 transform,
1117 VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
1118 VK_PRESENT_MODE_FIFO_KHR,
1119 VK_FALSE, // clipped
1120 (VkSwapchainKHR)0 // oldSwapchain
1121 };
1122
1123 return parameters;
1124 }
1125
1126 typedef de::SharedPtr<Unique<VkCommandBuffer>> CommandBufferSp;
1127 typedef de::SharedPtr<Unique<VkFence>> FenceSp;
1128 typedef de::SharedPtr<Unique<VkSemaphore>> SemaphoreSp;
1129
createFences(const DeviceInterface & vkd,const VkDevice device,size_t numFences,bool isSignaled=true)1130 vector<FenceSp> createFences(const DeviceInterface &vkd, const VkDevice device, size_t numFences,
1131 bool isSignaled = true)
1132 {
1133 vector<FenceSp> fences(numFences);
1134
1135 for (size_t ndx = 0; ndx < numFences; ++ndx)
1136 fences[ndx] =
1137 FenceSp(new Unique<VkFence>(createFence(vkd, device, (isSignaled) ? vk::VK_FENCE_CREATE_SIGNALED_BIT : 0)));
1138
1139 return fences;
1140 }
1141
createSemaphores(const DeviceInterface & vkd,const VkDevice device,size_t numSemaphores)1142 vector<SemaphoreSp> createSemaphores(const DeviceInterface &vkd, const VkDevice device, size_t numSemaphores)
1143 {
1144 vector<SemaphoreSp> semaphores(numSemaphores);
1145
1146 for (size_t ndx = 0; ndx < numSemaphores; ++ndx)
1147 semaphores[ndx] = SemaphoreSp(new Unique<VkSemaphore>(createSemaphore(vkd, device)));
1148
1149 return semaphores;
1150 }
1151
allocateCommandBuffers(const DeviceInterface & vkd,const VkDevice device,const VkCommandPool commandPool,const VkCommandBufferLevel level,const size_t numCommandBuffers)1152 vector<CommandBufferSp> allocateCommandBuffers(const DeviceInterface &vkd, const VkDevice device,
1153 const VkCommandPool commandPool, const VkCommandBufferLevel level,
1154 const size_t numCommandBuffers)
1155 {
1156 vector<CommandBufferSp> buffers(numCommandBuffers);
1157
1158 for (size_t ndx = 0; ndx < numCommandBuffers; ++ndx)
1159 buffers[ndx] =
1160 CommandBufferSp(new Unique<VkCommandBuffer>(allocateCommandBuffer(vkd, device, commandPool, level)));
1161
1162 return buffers;
1163 }
1164
1165 class AcquireNextImageWrapper
1166 {
1167 public:
AcquireNextImageWrapper(const DeviceInterface & vkd,VkDevice device,uint32_t deviceMask,VkSwapchainKHR swapchain,uint64_t timeout)1168 AcquireNextImageWrapper(const DeviceInterface &vkd, VkDevice device, uint32_t deviceMask, VkSwapchainKHR swapchain,
1169 uint64_t timeout)
1170 : m_vkd(vkd)
1171 , m_device(device)
1172 , m_swapchain(swapchain)
1173 , m_timeout(timeout)
1174 {
1175 DE_UNREF(deviceMask); // needed for compatibility with acquireNextImage2KHR
1176 }
1177
featureAvailable(Context &)1178 bool featureAvailable(Context &)
1179 {
1180 return true; // needed for compatibility with acquireNextImage2KHR
1181 }
1182
call(VkSemaphore semaphore,VkFence fence,uint32_t * imageIndex)1183 VkResult call(VkSemaphore semaphore, VkFence fence, uint32_t *imageIndex)
1184 {
1185 return m_vkd.acquireNextImageKHR(m_device, m_swapchain, m_timeout, semaphore, fence, imageIndex);
1186 }
1187
1188 protected:
1189 const DeviceInterface &m_vkd;
1190 VkDevice m_device;
1191 VkSwapchainKHR m_swapchain;
1192 uint64_t m_timeout;
1193 };
1194
1195 class AcquireNextImage2Wrapper
1196 {
1197 public:
AcquireNextImage2Wrapper(const DeviceInterface & vkd,VkDevice device,uint32_t deviceMask,VkSwapchainKHR swapchain,uint64_t timeout)1198 AcquireNextImage2Wrapper(const DeviceInterface &vkd, VkDevice device, uint32_t deviceMask, VkSwapchainKHR swapchain,
1199 uint64_t timeout)
1200 : m_vkd(vkd)
1201 , m_device(device)
1202 {
1203 m_info.sType = VK_STRUCTURE_TYPE_ACQUIRE_NEXT_IMAGE_INFO_KHR;
1204 m_info.pNext = DE_NULL;
1205 m_info.swapchain = swapchain;
1206 m_info.timeout = timeout;
1207 m_info.semaphore = DE_NULL;
1208 m_info.fence = DE_NULL;
1209 m_info.deviceMask = deviceMask;
1210 }
1211
featureAvailable(Context & context)1212 bool featureAvailable(Context &context)
1213 {
1214 return context.isDeviceFunctionalitySupported("VK_KHR_device_group");
1215 }
1216
call(VkSemaphore semaphore,VkFence fence,uint32_t * imageIndex)1217 VkResult call(VkSemaphore semaphore, VkFence fence, uint32_t *imageIndex)
1218 {
1219 m_info.semaphore = semaphore;
1220 m_info.fence = fence;
1221 return m_vkd.acquireNextImage2KHR(m_device, &m_info, imageIndex);
1222 }
1223
1224 protected:
1225 const DeviceInterface &m_vkd;
1226 VkDevice m_device;
1227 VkAcquireNextImageInfoKHR m_info;
1228 };
1229
1230 template <typename AcquireWrapperType>
basicRenderTest(Context & context,Type wsiType)1231 tcu::TestStatus basicRenderTest(Context &context, Type wsiType)
1232 {
1233 const tcu::UVec2 desiredSize(256, 256);
1234 const InstanceHelper instHelper(context, wsiType);
1235 const NativeObjects native(context, instHelper.supportedExtensions, wsiType, 1u, tcu::just(desiredSize));
1236 const Unique<VkSurfaceKHR> surface(createSurface(instHelper.vki, instHelper.instance, wsiType, native.getDisplay(),
1237 native.getWindow(), context.getTestContext().getCommandLine()));
1238 const DeviceHelper devHelper(context, instHelper.vki, instHelper.instance, *surface);
1239 const DeviceInterface &vkd = devHelper.vkd;
1240 const VkDevice device = *devHelper.device;
1241 SimpleAllocator allocator(vkd, device, getPhysicalDeviceMemoryProperties(instHelper.vki, devHelper.physicalDevice));
1242 const VkSwapchainCreateInfoKHR swapchainInfo =
1243 getBasicSwapchainParameters(wsiType, instHelper.vki, devHelper.physicalDevice, *surface, desiredSize, 2);
1244 const Unique<VkSwapchainKHR> swapchain(createSwapchainKHR(vkd, device, &swapchainInfo));
1245 const vector<VkImage> swapchainImages = getSwapchainImages(vkd, device, *swapchain);
1246
1247 AcquireWrapperType acquireImageWrapper(vkd, device, 1u, *swapchain, std::numeric_limits<uint64_t>::max());
1248 if (!acquireImageWrapper.featureAvailable(context))
1249 TCU_THROW(NotSupportedError, "Required extension is not supported");
1250
1251 const WsiTriangleRenderer renderer(vkd, device, allocator, context.getBinaryCollection(), false, swapchainImages,
1252 swapchainImages, swapchainInfo.imageFormat,
1253 tcu::UVec2(swapchainInfo.imageExtent.width, swapchainInfo.imageExtent.height));
1254
1255 const Unique<VkCommandPool> commandPool(
1256 createCommandPool(vkd, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, devHelper.queueFamilyIndex));
1257
1258 const size_t maxQueuedFrames = swapchainImages.size() * 2;
1259
1260 // We need to keep hold of fences from vkAcquireNextImage(2)KHR to actually
1261 // limit number of frames we allow to be queued.
1262 const vector<FenceSp> imageReadyFences(createFences(vkd, device, maxQueuedFrames));
1263
1264 // We need maxQueuedFrames+1 for imageReadySemaphores pool as we need to pass
1265 // the semaphore in same time as the fence we use to meter rendering.
1266 const vector<SemaphoreSp> imageReadySemaphores(createSemaphores(vkd, device, maxQueuedFrames + 1));
1267
1268 // For rest we simply need maxQueuedFrames as we will wait for image
1269 // from frameNdx-maxQueuedFrames to become available to us, guaranteeing that
1270 // previous uses must have completed.
1271 const vector<SemaphoreSp> renderingCompleteSemaphores(createSemaphores(vkd, device, maxQueuedFrames));
1272 const vector<CommandBufferSp> commandBuffers(
1273 allocateCommandBuffers(vkd, device, *commandPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY, maxQueuedFrames));
1274
1275 try
1276 {
1277 const uint32_t numFramesToRender = 60 * 10;
1278
1279 for (uint32_t frameNdx = 0; frameNdx < numFramesToRender; ++frameNdx)
1280 {
1281 const VkFence imageReadyFence = **imageReadyFences[frameNdx % imageReadyFences.size()];
1282 const VkSemaphore imageReadySemaphore = **imageReadySemaphores[frameNdx % imageReadySemaphores.size()];
1283 uint32_t imageNdx = ~0u;
1284
1285 VK_CHECK(vkd.waitForFences(device, 1u, &imageReadyFence, VK_TRUE, std::numeric_limits<uint64_t>::max()));
1286 VK_CHECK(vkd.resetFences(device, 1, &imageReadyFence));
1287
1288 {
1289 const VkResult acquireResult = acquireImageWrapper.call(imageReadySemaphore, (VkFence)0, &imageNdx);
1290
1291 if (acquireResult == VK_SUBOPTIMAL_KHR)
1292 context.getTestContext().getLog() << TestLog::Message << "Got " << acquireResult << " at frame "
1293 << frameNdx << TestLog::EndMessage;
1294 else
1295 VK_CHECK(acquireResult);
1296 }
1297
1298 TCU_CHECK((size_t)imageNdx < swapchainImages.size());
1299
1300 {
1301 const VkSemaphore renderingCompleteSemaphore =
1302 **renderingCompleteSemaphores[frameNdx % renderingCompleteSemaphores.size()];
1303 const VkCommandBuffer commandBuffer = **commandBuffers[frameNdx % commandBuffers.size()];
1304 const VkPipelineStageFlags waitDstStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
1305 const VkSubmitInfo submitInfo = {VK_STRUCTURE_TYPE_SUBMIT_INFO,
1306 DE_NULL,
1307 1u,
1308 &imageReadySemaphore,
1309 &waitDstStage,
1310 1u,
1311 &commandBuffer,
1312 1u,
1313 &renderingCompleteSemaphore};
1314 const VkPresentInfoKHR presentInfo = {VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
1315 DE_NULL,
1316 1u,
1317 &renderingCompleteSemaphore,
1318 1u,
1319 &*swapchain,
1320 &imageNdx,
1321 (VkResult *)DE_NULL};
1322
1323 renderer.recordFrame(commandBuffer, imageNdx, frameNdx);
1324 VK_CHECK(vkd.queueSubmit(devHelper.queue, 1u, &submitInfo, imageReadyFence));
1325 VK_CHECK_WSI(vkd.queuePresentKHR(devHelper.queue, &presentInfo));
1326 }
1327 }
1328
1329 VK_CHECK(vkd.deviceWaitIdle(device));
1330 }
1331 catch (...)
1332 {
1333 // Make sure device is idle before destroying resources
1334 vkd.deviceWaitIdle(device);
1335 throw;
1336 }
1337
1338 return tcu::TestStatus::pass("Rendering tests succeeded");
1339 }
1340
1341 class FrameStreamObjects
1342 {
1343 public:
1344 struct FrameObjects
1345 {
1346 const vk::VkFence &renderCompleteFence;
1347 const vk::VkSemaphore &renderCompleteSemaphore;
1348 const vk::VkSemaphore &imageAvailableSemaphore;
1349 const vk::VkCommandBuffer &commandBuffer;
1350 };
1351
FrameStreamObjects(const vk::DeviceInterface & vkd,vk::VkDevice device,vk::VkCommandPool cmdPool,size_t maxQueuedFrames)1352 FrameStreamObjects(const vk::DeviceInterface &vkd, vk::VkDevice device, vk::VkCommandPool cmdPool,
1353 size_t maxQueuedFrames)
1354 : renderingCompleteFences(createFences(vkd, device, maxQueuedFrames))
1355 , renderingCompleteSemaphores(createSemaphores(vkd, device, maxQueuedFrames))
1356 , imageAvailableSemaphores(createSemaphores(vkd, device, maxQueuedFrames))
1357 , commandBuffers(
1358 allocateCommandBuffers(vkd, device, cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY, maxQueuedFrames))
1359 , m_maxQueuedFrames(maxQueuedFrames)
1360 , m_nextFrame(0u)
1361 {
1362 }
1363
frameNumber(void) const1364 size_t frameNumber(void) const
1365 {
1366 DE_ASSERT(m_nextFrame > 0u);
1367 return m_nextFrame - 1u;
1368 }
1369
newFrame()1370 FrameObjects newFrame()
1371 {
1372 const size_t mod = m_nextFrame % m_maxQueuedFrames;
1373 FrameObjects ret = {
1374 **renderingCompleteFences[mod],
1375 **renderingCompleteSemaphores[mod],
1376 **imageAvailableSemaphores[mod],
1377 **commandBuffers[mod],
1378 };
1379 ++m_nextFrame;
1380 return ret;
1381 }
1382
1383 private:
1384 const vector<FenceSp> renderingCompleteFences;
1385 const vector<SemaphoreSp> renderingCompleteSemaphores;
1386 const vector<SemaphoreSp> imageAvailableSemaphores;
1387 const vector<CommandBufferSp> commandBuffers;
1388
1389 const size_t m_maxQueuedFrames;
1390 size_t m_nextFrame;
1391 };
1392
1393 struct MultiSwapchainParams
1394 {
1395 Type wsiType;
1396 size_t swapchainCount;
1397 };
1398
1399 struct AccumulatedPresentInfo
1400 {
1401 vector<VkSemaphore> semaphores;
1402 vector<VkSwapchainKHR> swapchains;
1403 vector<uint32_t> imageIndices;
1404
AccumulatedPresentInfovkt::wsi::__anon88b80f900111::AccumulatedPresentInfo1405 AccumulatedPresentInfo() : semaphores(), swapchains(), imageIndices()
1406 {
1407 }
1408
push_backvkt::wsi::__anon88b80f900111::AccumulatedPresentInfo1409 void push_back(VkSemaphore sem, VkSwapchainKHR sc, uint32_t index)
1410 {
1411 semaphores.push_back(sem);
1412 swapchains.push_back(sc);
1413 imageIndices.push_back(index);
1414 }
1415
resetvkt::wsi::__anon88b80f900111::AccumulatedPresentInfo1416 void reset()
1417 {
1418 semaphores.resize(0);
1419 swapchains.resize(0);
1420 imageIndices.resize(0);
1421 }
1422
sizevkt::wsi::__anon88b80f900111::AccumulatedPresentInfo1423 size_t size() const
1424 {
1425 // Any of the vectors would do.
1426 return semaphores.size();
1427 }
1428 };
1429
1430 template <typename AcquireWrapperType>
multiSwapchainRenderTest(Context & context,MultiSwapchainParams params)1431 tcu::TestStatus multiSwapchainRenderTest(Context &context, MultiSwapchainParams params)
1432 {
1433 DE_ASSERT(params.swapchainCount > 0);
1434 const PlatformProperties &platformProperties = getPlatformProperties(params.wsiType);
1435 if (params.swapchainCount > platformProperties.maxWindowsPerDisplay)
1436 {
1437 std::ostringstream msg;
1438 msg << "Creating " << params.swapchainCount << " windows not supported";
1439 TCU_THROW(NotSupportedError, msg.str());
1440 }
1441
1442 const tcu::UVec2 desiredSize(256, 256);
1443 const InstanceHelper instHelper(context, params.wsiType);
1444
1445 // Create native window system objects, surfaces and helper surface vector.
1446 std::unique_ptr<NativeObjects> native;
1447 try
1448 {
1449 native.reset(new NativeObjects(context, instHelper.supportedExtensions, params.wsiType, params.swapchainCount,
1450 tcu::just(desiredSize)));
1451 }
1452 catch (tcu::ResourceError &)
1453 {
1454 std::ostringstream msg;
1455 msg << "Unable to create " << params.swapchainCount << " windows";
1456 TCU_THROW(NotSupportedError, msg.str());
1457 }
1458
1459 vector<Move<VkSurfaceKHR>> surface;
1460 vector<VkSurfaceKHR> surfaceKHR; // The plain Vulkan objects from the vector above.
1461
1462 for (size_t i = 0; i < params.swapchainCount; ++i)
1463 {
1464 surface.emplace_back(createSurface(instHelper.vki, instHelper.instance, params.wsiType, native->getDisplay(),
1465 native->getWindow(i), context.getTestContext().getCommandLine()));
1466 surfaceKHR.push_back(surface.back().get());
1467 }
1468
1469 // Create a device compatible with all surfaces.
1470 const DeviceHelper devHelper(context, instHelper.vki, instHelper.instance, surfaceKHR);
1471 const DeviceInterface &vkd = devHelper.vkd;
1472 const VkDevice device = *devHelper.device;
1473 SimpleAllocator allocator(vkd, device, getPhysicalDeviceMemoryProperties(instHelper.vki, devHelper.physicalDevice));
1474
1475 // Create several swapchains and images.
1476 vector<VkSwapchainCreateInfoKHR> swapchainInfo;
1477 vector<Move<VkSwapchainKHR>> swapchain;
1478 vector<vector<VkImage>> swapchainImages;
1479 vector<AcquireWrapperType> acquireImageWrapper;
1480 for (size_t i = 0; i < params.swapchainCount; ++i)
1481 {
1482 swapchainInfo.emplace_back(getBasicSwapchainParameters(params.wsiType, instHelper.vki, devHelper.physicalDevice,
1483 *surface[i], desiredSize, 2));
1484 swapchain.emplace_back(createSwapchainKHR(vkd, device, &swapchainInfo.back()));
1485 swapchainImages.emplace_back(getSwapchainImages(vkd, device, swapchain.back().get()));
1486 acquireImageWrapper.emplace_back(vkd, device, 1u, swapchain.back().get(), std::numeric_limits<uint64_t>::max());
1487 }
1488
1489 // Every acquire wrapper requires the same features, so we only check the first one.
1490 if (!acquireImageWrapper.front().featureAvailable(context))
1491 TCU_THROW(NotSupportedError, "Required extension is not supported");
1492
1493 // Renderer per swapchain.
1494 vector<WsiTriangleRenderer> renderer;
1495 for (size_t i = 0; i < params.swapchainCount; ++i)
1496 {
1497 renderer.emplace_back(vkd, device, allocator, context.getBinaryCollection(), false, swapchainImages[i],
1498 swapchainImages[i], swapchainInfo[i].imageFormat,
1499 tcu::UVec2(swapchainInfo[i].imageExtent.width, swapchainInfo[i].imageExtent.height));
1500 }
1501
1502 const Unique<VkCommandPool> commandPool(
1503 createCommandPool(vkd, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, devHelper.queueFamilyIndex));
1504 const size_t maxQueuedFrames = swapchainImages.front().size() * 2; // Limit in-flight frames.
1505
1506 vector<FrameStreamObjects> frameStreamObjects;
1507 for (size_t i = 0; i < params.swapchainCount; ++i)
1508 frameStreamObjects.emplace_back(vkd, device, commandPool.get(), maxQueuedFrames);
1509
1510 try
1511 {
1512 // 3 seconds for 60 Hz screens.
1513 const uint32_t kNumFramesToRender = 60 * 3 * static_cast<uint32_t>(params.swapchainCount);
1514 AccumulatedPresentInfo accumulatedPresentInfo;
1515
1516 for (size_t frameNdx = 0; frameNdx < kNumFramesToRender; ++frameNdx)
1517 {
1518 size_t swapchainIndex = frameNdx % params.swapchainCount;
1519 auto &fsObjects = frameStreamObjects[swapchainIndex];
1520 auto frameObjects = fsObjects.newFrame();
1521 uint32_t imageNdx = std::numeric_limits<uint32_t>::max();
1522
1523 VK_CHECK(vkd.waitForFences(device, 1u, &frameObjects.renderCompleteFence, VK_TRUE,
1524 std::numeric_limits<uint64_t>::max()));
1525 VK_CHECK(vkd.resetFences(device, 1u, &frameObjects.renderCompleteFence));
1526
1527 {
1528 const VkResult acquireResult = acquireImageWrapper[swapchainIndex].call(
1529 frameObjects.imageAvailableSemaphore, (VkFence)DE_NULL, &imageNdx);
1530 if (acquireResult == VK_SUBOPTIMAL_KHR)
1531 context.getTestContext().getLog() << TestLog::Message << "Got " << acquireResult << " at frame "
1532 << frameNdx << TestLog::EndMessage;
1533 else
1534 VK_CHECK(acquireResult);
1535 }
1536
1537 TCU_CHECK(static_cast<size_t>(imageNdx) < swapchainImages[swapchainIndex].size());
1538
1539 {
1540 const VkPipelineStageFlags waitDstStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
1541 const VkSubmitInfo submitInfo = {
1542 VK_STRUCTURE_TYPE_SUBMIT_INFO,
1543 DE_NULL,
1544 1u,
1545 &frameObjects.imageAvailableSemaphore,
1546 &waitDstStage,
1547 1u,
1548 &frameObjects.commandBuffer,
1549 1u,
1550 &frameObjects.renderCompleteSemaphore,
1551 };
1552
1553 renderer[swapchainIndex].recordFrame(frameObjects.commandBuffer, imageNdx,
1554 static_cast<uint32_t>(frameNdx));
1555 VK_CHECK(vkd.queueSubmit(devHelper.queue, 1u, &submitInfo, frameObjects.renderCompleteFence));
1556
1557 // Save present information for the current frame.
1558 accumulatedPresentInfo.push_back(frameObjects.renderCompleteSemaphore, swapchain[swapchainIndex].get(),
1559 imageNdx);
1560
1561 // Present frames when we have accumulated one frame per swapchain.
1562 if (accumulatedPresentInfo.size() == params.swapchainCount)
1563 {
1564 DE_ASSERT(accumulatedPresentInfo.semaphores.size() == accumulatedPresentInfo.swapchains.size() &&
1565 accumulatedPresentInfo.semaphores.size() == accumulatedPresentInfo.imageIndices.size());
1566
1567 vector<VkResult> results(params.swapchainCount, VK_ERROR_DEVICE_LOST);
1568
1569 const VkPresentInfoKHR presentInfo = {
1570 VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
1571 DE_NULL,
1572 static_cast<uint32_t>(accumulatedPresentInfo.semaphores.size()),
1573 accumulatedPresentInfo.semaphores.data(),
1574 static_cast<uint32_t>(accumulatedPresentInfo.swapchains.size()),
1575 accumulatedPresentInfo.swapchains.data(),
1576 accumulatedPresentInfo.imageIndices.data(),
1577 results.data(),
1578 };
1579
1580 // Check both the global result and the individual results.
1581 VK_CHECK_WSI(vkd.queuePresentKHR(devHelper.queue, &presentInfo));
1582 for (const auto &result : results)
1583 VK_CHECK_WSI(result);
1584
1585 accumulatedPresentInfo.reset();
1586 }
1587 }
1588 }
1589
1590 VK_CHECK(vkd.deviceWaitIdle(device));
1591 }
1592 catch (...)
1593 {
1594 // Make sure device is idle before destroying resources
1595 vkd.deviceWaitIdle(device);
1596 throw;
1597 }
1598
1599 return tcu::TestStatus::pass("Rendering tests succeeded");
1600 }
1601
deviceGroupRenderTest(Context & context,Type wsiType)1602 tcu::TestStatus deviceGroupRenderTest(Context &context, Type wsiType)
1603 {
1604 const InstanceHelper instHelper(context, wsiType, vector<string>(1, string("VK_KHR_device_group_creation")));
1605 const tcu::CommandLine &cmdLine = context.getTestContext().getCommandLine();
1606 VkPhysicalDevice physicalDevice = chooseDevice(instHelper.vki, instHelper.instance, cmdLine);
1607 const Extensions &supportedExtensions = enumerateDeviceExtensionProperties(instHelper.vki, physicalDevice, DE_NULL);
1608
1609 std::vector<const char *> deviceExtensions;
1610 deviceExtensions.push_back("VK_KHR_swapchain");
1611 if (!isCoreDeviceExtension(context.getUsedApiVersion(), "VK_KHR_device_group"))
1612 deviceExtensions.push_back("VK_KHR_device_group");
1613
1614 for (std::size_t ndx = 0; ndx < deviceExtensions.size(); ++ndx)
1615 {
1616 if (!isExtensionStructSupported(supportedExtensions, RequiredExtension(deviceExtensions[ndx])))
1617 TCU_THROW(NotSupportedError, (string(deviceExtensions[ndx]) + " is not supported").c_str());
1618 }
1619
1620 const tcu::UVec2 desiredSize(256, 256);
1621 const NativeObjects native(context, instHelper.supportedExtensions, wsiType, 1u, tcu::just(desiredSize));
1622 const Unique<VkSurfaceKHR> surface(createSurface(instHelper.vki, instHelper.instance, wsiType, native.getDisplay(),
1623 native.getWindow(), context.getTestContext().getCommandLine()));
1624
1625 const uint32_t devGroupIdx = cmdLine.getVKDeviceGroupId() - 1;
1626 const uint32_t deviceIdx = context.getTestContext().getCommandLine().getVKDeviceId() - 1u;
1627 const vector<VkPhysicalDeviceGroupProperties> deviceGroupProps =
1628 enumeratePhysicalDeviceGroups(instHelper.vki, instHelper.instance);
1629 uint32_t physicalDevicesInGroupCount = deviceGroupProps[devGroupIdx].physicalDeviceCount;
1630 const VkPhysicalDevice *physicalDevicesInGroup = deviceGroupProps[devGroupIdx].physicalDevices;
1631 uint32_t queueFamilyIndex = chooseQueueFamilyIndex(instHelper.vki, physicalDevicesInGroup[deviceIdx], *surface);
1632 const std::vector<VkQueueFamilyProperties> queueProps =
1633 getPhysicalDeviceQueueFamilyProperties(instHelper.vki, physicalDevicesInGroup[deviceIdx]);
1634 const float queuePriority = 1.0f;
1635 const uint32_t firstDeviceID = 0;
1636 const uint32_t secondDeviceID = 1;
1637
1638 // create a device group
1639 const VkDeviceGroupDeviceCreateInfo groupDeviceInfo = {
1640 VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO_KHR, // stype
1641 DE_NULL, // pNext
1642 physicalDevicesInGroupCount, // physicalDeviceCount
1643 physicalDevicesInGroup // physicalDevices
1644 };
1645 const VkDeviceQueueCreateInfo deviceQueueCreateInfo = {
1646 VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, // type
1647 DE_NULL, // pNext
1648 (VkDeviceQueueCreateFlags)0u, // flags
1649 queueFamilyIndex, // queueFamilyIndex
1650 1u, // queueCount
1651 &queuePriority, // pQueuePriorities
1652 };
1653
1654 const VkDeviceCreateInfo deviceCreateInfo = {
1655 VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, // sType
1656 &groupDeviceInfo, // pNext
1657 (VkDeviceCreateFlags)0u, // flags
1658 1, // queueRecordCount
1659 &deviceQueueCreateInfo, // pRequestedQueues
1660 0, // layerCount
1661 DE_NULL, // ppEnabledLayerNames
1662 uint32_t(deviceExtensions.size()), // enabledExtensionCount
1663 &deviceExtensions[0], // ppEnabledExtensionNames
1664 DE_NULL, // pEnabledFeatures
1665 };
1666
1667 Move<VkDevice> groupDevice = createCustomDevice(context.getTestContext().getCommandLine().isValidationEnabled(),
1668 context.getPlatformInterface(), instHelper.instance, instHelper.vki,
1669 physicalDevicesInGroup[deviceIdx], &deviceCreateInfo);
1670 const DeviceDriver vkd(context.getPlatformInterface(), instHelper.instance, *groupDevice,
1671 context.getUsedApiVersion(), context.getTestContext().getCommandLine());
1672 VkQueue queue(getDeviceQueue(vkd, *groupDevice, queueFamilyIndex, 0));
1673 SimpleAllocator allocator(vkd, *groupDevice,
1674 getPhysicalDeviceMemoryProperties(instHelper.vki, physicalDevicesInGroup[deviceIdx]));
1675
1676 // create swapchain for device group
1677 VkDeviceGroupSwapchainCreateInfoKHR deviceGroupSwapchainInfo = initVulkanStructure();
1678 deviceGroupSwapchainInfo.modes = VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_BIT_KHR;
1679
1680 VkSwapchainCreateInfoKHR swapchainInfo = getBasicSwapchainParameters(
1681 wsiType, instHelper.vki, physicalDevicesInGroup[deviceIdx], *surface, desiredSize, 2);
1682 swapchainInfo.pNext = &deviceGroupSwapchainInfo;
1683
1684 const Unique<VkSwapchainKHR> swapchain(createSwapchainKHR(vkd, *groupDevice, &swapchainInfo));
1685 const vector<VkImage> swapchainImages = getSwapchainImages(vkd, *groupDevice, *swapchain);
1686
1687 const WsiTriangleRenderer renderer(vkd, *groupDevice, allocator, context.getBinaryCollection(), false,
1688 swapchainImages, swapchainImages, swapchainInfo.imageFormat,
1689 tcu::UVec2(swapchainInfo.imageExtent.width, swapchainInfo.imageExtent.height));
1690
1691 const Unique<VkCommandPool> commandPool(
1692 createCommandPool(vkd, *groupDevice, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
1693
1694 const size_t maxQueuedFrames = swapchainImages.size() * 2;
1695
1696 // We need to keep hold of fences from vkAcquireNextImage2KHR
1697 // to actually limit number of frames we allow to be queued.
1698 const vector<FenceSp> imageReadyFences(createFences(vkd, *groupDevice, maxQueuedFrames));
1699
1700 // We need maxQueuedFrames+1 for imageReadySemaphores pool as we need to
1701 // pass the semaphore in same time as the fence we use to meter rendering.
1702 const vector<SemaphoreSp> imageReadySemaphores(createSemaphores(vkd, *groupDevice, maxQueuedFrames + 1));
1703
1704 // For rest we simply need maxQueuedFrames as we will wait for image from frameNdx-maxQueuedFrames
1705 // to become available to us, guaranteeing that previous uses must have completed.
1706 const vector<SemaphoreSp> renderingCompleteSemaphores(createSemaphores(vkd, *groupDevice, maxQueuedFrames));
1707 const vector<CommandBufferSp> commandBuffers(
1708 allocateCommandBuffers(vkd, *groupDevice, *commandPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY, maxQueuedFrames));
1709
1710 try
1711 {
1712 const uint32_t numFramesToRender = 60 * 10;
1713
1714 for (uint32_t frameNdx = 0; frameNdx < numFramesToRender; ++frameNdx)
1715 {
1716 const VkFence imageReadyFence = **imageReadyFences[frameNdx % imageReadyFences.size()];
1717 const VkSemaphore imageReadySemaphore = **imageReadySemaphores[frameNdx % imageReadySemaphores.size()];
1718 uint32_t imageNdx = ~0u;
1719
1720 VK_CHECK(
1721 vkd.waitForFences(*groupDevice, 1u, &imageReadyFence, VK_TRUE, std::numeric_limits<uint64_t>::max()));
1722 VK_CHECK(vkd.resetFences(*groupDevice, 1, &imageReadyFence));
1723
1724 {
1725 VkAcquireNextImageInfoKHR acquireNextImageInfo = {VK_STRUCTURE_TYPE_ACQUIRE_NEXT_IMAGE_INFO_KHR,
1726 DE_NULL,
1727 *swapchain,
1728 std::numeric_limits<uint64_t>::max(),
1729 imageReadySemaphore,
1730 (VkFence)0,
1731 (1 << firstDeviceID)};
1732
1733 const VkResult acquireResult = vkd.acquireNextImage2KHR(*groupDevice, &acquireNextImageInfo, &imageNdx);
1734
1735 if (acquireResult == VK_SUBOPTIMAL_KHR)
1736 context.getTestContext().getLog() << TestLog::Message << "Got " << acquireResult << " at frame "
1737 << frameNdx << TestLog::EndMessage;
1738 else
1739 VK_CHECK(acquireResult);
1740 }
1741
1742 TCU_CHECK((size_t)imageNdx < swapchainImages.size());
1743
1744 {
1745 const VkSemaphore renderingCompleteSemaphore =
1746 **renderingCompleteSemaphores[frameNdx % renderingCompleteSemaphores.size()];
1747 const VkCommandBuffer commandBuffer = **commandBuffers[frameNdx % commandBuffers.size()];
1748 const VkPipelineStageFlags waitDstStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
1749
1750 // render triangle using one or two subdevices when available
1751 renderer.recordDeviceGroupFrame(commandBuffer, firstDeviceID, secondDeviceID,
1752 physicalDevicesInGroupCount, imageNdx, frameNdx);
1753
1754 // submit queue
1755 uint32_t deviceMask = (1 << firstDeviceID);
1756 std::vector<uint32_t> deviceIndices(1, firstDeviceID);
1757 if (physicalDevicesInGroupCount > 1)
1758 {
1759 deviceMask |= (1 << secondDeviceID);
1760 deviceIndices.push_back(secondDeviceID);
1761 }
1762 const VkDeviceGroupSubmitInfo deviceGroupSubmitInfo = {
1763 VK_STRUCTURE_TYPE_DEVICE_GROUP_SUBMIT_INFO_KHR, // sType
1764 DE_NULL, // pNext
1765 uint32_t(deviceIndices.size()), // waitSemaphoreCount
1766 &deviceIndices[0], // pWaitSemaphoreDeviceIndices
1767 1u, // commandBufferCount
1768 &deviceMask, // pCommandBufferDeviceMasks
1769 uint32_t(deviceIndices.size()), // signalSemaphoreCount
1770 &deviceIndices[0], // pSignalSemaphoreDeviceIndices
1771 };
1772 const VkSubmitInfo submitInfo = {
1773 VK_STRUCTURE_TYPE_SUBMIT_INFO, // sType
1774 &deviceGroupSubmitInfo, // pNext
1775 1u, // waitSemaphoreCount
1776 &imageReadySemaphore, // pWaitSemaphores
1777 &waitDstStage, // pWaitDstStageMask
1778 1u, // commandBufferCount
1779 &commandBuffer, // pCommandBuffers
1780 1u, // signalSemaphoreCount
1781 &renderingCompleteSemaphore, // pSignalSemaphores
1782 };
1783 VK_CHECK(vkd.queueSubmit(queue, 1u, &submitInfo, imageReadyFence));
1784
1785 // present swapchain image
1786 deviceMask = (1 << firstDeviceID);
1787 const VkDeviceGroupPresentInfoKHR deviceGroupPresentInfo = {
1788 VK_STRUCTURE_TYPE_DEVICE_GROUP_PRESENT_INFO_KHR, DE_NULL, 1u, &deviceMask,
1789 VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_BIT_KHR,
1790 };
1791 const VkPresentInfoKHR presentInfo = {VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
1792 &deviceGroupPresentInfo,
1793 1u,
1794 &renderingCompleteSemaphore,
1795 1u,
1796 &*swapchain,
1797 &imageNdx,
1798 (VkResult *)DE_NULL};
1799 VK_CHECK_WSI(vkd.queuePresentKHR(queue, &presentInfo));
1800 }
1801 }
1802
1803 VK_CHECK(vkd.deviceWaitIdle(*groupDevice));
1804 }
1805 catch (...)
1806 {
1807 // Make sure device is idle before destroying resources
1808 vkd.deviceWaitIdle(*groupDevice);
1809 throw;
1810 }
1811
1812 return tcu::TestStatus::pass("Rendering tests succeeded");
1813 }
1814
deviceGroupRenderTest2(Context & context,Type wsiType)1815 tcu::TestStatus deviceGroupRenderTest2(Context &context, Type wsiType)
1816 {
1817 const InstanceHelper instHelper(context, wsiType, vector<string>(1, string("VK_KHR_device_group_creation")));
1818 const tcu::CommandLine &cmdLine = context.getTestContext().getCommandLine();
1819 VkPhysicalDevice physicalDevice = chooseDevice(instHelper.vki, instHelper.instance, cmdLine);
1820 const Extensions &deviceExtensions = enumerateDeviceExtensionProperties(instHelper.vki, physicalDevice, DE_NULL);
1821
1822 // structures this tests checks were added in revision 69
1823 if (!isExtensionStructSupported(deviceExtensions, RequiredExtension("VK_KHR_swapchain", 69)))
1824 TCU_THROW(NotSupportedError, "Required extension revision is not supported");
1825
1826 std::vector<const char *> requiredExtensions;
1827 requiredExtensions.push_back("VK_KHR_swapchain");
1828 if (!isCoreDeviceExtension(context.getUsedApiVersion(), "VK_KHR_device_group"))
1829 {
1830 requiredExtensions.push_back("VK_KHR_device_group");
1831 if (!isExtensionStructSupported(deviceExtensions, RequiredExtension("VK_KHR_device_group")))
1832 TCU_THROW(NotSupportedError, "VK_KHR_device_group is not supported");
1833 }
1834
1835 const tcu::UVec2 desiredSize(256, 256);
1836 const NativeObjects native(context, instHelper.supportedExtensions, wsiType, 1u, tcu::just(desiredSize));
1837 const Unique<VkSurfaceKHR> surface(createSurface(instHelper.vki, instHelper.instance, wsiType, native.getDisplay(),
1838 native.getWindow(), context.getTestContext().getCommandLine()));
1839
1840 const uint32_t devGroupIdx = cmdLine.getVKDeviceGroupId() - 1;
1841 const uint32_t deviceIdx = context.getTestContext().getCommandLine().getVKDeviceId() - 1u;
1842 const vector<VkPhysicalDeviceGroupProperties> deviceGroupProps =
1843 enumeratePhysicalDeviceGroups(instHelper.vki, instHelper.instance);
1844 uint32_t physicalDevicesInGroupCount = deviceGroupProps[devGroupIdx].physicalDeviceCount;
1845 const VkPhysicalDevice *physicalDevicesInGroup = deviceGroupProps[devGroupIdx].physicalDevices;
1846 uint32_t queueFamilyIndex = chooseQueueFamilyIndex(instHelper.vki, physicalDevicesInGroup[deviceIdx], *surface);
1847 const std::vector<VkQueueFamilyProperties> queueProps =
1848 getPhysicalDeviceQueueFamilyProperties(instHelper.vki, physicalDevicesInGroup[deviceIdx]);
1849 const float queuePriority = 1.0f;
1850 const uint32_t firstDeviceID = 0;
1851 const uint32_t secondDeviceID = 1;
1852 const uint32_t deviceIndices[] = {firstDeviceID, secondDeviceID};
1853
1854 if (physicalDevicesInGroupCount < 2)
1855 TCU_THROW(NotSupportedError, "Test requires more than 1 device in device group");
1856
1857 // create a device group
1858 const VkDeviceGroupDeviceCreateInfo groupDeviceInfo = {
1859 VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO_KHR, // stype
1860 DE_NULL, // pNext
1861 physicalDevicesInGroupCount, // physicalDeviceCount
1862 physicalDevicesInGroup // physicalDevices
1863 };
1864 const VkDeviceQueueCreateInfo deviceQueueCreateInfo = {
1865 VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, // type
1866 DE_NULL, // pNext
1867 (VkDeviceQueueCreateFlags)0u, // flags
1868 queueFamilyIndex, // queueFamilyIndex
1869 1u, // queueCount
1870 &queuePriority, // pQueuePriorities
1871 };
1872
1873 const VkDeviceCreateInfo deviceCreateInfo = {
1874 VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, // sType
1875 &groupDeviceInfo, // pNext
1876 (VkDeviceCreateFlags)0u, // flags
1877 1, // queueRecordCount
1878 &deviceQueueCreateInfo, // pRequestedQueues
1879 0, // layerCount
1880 DE_NULL, // ppEnabledLayerNames
1881 uint32_t(requiredExtensions.size()), // enabledExtensionCount
1882 &requiredExtensions[0], // ppEnabledExtensionNames
1883 DE_NULL, // pEnabledFeatures
1884 };
1885
1886 Move<VkDevice> groupDevice = createCustomDevice(context.getTestContext().getCommandLine().isValidationEnabled(),
1887 context.getPlatformInterface(), instHelper.instance, instHelper.vki,
1888 physicalDevicesInGroup[deviceIdx], &deviceCreateInfo);
1889 const DeviceDriver vkd(context.getPlatformInterface(), instHelper.instance, *groupDevice,
1890 context.getUsedApiVersion(), context.getTestContext().getCommandLine());
1891 VkQueue queue(getDeviceQueue(vkd, *groupDevice, queueFamilyIndex, 0));
1892 SimpleAllocator allocator(vkd, *groupDevice,
1893 getPhysicalDeviceMemoryProperties(instHelper.vki, physicalDevicesInGroup[deviceIdx]));
1894
1895 // create swapchain for device group
1896 const VkSurfaceCapabilitiesKHR capabilities =
1897 getPhysicalDeviceSurfaceCapabilities(instHelper.vki, physicalDevice, *surface);
1898 const vector<VkSurfaceFormatKHR> formats =
1899 getPhysicalDeviceSurfaceFormats(instHelper.vki, physicalDevice, *surface);
1900 const PlatformProperties &platformProperties = getPlatformProperties(wsiType);
1901 const VkSurfaceTransformFlagBitsKHR transform =
1902 (capabilities.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) ?
1903 VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR :
1904 capabilities.currentTransform;
1905 const uint32_t desiredImageCount = 2;
1906
1907 struct VkDeviceGroupSwapchainCreateInfoKHR deviceGroupSwapchainInfo = {
1908 VK_STRUCTURE_TYPE_IMAGE_SWAPCHAIN_CREATE_INFO_KHR, DE_NULL, VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_BIT_KHR};
1909 const VkSwapchainCreateInfoKHR swapchainInfo = {
1910 VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
1911 &deviceGroupSwapchainInfo,
1912 VK_SWAPCHAIN_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT_KHR,
1913 *surface,
1914 de::clamp(desiredImageCount, capabilities.minImageCount,
1915 capabilities.maxImageCount > 0 ? capabilities.maxImageCount :
1916 capabilities.minImageCount + desiredImageCount),
1917 formats[0].format,
1918 formats[0].colorSpace,
1919 (platformProperties.swapchainExtent == PlatformProperties::SWAPCHAIN_EXTENT_MUST_MATCH_WINDOW_SIZE ?
1920 capabilities.currentExtent :
1921 vk::makeExtent2D(desiredSize.x(), desiredSize.y())),
1922 1u,
1923 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
1924 VK_SHARING_MODE_EXCLUSIVE,
1925 0u,
1926 (const uint32_t *)DE_NULL,
1927 transform,
1928 VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
1929 VK_PRESENT_MODE_FIFO_KHR,
1930 VK_FALSE,
1931 (VkSwapchainKHR)0};
1932
1933 const Unique<VkSwapchainKHR> swapchain(createSwapchainKHR(vkd, *groupDevice, &swapchainInfo));
1934 uint32_t numImages = 0;
1935 VK_CHECK(vkd.getSwapchainImagesKHR(*groupDevice, *swapchain, &numImages, DE_NULL));
1936 if (numImages == 0)
1937 return tcu::TestStatus::pass("Pass");
1938
1939 VkImageSwapchainCreateInfoKHR imageSwapchainCreateInfo = {VK_STRUCTURE_TYPE_IMAGE_SWAPCHAIN_CREATE_INFO_KHR,
1940 DE_NULL, *swapchain};
1941
1942 VkImageCreateInfo imageCreateInfo = {
1943 VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
1944 &imageSwapchainCreateInfo,
1945 VK_IMAGE_CREATE_ALIAS_BIT | VK_IMAGE_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT_KHR, // flags
1946 VK_IMAGE_TYPE_2D, // imageType
1947 formats[0].format, // format
1948 {
1949 // extent
1950 desiredSize.x(), // width
1951 desiredSize.y(), // height
1952 1u // depth
1953 },
1954 1u, // mipLevels
1955 1u, // arrayLayers
1956 VK_SAMPLE_COUNT_1_BIT, // samples
1957 VK_IMAGE_TILING_OPTIMAL, // tiling
1958 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, // usage
1959 VK_SHARING_MODE_EXCLUSIVE, // sharingMode
1960 0u, // queueFamilyIndexCount
1961 DE_NULL, // pQueueFamilyIndices
1962 VK_IMAGE_LAYOUT_UNDEFINED // initialLayout
1963 };
1964
1965 typedef vk::Unique<VkImage> UniqueImage;
1966 typedef de::SharedPtr<UniqueImage> ImageSp;
1967
1968 vector<ImageSp> images(numImages);
1969 vector<VkImage> rawImages(numImages);
1970 vector<ImageSp> imagesSfr(numImages);
1971 vector<VkImage> rawImagesSfr(numImages);
1972 vector<VkBindImageMemorySwapchainInfoKHR> bindImageMemorySwapchainInfo(numImages);
1973
1974 // Create non-SFR image aliases for image layout transition
1975 {
1976 vector<VkBindImageMemoryInfo> bindImageMemoryInfos(numImages);
1977
1978 for (uint32_t idx = 0; idx < numImages; ++idx)
1979 {
1980 // Create image
1981 images[idx] = ImageSp(new UniqueImage(createImage(vkd, *groupDevice, &imageCreateInfo)));
1982
1983 VkBindImageMemorySwapchainInfoKHR bimsInfo = {VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_SWAPCHAIN_INFO_KHR,
1984 DE_NULL, *swapchain, idx};
1985 bindImageMemorySwapchainInfo[idx] = bimsInfo;
1986
1987 VkBindImageMemoryInfo bimInfo = {
1988 VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO, &bindImageMemorySwapchainInfo[idx], **images[idx],
1989 DE_NULL, // If the pNext chain includes an instance of VkBindImageMemorySwapchainInfoKHR, memory must be VK_NULL_HANDLE
1990 0u // If swapchain <in VkBindImageMemorySwapchainInfoKHR> is not NULL, the swapchain and imageIndex are used to determine the memory that the image is bound to, instead of memory and memoryOffset.
1991 };
1992 bindImageMemoryInfos[idx] = bimInfo;
1993 rawImages[idx] = **images[idx];
1994 }
1995
1996 VK_CHECK(vkd.bindImageMemory2(*groupDevice, numImages, &bindImageMemoryInfos[0]));
1997 }
1998
1999 // Create the SFR images
2000 {
2001 vector<VkBindImageMemoryDeviceGroupInfo> bindImageMemoryDeviceGroupInfo(numImages);
2002 vector<VkBindImageMemoryInfo> bindImageMemoryInfos(numImages);
2003 for (uint32_t idx = 0; idx < numImages; ++idx)
2004 {
2005 // Create image
2006 imagesSfr[idx] = ImageSp(new UniqueImage(createImage(vkd, *groupDevice, &imageCreateInfo)));
2007
2008 // Split into 2 vertical halves
2009 // NOTE: the same split has to be done also in WsiTriangleRenderer::recordDeviceGroupFrame
2010 const uint32_t halfWidth = desiredSize.x() / 2;
2011 const uint32_t height = desiredSize.y();
2012 const VkRect2D sfrRects[] = {
2013 {{0, 0}, {halfWidth, height}}, // offset, extent
2014 {{(int32_t)halfWidth, 0}, {halfWidth, height}}, // offset, extent
2015 {{0, 0}, {halfWidth, height}}, // offset, extent
2016 {{(int32_t)halfWidth, 0}, {halfWidth, height}} // offset, extent
2017 };
2018
2019 VkBindImageMemoryDeviceGroupInfo bimdgInfo = {VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_DEVICE_GROUP_INFO,
2020 &bindImageMemorySwapchainInfo[idx],
2021 DE_LENGTH_OF_ARRAY(deviceIndices),
2022 deviceIndices,
2023 DE_LENGTH_OF_ARRAY(sfrRects),
2024 sfrRects};
2025 bindImageMemoryDeviceGroupInfo[idx] = bimdgInfo;
2026
2027 VkBindImageMemoryInfo bimInfo = {
2028 VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO, &bindImageMemoryDeviceGroupInfo[idx], **imagesSfr[idx],
2029 DE_NULL, // If the pNext chain includes an instance of VkBindImageMemorySwapchainInfoKHR, memory must be VK_NULL_HANDLE
2030 0u // If swapchain <in VkBindImageMemorySwapchainInfoKHR> is not NULL, the swapchain and imageIndex are used to determine the memory that the image is bound to, instead of memory and memoryOffset.
2031 };
2032 bindImageMemoryInfos[idx] = bimInfo;
2033 rawImagesSfr[idx] = **imagesSfr[idx];
2034 }
2035
2036 VK_CHECK(vkd.bindImageMemory2(*groupDevice, numImages, &bindImageMemoryInfos[0]));
2037 }
2038
2039 VkPeerMemoryFeatureFlags peerMemoryFeatures = 0u;
2040 vkd.getDeviceGroupPeerMemoryFeatures(*groupDevice, 0, firstDeviceID, secondDeviceID, &peerMemoryFeatures);
2041 bool explicitLayoutTransitions = !(peerMemoryFeatures & VK_PEER_MEMORY_FEATURE_GENERIC_SRC_BIT) ||
2042 !(peerMemoryFeatures & VK_PEER_MEMORY_FEATURE_GENERIC_DST_BIT);
2043
2044 const WsiTriangleRenderer renderer(vkd, *groupDevice, allocator, context.getBinaryCollection(),
2045 explicitLayoutTransitions, rawImagesSfr, rawImages, swapchainInfo.imageFormat,
2046 tcu::UVec2(swapchainInfo.imageExtent.width, swapchainInfo.imageExtent.height));
2047
2048 const Unique<VkCommandPool> commandPool(
2049 createCommandPool(vkd, *groupDevice, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
2050
2051 const size_t maxQueuedFrames = rawImagesSfr.size() * 2;
2052
2053 // We need to keep hold of fences from vkAcquireNextImage2KHR
2054 // to actually limit number of frames we allow to be queued.
2055 const vector<FenceSp> imageReadyFences(createFences(vkd, *groupDevice, maxQueuedFrames));
2056
2057 // We need maxQueuedFrames+1 for imageReadySemaphores pool as we need to
2058 // pass the semaphore in same time as the fence we use to meter rendering.
2059 const vector<SemaphoreSp> imageReadySemaphores(createSemaphores(vkd, *groupDevice, maxQueuedFrames + 1));
2060
2061 // For rest we simply need maxQueuedFrames as we will wait for image from frameNdx-maxQueuedFrames
2062 // to become available to us, guaranteeing that previous uses must have completed.
2063 const vector<SemaphoreSp> renderingCompleteSemaphores(createSemaphores(vkd, *groupDevice, maxQueuedFrames));
2064 const vector<CommandBufferSp> commandBuffers(
2065 allocateCommandBuffers(vkd, *groupDevice, *commandPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY, maxQueuedFrames));
2066
2067 try
2068 {
2069 const uint32_t numFramesToRender = 60 * 10;
2070
2071 for (uint32_t frameNdx = 0; frameNdx < numFramesToRender; ++frameNdx)
2072 {
2073 const VkFence imageReadyFence = **imageReadyFences[frameNdx % imageReadyFences.size()];
2074 const VkSemaphore imageReadySemaphore = **imageReadySemaphores[frameNdx % imageReadySemaphores.size()];
2075 uint32_t imageNdx = ~0u;
2076
2077 VK_CHECK(
2078 vkd.waitForFences(*groupDevice, 1u, &imageReadyFence, VK_TRUE, std::numeric_limits<uint64_t>::max()));
2079 VK_CHECK(vkd.resetFences(*groupDevice, 1, &imageReadyFence));
2080
2081 {
2082 VkAcquireNextImageInfoKHR acquireNextImageInfo = {VK_STRUCTURE_TYPE_ACQUIRE_NEXT_IMAGE_INFO_KHR,
2083 DE_NULL,
2084 *swapchain,
2085 std::numeric_limits<uint64_t>::max(),
2086 imageReadySemaphore,
2087 (VkFence)0,
2088 (1 << firstDeviceID)};
2089
2090 const VkResult acquireResult = vkd.acquireNextImage2KHR(*groupDevice, &acquireNextImageInfo, &imageNdx);
2091
2092 if (acquireResult == VK_SUBOPTIMAL_KHR)
2093 context.getTestContext().getLog() << TestLog::Message << "Got " << acquireResult << " at frame "
2094 << frameNdx << TestLog::EndMessage;
2095 else
2096 VK_CHECK(acquireResult);
2097 }
2098
2099 TCU_CHECK((size_t)imageNdx < rawImagesSfr.size());
2100
2101 {
2102 const VkSemaphore renderingCompleteSemaphore =
2103 **renderingCompleteSemaphores[frameNdx % renderingCompleteSemaphores.size()];
2104 const VkCommandBuffer commandBuffer = **commandBuffers[frameNdx % commandBuffers.size()];
2105 const VkPipelineStageFlags waitDstStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
2106
2107 // render triangle using one or two subdevices when available
2108 renderer.recordDeviceGroupFrame(commandBuffer, firstDeviceID, secondDeviceID,
2109 physicalDevicesInGroupCount, imageNdx, frameNdx);
2110
2111 // submit queue
2112 uint32_t deviceMask = (1 << firstDeviceID) | (1 << secondDeviceID);
2113 const VkDeviceGroupSubmitInfo deviceGroupSubmitInfo = {
2114 VK_STRUCTURE_TYPE_DEVICE_GROUP_SUBMIT_INFO_KHR, // sType
2115 DE_NULL, // pNext
2116 DE_LENGTH_OF_ARRAY(deviceIndices), // waitSemaphoreCount
2117 deviceIndices, // pWaitSemaphoreDeviceIndices
2118 1u, // commandBufferCount
2119 &deviceMask, // pCommandBufferDeviceMasks
2120 DE_LENGTH_OF_ARRAY(deviceIndices), // signalSemaphoreCount
2121 deviceIndices, // pSignalSemaphoreDeviceIndices
2122 };
2123 const VkSubmitInfo submitInfo = {
2124 VK_STRUCTURE_TYPE_SUBMIT_INFO, // sType
2125 &deviceGroupSubmitInfo, // pNext
2126 1u, // waitSemaphoreCount
2127 &imageReadySemaphore, // pWaitSemaphores
2128 &waitDstStage, // pWaitDstStageMask
2129 1u, // commandBufferCount
2130 &commandBuffer, // pCommandBuffers
2131 1u, // signalSemaphoreCount
2132 &renderingCompleteSemaphore, // pSignalSemaphores
2133 };
2134 VK_CHECK(vkd.queueSubmit(queue, 1u, &submitInfo, imageReadyFence));
2135
2136 // present swapchain image - asume that first device has a presentation engine
2137 deviceMask = (1 << firstDeviceID);
2138 const VkDeviceGroupPresentInfoKHR deviceGroupPresentInfo = {
2139 VK_STRUCTURE_TYPE_DEVICE_GROUP_PRESENT_INFO_KHR, DE_NULL, 1u, &deviceMask,
2140 VK_DEVICE_GROUP_PRESENT_MODE_REMOTE_BIT_KHR,
2141 };
2142 const VkPresentInfoKHR presentInfo = {VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
2143 &deviceGroupPresentInfo,
2144 1u,
2145 &renderingCompleteSemaphore,
2146 1u,
2147 &*swapchain,
2148 &imageNdx,
2149 (VkResult *)DE_NULL};
2150 VK_CHECK(vkd.queuePresentKHR(queue, &presentInfo));
2151 }
2152 }
2153
2154 VK_CHECK(vkd.deviceWaitIdle(*groupDevice));
2155 }
2156 catch (...)
2157 {
2158 // Make sure device is idle before destroying resources
2159 vkd.deviceWaitIdle(*groupDevice);
2160 throw;
2161 }
2162
2163 return tcu::TestStatus::pass("Rendering tests succeeded");
2164 }
2165
getSwapchainSizeSequence(const VkSurfaceCapabilitiesKHR & capabilities,const tcu::UVec2 & defaultSize)2166 vector<tcu::UVec2> getSwapchainSizeSequence(const VkSurfaceCapabilitiesKHR &capabilities, const tcu::UVec2 &defaultSize)
2167 {
2168 vector<tcu::UVec2> sizes(3);
2169 sizes[0] = defaultSize / 2u;
2170 sizes[1] = defaultSize;
2171 sizes[2] = defaultSize * 2u;
2172
2173 for (uint32_t i = 0; i < sizes.size(); ++i)
2174 {
2175 sizes[i].x() = de::clamp(sizes[i].x(), capabilities.minImageExtent.width, capabilities.maxImageExtent.width);
2176 sizes[i].y() = de::clamp(sizes[i].y(), capabilities.minImageExtent.height, capabilities.maxImageExtent.height);
2177 }
2178
2179 return sizes;
2180 }
2181
resizeSwapchainTest(Context & context,Type wsiType)2182 tcu::TestStatus resizeSwapchainTest(Context &context, Type wsiType)
2183 {
2184 const tcu::UVec2 desiredSize(256, 256);
2185 const InstanceHelper instHelper(context, wsiType);
2186 const NativeObjects native(context, instHelper.supportedExtensions, wsiType, 1u, tcu::just(desiredSize));
2187 const Unique<VkSurfaceKHR> surface(createSurface(instHelper.vki, instHelper.instance, wsiType, native.getDisplay(),
2188 native.getWindow(), context.getTestContext().getCommandLine()));
2189 const DeviceHelper devHelper(context, instHelper.vki, instHelper.instance, *surface);
2190 const PlatformProperties &platformProperties = getPlatformProperties(wsiType);
2191 const VkSurfaceCapabilitiesKHR capabilities =
2192 getPhysicalDeviceSurfaceCapabilities(instHelper.vki, devHelper.physicalDevice, *surface);
2193 const DeviceInterface &vkd = devHelper.vkd;
2194 const VkDevice device = *devHelper.device;
2195 SimpleAllocator allocator(vkd, device, getPhysicalDeviceMemoryProperties(instHelper.vki, devHelper.physicalDevice));
2196 vector<tcu::UVec2> sizes = getSwapchainSizeSequence(capabilities, desiredSize);
2197 Move<VkSwapchainKHR> prevSwapchain;
2198
2199 DE_ASSERT(platformProperties.swapchainExtent != PlatformProperties::SWAPCHAIN_EXTENT_MUST_MATCH_WINDOW_SIZE);
2200 DE_UNREF(platformProperties);
2201
2202 for (uint32_t sizeNdx = 0; sizeNdx < sizes.size(); ++sizeNdx)
2203 {
2204 // \todo [2016-05-30 jesse] This test currently waits for idle and
2205 // recreates way more than necessary when recreating the swapchain. Make
2206 // it match expected real app behavior better by smoothly switching from
2207 // old to new swapchain. Once that is done, it will also be possible to
2208 // test creating a new swapchain while images from the previous one are
2209 // still acquired.
2210
2211 VkSwapchainCreateInfoKHR swapchainInfo =
2212 getBasicSwapchainParameters(wsiType, instHelper.vki, devHelper.physicalDevice, *surface, sizes[sizeNdx], 2);
2213 swapchainInfo.oldSwapchain = *prevSwapchain;
2214
2215 Move<VkSwapchainKHR> swapchain(createSwapchainKHR(vkd, device, &swapchainInfo));
2216 const vector<VkImage> swapchainImages = getSwapchainImages(vkd, device, *swapchain);
2217 const WsiTriangleRenderer renderer(
2218 vkd, device, allocator, context.getBinaryCollection(), false, swapchainImages, swapchainImages,
2219 swapchainInfo.imageFormat, tcu::UVec2(swapchainInfo.imageExtent.width, swapchainInfo.imageExtent.height));
2220 const Unique<VkCommandPool> commandPool(createCommandPool(
2221 vkd, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, devHelper.queueFamilyIndex));
2222 const size_t maxQueuedFrames = swapchainImages.size() * 2;
2223
2224 // We need to keep hold of fences from vkAcquireNextImageKHR to actually
2225 // limit number of frames we allow to be queued.
2226 const vector<FenceSp> imageReadyFences(createFences(vkd, device, maxQueuedFrames));
2227
2228 // We need maxQueuedFrames+1 for imageReadySemaphores pool as we need to pass
2229 // the semaphore in same time as the fence we use to meter rendering.
2230 const vector<SemaphoreSp> imageReadySemaphores(createSemaphores(vkd, device, maxQueuedFrames + 1));
2231
2232 // For rest we simply need maxQueuedFrames as we will wait for image
2233 // from frameNdx-maxQueuedFrames to become available to us, guaranteeing that
2234 // previous uses must have completed.
2235 const vector<SemaphoreSp> renderingCompleteSemaphores(createSemaphores(vkd, device, maxQueuedFrames));
2236 const vector<CommandBufferSp> commandBuffers(
2237 allocateCommandBuffers(vkd, device, *commandPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY, maxQueuedFrames));
2238
2239 try
2240 {
2241 const uint32_t numFramesToRender = 60;
2242
2243 for (uint32_t frameNdx = 0; frameNdx < numFramesToRender; ++frameNdx)
2244 {
2245 const VkFence imageReadyFence = **imageReadyFences[frameNdx % imageReadyFences.size()];
2246 const VkSemaphore imageReadySemaphore = **imageReadySemaphores[frameNdx % imageReadySemaphores.size()];
2247 uint32_t imageNdx = ~0u;
2248
2249 VK_CHECK(
2250 vkd.waitForFences(device, 1u, &imageReadyFence, VK_TRUE, std::numeric_limits<uint64_t>::max()));
2251 VK_CHECK(vkd.resetFences(device, 1, &imageReadyFence));
2252
2253 {
2254 const VkResult acquireResult =
2255 vkd.acquireNextImageKHR(device, *swapchain, std::numeric_limits<uint64_t>::max(),
2256 imageReadySemaphore, DE_NULL, &imageNdx);
2257
2258 if (acquireResult == VK_SUBOPTIMAL_KHR)
2259 context.getTestContext().getLog() << TestLog::Message << "Got " << acquireResult << " at frame "
2260 << frameNdx << TestLog::EndMessage;
2261 else
2262 VK_CHECK(acquireResult);
2263 }
2264
2265 TCU_CHECK((size_t)imageNdx < swapchainImages.size());
2266
2267 {
2268 const VkSemaphore renderingCompleteSemaphore =
2269 **renderingCompleteSemaphores[frameNdx % renderingCompleteSemaphores.size()];
2270 const VkCommandBuffer commandBuffer = **commandBuffers[frameNdx % commandBuffers.size()];
2271 const VkPipelineStageFlags waitDstStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
2272 const VkSubmitInfo submitInfo = {VK_STRUCTURE_TYPE_SUBMIT_INFO,
2273 DE_NULL,
2274 1u,
2275 &imageReadySemaphore,
2276 &waitDstStage,
2277 1u,
2278 &commandBuffer,
2279 1u,
2280 &renderingCompleteSemaphore};
2281 const VkPresentInfoKHR presentInfo = {VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
2282 DE_NULL,
2283 1u,
2284 &renderingCompleteSemaphore,
2285 1u,
2286 &*swapchain,
2287 &imageNdx,
2288 (VkResult *)DE_NULL};
2289
2290 renderer.recordFrame(commandBuffer, imageNdx, frameNdx);
2291 VK_CHECK(vkd.queueSubmit(devHelper.queue, 1u, &submitInfo, imageReadyFence));
2292 VK_CHECK_WSI(vkd.queuePresentKHR(devHelper.queue, &presentInfo));
2293 }
2294 }
2295
2296 VK_CHECK(vkd.deviceWaitIdle(device));
2297
2298 prevSwapchain = swapchain;
2299 }
2300 catch (...)
2301 {
2302 // Make sure device is idle before destroying resources
2303 vkd.deviceWaitIdle(device);
2304 throw;
2305 }
2306 }
2307
2308 return tcu::TestStatus::pass("Resizing tests succeeded");
2309 }
2310
getImagesIncompleteResultTest(Context & context,Type wsiType)2311 tcu::TestStatus getImagesIncompleteResultTest(Context &context, Type wsiType)
2312 {
2313 const tcu::UVec2 desiredSize(256, 256);
2314 const InstanceHelper instHelper(context, wsiType);
2315 const NativeObjects native(context, instHelper.supportedExtensions, wsiType, 1u, tcu::just(desiredSize));
2316 const Unique<VkSurfaceKHR> surface(createSurface(instHelper.vki, instHelper.instance, wsiType, native.getDisplay(),
2317 native.getWindow(), context.getTestContext().getCommandLine()));
2318 const DeviceHelper devHelper(context, instHelper.vki, instHelper.instance, *surface);
2319 const VkSwapchainCreateInfoKHR swapchainInfo =
2320 getBasicSwapchainParameters(wsiType, instHelper.vki, devHelper.physicalDevice, *surface, desiredSize, 2);
2321 const Unique<VkSwapchainKHR> swapchain(createSwapchainKHR(devHelper.vkd, *devHelper.device, &swapchainInfo));
2322
2323 vector<VkImage> swapchainImages = getSwapchainImages(devHelper.vkd, *devHelper.device, *swapchain);
2324
2325 ValidateQueryBits::fillBits(swapchainImages.begin(), swapchainImages.end());
2326
2327 const uint32_t usedCount = static_cast<uint32_t>(swapchainImages.size() / 2);
2328 uint32_t count = usedCount;
2329 const VkResult result =
2330 devHelper.vkd.getSwapchainImagesKHR(*devHelper.device, *swapchain, &count, &swapchainImages[0]);
2331
2332 if (count != usedCount || result != VK_INCOMPLETE ||
2333 !ValidateQueryBits::checkBits(swapchainImages.begin() + count, swapchainImages.end()))
2334 return tcu::TestStatus::fail("Get swapchain images didn't return VK_INCOMPLETE");
2335 else
2336 return tcu::TestStatus::pass("Get swapchain images tests succeeded");
2337 }
2338
getImagesResultsCountTest(Context & context,Type wsiType)2339 tcu::TestStatus getImagesResultsCountTest(Context &context, Type wsiType)
2340 {
2341 const tcu::UVec2 desiredSize(256, 256);
2342 const InstanceHelper instHelper(context, wsiType);
2343 const NativeObjects native(context, instHelper.supportedExtensions, wsiType, 1u, tcu::just(desiredSize));
2344 const Unique<VkSurfaceKHR> surface(createSurface(instHelper.vki, instHelper.instance, wsiType, native.getDisplay(),
2345 native.getWindow(), context.getTestContext().getCommandLine()));
2346 const DeviceHelper devHelper(context, instHelper.vki, instHelper.instance, *surface);
2347 const VkSwapchainCreateInfoKHR swapchainInfo =
2348 getBasicSwapchainParameters(wsiType, instHelper.vki, devHelper.physicalDevice, *surface, desiredSize, 2);
2349 const Unique<VkSwapchainKHR> swapchain(createSwapchainKHR(devHelper.vkd, *devHelper.device, &swapchainInfo));
2350
2351 uint32_t numImages = 0;
2352
2353 VK_CHECK(devHelper.vkd.getSwapchainImagesKHR(*devHelper.device, *swapchain, &numImages, DE_NULL));
2354
2355 if (numImages > 0)
2356 {
2357 std::vector<VkImage> images(numImages + 1);
2358 const uint32_t numImagesOrig = numImages;
2359
2360 // check if below call properly overwrites formats count
2361 numImages++;
2362
2363 VK_CHECK(devHelper.vkd.getSwapchainImagesKHR(*devHelper.device, *swapchain, &numImages, &images[0]));
2364
2365 if ((size_t)numImages != numImagesOrig)
2366 TCU_FAIL("Image count changed between calls");
2367 }
2368 return tcu::TestStatus::pass("Get swapchain images tests succeeded");
2369 }
2370
destroyNullHandleSwapchainTest(Context & context,Type wsiType)2371 tcu::TestStatus destroyNullHandleSwapchainTest(Context &context, Type wsiType)
2372 {
2373 const InstanceHelper instHelper(context, wsiType);
2374 const NativeObjects native(context, instHelper.supportedExtensions, wsiType);
2375 const Unique<VkSurfaceKHR> surface(createSurface(instHelper.vki, instHelper.instance, wsiType, native.getDisplay(),
2376 native.getWindow(), context.getTestContext().getCommandLine()));
2377 const DeviceHelper devHelper(context, instHelper.vki, instHelper.instance, *surface);
2378 const VkSwapchainKHR nullHandle = DE_NULL;
2379
2380 // Default allocator
2381 devHelper.vkd.destroySwapchainKHR(*devHelper.device, nullHandle, DE_NULL);
2382
2383 // Custom allocator
2384 {
2385 AllocationCallbackRecorder recordingAllocator(getSystemAllocator(), 1u);
2386
2387 devHelper.vkd.destroySwapchainKHR(*devHelper.device, nullHandle, recordingAllocator.getCallbacks());
2388
2389 if (recordingAllocator.getNumRecords() != 0u)
2390 return tcu::TestStatus::fail("Implementation allocated/freed the memory");
2391 }
2392
2393 return tcu::TestStatus::pass("Destroying a VK_NULL_HANDLE surface has no effect");
2394 }
2395
destroyOldSwapchainTest(Context & context,Type wsiType)2396 tcu::TestStatus destroyOldSwapchainTest(Context &context, Type wsiType)
2397 {
2398 const tcu::UVec2 desiredSize(256, 256);
2399 const InstanceHelper instHelper(context, wsiType);
2400 const NativeObjects native(context, instHelper.supportedExtensions, wsiType);
2401 const Unique<VkSurfaceKHR> surface(createSurface(instHelper.vki, instHelper.instance, wsiType, native.getDisplay(),
2402 native.getWindow(), context.getTestContext().getCommandLine()));
2403 const DeviceHelper devHelper(context, instHelper.vki, instHelper.instance, *surface);
2404
2405 // Create the first swapchain.
2406 VkSwapchainCreateInfoKHR swapchainInfo =
2407 getBasicSwapchainParameters(wsiType, instHelper.vki, devHelper.physicalDevice, *surface, desiredSize, 2);
2408 VkSwapchainKHR swapchain = 0;
2409 VK_CHECK(devHelper.vkd.createSwapchainKHR(*devHelper.device, &swapchainInfo, DE_NULL, &swapchain));
2410
2411 // Create a new swapchain replacing the old one.
2412 swapchainInfo.oldSwapchain = swapchain;
2413 VkSwapchainKHR recreatedSwapchain = 0;
2414 VK_CHECK(devHelper.vkd.createSwapchainKHR(*devHelper.device, &swapchainInfo, DE_NULL, &recreatedSwapchain));
2415
2416 // Destroying the old swapchain should have no effect.
2417 devHelper.vkd.destroySwapchainKHR(*devHelper.device, swapchain, DE_NULL);
2418
2419 // Destroy the new swapchain for cleanup.
2420 devHelper.vkd.destroySwapchainKHR(*devHelper.device, recreatedSwapchain, DE_NULL);
2421
2422 return tcu::TestStatus::pass("Destroying an old swapchain has no effect.");
2423 }
2424
acquireTooManyTest(Context & context,Type wsiType)2425 tcu::TestStatus acquireTooManyTest(Context &context, Type wsiType)
2426 {
2427 const tcu::UVec2 desiredSize(256, 256);
2428 const InstanceHelper instHelper(context, wsiType);
2429 const NativeObjects native(context, instHelper.supportedExtensions, wsiType, tcu::just(desiredSize));
2430 const Unique<VkSurfaceKHR> surface(createSurface(instHelper.vki, instHelper.instance, wsiType, native.getDisplay(),
2431 native.getWindow(), context.getTestContext().getCommandLine()));
2432 const DeviceHelper devHelper(context, instHelper.vki, instHelper.instance, *surface);
2433 const VkSwapchainCreateInfoKHR swapchainInfo =
2434 getBasicSwapchainParameters(wsiType, instHelper.vki, devHelper.physicalDevice, *surface, desiredSize, 2);
2435 const Unique<VkSwapchainKHR> swapchain(createSwapchainKHR(devHelper.vkd, *devHelper.device, &swapchainInfo));
2436
2437 uint32_t numImages;
2438 VK_CHECK(devHelper.vkd.getSwapchainImagesKHR(*devHelper.device, *swapchain, &numImages, DE_NULL));
2439 const uint32_t minImageCount =
2440 getPhysicalDeviceSurfaceCapabilities(instHelper.vki, devHelper.physicalDevice, *surface).minImageCount;
2441 if (numImages < minImageCount)
2442 return tcu::TestStatus::fail("Get swapchain images returned less than minImageCount images");
2443 const uint32_t numAcquirableImages = numImages - minImageCount + 1;
2444
2445 const auto fences = createFences(devHelper.vkd, *devHelper.device, numAcquirableImages + 1, false);
2446 uint32_t unused;
2447
2448 for (uint32_t i = 0; i < numAcquirableImages; ++i)
2449 {
2450 VK_CHECK_WSI(devHelper.vkd.acquireNextImageKHR(
2451 *devHelper.device, *swapchain, std::numeric_limits<uint64_t>::max(), (VkSemaphore)0, **fences[i], &unused));
2452 }
2453
2454 const auto result = devHelper.vkd.acquireNextImageKHR(*devHelper.device, *swapchain, 0, (VkSemaphore)0,
2455 **fences[numAcquirableImages], &unused);
2456
2457 if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR && result != VK_NOT_READY)
2458 {
2459 return tcu::TestStatus::fail("Implementation failed to respond well acquiring too many images with 0 timeout");
2460 }
2461
2462 // cleanup
2463 const uint32_t numFences =
2464 (result == VK_NOT_READY) ? static_cast<uint32_t>(fences.size() - 1) : static_cast<uint32_t>(fences.size());
2465 vector<vk::VkFence> fencesRaw(numFences);
2466 std::transform(fences.begin(), fences.begin() + numFences, fencesRaw.begin(),
2467 [](const FenceSp &f) -> vk::VkFence { return **f; });
2468 VK_CHECK(devHelper.vkd.waitForFences(*devHelper.device, numFences, fencesRaw.data(), VK_TRUE,
2469 std::numeric_limits<uint64_t>::max()));
2470
2471 return tcu::TestStatus::pass("Acquire too many swapchain images test succeeded");
2472 }
2473
acquireTooManyTimeoutTest(Context & context,Type wsiType)2474 tcu::TestStatus acquireTooManyTimeoutTest(Context &context, Type wsiType)
2475 {
2476 const tcu::UVec2 desiredSize(256, 256);
2477 const InstanceHelper instHelper(context, wsiType);
2478 const NativeObjects native(context, instHelper.supportedExtensions, wsiType, tcu::just(desiredSize));
2479 const Unique<VkSurfaceKHR> surface(createSurface(instHelper.vki, instHelper.instance, wsiType, native.getDisplay(),
2480 native.getWindow(), context.getTestContext().getCommandLine()));
2481 const DeviceHelper devHelper(context, instHelper.vki, instHelper.instance, *surface);
2482 const VkSwapchainCreateInfoKHR swapchainInfo =
2483 getBasicSwapchainParameters(wsiType, instHelper.vki, devHelper.physicalDevice, *surface, desiredSize, 2);
2484 const Unique<VkSwapchainKHR> swapchain(createSwapchainKHR(devHelper.vkd, *devHelper.device, &swapchainInfo));
2485
2486 uint32_t numImages;
2487 VK_CHECK(devHelper.vkd.getSwapchainImagesKHR(*devHelper.device, *swapchain, &numImages, DE_NULL));
2488 const uint32_t minImageCount =
2489 getPhysicalDeviceSurfaceCapabilities(instHelper.vki, devHelper.physicalDevice, *surface).minImageCount;
2490 if (numImages < minImageCount)
2491 return tcu::TestStatus::fail("Get swapchain images returned less than minImageCount images");
2492 const uint32_t numAcquirableImages = numImages - minImageCount + 1;
2493
2494 const auto fences = createFences(devHelper.vkd, *devHelper.device, numAcquirableImages + 1, false);
2495 uint32_t unused;
2496
2497 for (uint32_t i = 0; i < numAcquirableImages; ++i)
2498 {
2499 VK_CHECK_WSI(devHelper.vkd.acquireNextImageKHR(
2500 *devHelper.device, *swapchain, std::numeric_limits<uint64_t>::max(), (VkSemaphore)0, **fences[i], &unused));
2501 }
2502
2503 const uint64_t millisecond = 1000000;
2504 const uint64_t timeout = 50 * millisecond; // arbitrary realistic non-0 non-infinite timeout
2505 const auto result = devHelper.vkd.acquireNextImageKHR(*devHelper.device, *swapchain, timeout, (VkSemaphore)0,
2506 **fences[numAcquirableImages], &unused);
2507
2508 if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR && result != VK_TIMEOUT)
2509 {
2510 return tcu::TestStatus::fail("Implementation failed to respond well acquiring too many images with timeout");
2511 }
2512
2513 // cleanup
2514 const uint32_t numFences =
2515 (result == VK_TIMEOUT) ? static_cast<uint32_t>(fences.size() - 1) : static_cast<uint32_t>(fences.size());
2516 vector<vk::VkFence> fencesRaw(numFences);
2517 std::transform(fences.begin(), fences.begin() + numFences, fencesRaw.begin(),
2518 [](const FenceSp &f) -> vk::VkFence { return **f; });
2519 VK_CHECK(devHelper.vkd.waitForFences(*devHelper.device, numFences, fencesRaw.data(), VK_TRUE,
2520 std::numeric_limits<uint64_t>::max()));
2521
2522 return tcu::TestStatus::pass("Acquire too many swapchain images test succeeded");
2523 }
2524
getBasicRenderPrograms(SourceCollections & dst,Type)2525 void getBasicRenderPrograms(SourceCollections &dst, Type)
2526 {
2527 WsiTriangleRenderer::getPrograms(dst);
2528 }
2529
getBasicRenderPrograms(SourceCollections & dst,MultiSwapchainParams)2530 void getBasicRenderPrograms(SourceCollections &dst, MultiSwapchainParams)
2531 {
2532 WsiTriangleRenderer::getPrograms(dst);
2533 }
2534
populateRenderGroup(tcu::TestCaseGroup * testGroup,Type wsiType)2535 void populateRenderGroup(tcu::TestCaseGroup *testGroup, Type wsiType)
2536 {
2537 // Basic Rendering Test
2538 addFunctionCaseWithPrograms(testGroup, "basic", getBasicRenderPrograms, basicRenderTest<AcquireNextImageWrapper>,
2539 wsiType);
2540 // Basic Rendering Test using AcquireNextImage2
2541 addFunctionCaseWithPrograms(testGroup, "basic2", getBasicRenderPrograms, basicRenderTest<AcquireNextImage2Wrapper>,
2542 wsiType);
2543 // Basic Rendering Test using device_group
2544 addFunctionCaseWithPrograms(testGroup, "device_group", getBasicRenderPrograms, deviceGroupRenderTest, wsiType);
2545 // Rendering Test using device_group and VkImageSwapchainCreateInfo
2546 addFunctionCaseWithPrograms(testGroup, "device_group2", getBasicRenderPrograms, deviceGroupRenderTest2, wsiType);
2547
2548 const MultiSwapchainParams kTwoSwapchains{wsiType, 2u};
2549 const MultiSwapchainParams kTenSwapchains{wsiType, 10u};
2550
2551 // 2 Swapchains Rendering Test
2552 addFunctionCaseWithPrograms(testGroup, "2swapchains", getBasicRenderPrograms,
2553 multiSwapchainRenderTest<AcquireNextImageWrapper>, kTwoSwapchains);
2554 // 2 Swapchains Rendering Test using AcquireNextImage2
2555 addFunctionCaseWithPrograms(testGroup, "2swapchains2", getBasicRenderPrograms,
2556 multiSwapchainRenderTest<AcquireNextImage2Wrapper>, kTwoSwapchains);
2557 // 10 Swapchains Rendering Test
2558 addFunctionCaseWithPrograms(testGroup, "10swapchains", getBasicRenderPrograms,
2559 multiSwapchainRenderTest<AcquireNextImageWrapper>, kTenSwapchains);
2560 // 10 Swapchains Rendering Test using AcquireNextImage2
2561 addFunctionCaseWithPrograms(testGroup, "10swapchains2", getBasicRenderPrograms,
2562 multiSwapchainRenderTest<AcquireNextImage2Wrapper>, kTenSwapchains);
2563 }
2564
populateGetImagesGroup(tcu::TestCaseGroup * testGroup,Type wsiType)2565 void populateGetImagesGroup(tcu::TestCaseGroup *testGroup, Type wsiType)
2566 {
2567 // Test VK_INCOMPLETE return code
2568 addFunctionCase(testGroup, "incomplete", getImagesIncompleteResultTest, wsiType);
2569 // Test proper count of images
2570 addFunctionCase(testGroup, "count", getImagesResultsCountTest, wsiType);
2571 }
2572
populateModifyGroup(tcu::TestCaseGroup * testGroup,Type wsiType)2573 void populateModifyGroup(tcu::TestCaseGroup *testGroup, Type wsiType)
2574 {
2575 const PlatformProperties &platformProperties = getPlatformProperties(wsiType);
2576
2577 if (platformProperties.swapchainExtent != PlatformProperties::SWAPCHAIN_EXTENT_MUST_MATCH_WINDOW_SIZE)
2578 {
2579 // Resize Swapchain Test
2580 addFunctionCaseWithPrograms(testGroup, "resize", getBasicRenderPrograms, resizeSwapchainTest, wsiType);
2581 }
2582
2583 // \todo [2016-05-30 jesse] Add tests for modifying preTransform, compositeAlpha, presentMode
2584 }
2585
populateDestroyGroup(tcu::TestCaseGroup * testGroup,Type wsiType)2586 void populateDestroyGroup(tcu::TestCaseGroup *testGroup, Type wsiType)
2587 {
2588 // Destroying a VK_NULL_HANDLE swapchain
2589 addFunctionCase(testGroup, "null_handle", destroyNullHandleSwapchainTest, wsiType);
2590 // Destroying an old swapchain
2591 addFunctionCase(testGroup, "old_swapchain", destroyOldSwapchainTest, wsiType);
2592 }
2593
populateAcquireGroup(tcu::TestCaseGroup * testGroup,Type wsiType)2594 void populateAcquireGroup(tcu::TestCaseGroup *testGroup, Type wsiType)
2595 {
2596 // Test acquiring too many images with 0 timeout
2597 addFunctionCase(testGroup, "too_many", acquireTooManyTest, wsiType);
2598 // Test acquiring too many images with timeout
2599 addFunctionCase(testGroup, "too_many_timeout", acquireTooManyTimeoutTest, wsiType);
2600 }
2601
2602 } // namespace
2603
createSwapchainTests(tcu::TestCaseGroup * testGroup,vk::wsi::Type wsiType)2604 void createSwapchainTests(tcu::TestCaseGroup *testGroup, vk::wsi::Type wsiType)
2605 {
2606 // Create VkSwapchain with various parameters
2607 addTestGroup(testGroup, "create", populateSwapchainGroup, GroupParameters(wsiType, createSwapchainTest));
2608 // Simulate OOM using callbacks during swapchain construction
2609 addTestGroup(testGroup, "simulate_oom", populateSwapchainGroup,
2610 GroupParameters(wsiType, createSwapchainSimulateOOMTest));
2611 // Rendering Tests
2612 addTestGroup(testGroup, "render", populateRenderGroup, wsiType);
2613 // Modify VkSwapchain
2614 addTestGroup(testGroup, "modify", populateModifyGroup, wsiType);
2615 // Destroy VkSwapchain
2616 addTestGroup(testGroup, "destroy", populateDestroyGroup, wsiType);
2617 // Get swapchain images
2618 addTestGroup(testGroup, "get_images", populateGetImagesGroup, wsiType);
2619 // Ancquire next swapchain image
2620 addTestGroup(testGroup, "acquire", populateAcquireGroup, wsiType);
2621 // Create VkSwapchain and use VK_EXT_private_data
2622 addTestGroup(testGroup, "private_data", populateSwapchainPrivateDataGroup,
2623 GroupParameters(wsiType, createSwapchainPrivateDataTest));
2624 }
2625
2626 } // namespace wsi
2627 } // namespace vkt
2628