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