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