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