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
29 #include "vkDefs.hpp"
30 #include "vkPlatform.hpp"
31 #include "vkStrUtil.hpp"
32 #include "vkRef.hpp"
33 #include "vkRefUtil.hpp"
34 #include "vkQueryUtil.hpp"
35 #include "vkMemUtil.hpp"
36 #include "vkDeviceUtil.hpp"
37 #include "vkPrograms.hpp"
38 #include "vkTypeUtil.hpp"
39 #include "vkWsiPlatform.hpp"
40 #include "vkWsiUtil.hpp"
41 #include "vkAllocationCallbackUtil.hpp"
42
43 #include "tcuTestLog.hpp"
44 #include "tcuFormatUtil.hpp"
45 #include "tcuPlatform.hpp"
46 #include "tcuResultCollector.hpp"
47
48 #include "deUniquePtr.hpp"
49 #include "deStringUtil.hpp"
50 #include "deArrayUtil.hpp"
51 #include "deSharedPtr.hpp"
52
53 #include <limits>
54
55 namespace vkt
56 {
57 namespace wsi
58 {
59
60 namespace
61 {
62
63 using namespace vk;
64 using namespace vk::wsi;
65
66 using tcu::TestLog;
67 using tcu::Maybe;
68 using tcu::UVec2;
69
70 using de::MovePtr;
71 using de::UniquePtr;
72
73 using std::string;
74 using std::vector;
75
76 typedef vector<VkExtensionProperties> Extensions;
77
checkAllSupported(const Extensions & supportedExtensions,const vector<string> & requiredExtensions)78 void checkAllSupported (const Extensions& supportedExtensions, const vector<string>& requiredExtensions)
79 {
80 for (vector<string>::const_iterator requiredExtName = requiredExtensions.begin();
81 requiredExtName != requiredExtensions.end();
82 ++requiredExtName)
83 {
84 if (!isExtensionSupported(supportedExtensions, RequiredExtension(*requiredExtName)))
85 TCU_THROW(NotSupportedError, (*requiredExtName + " is not supported").c_str());
86 }
87 }
88
createInstanceWithWsi(const PlatformInterface & vkp,const Extensions & supportedExtensions,Type wsiType,const VkAllocationCallbacks * pAllocator=DE_NULL)89 Move<VkInstance> createInstanceWithWsi (const PlatformInterface& vkp,
90 const Extensions& supportedExtensions,
91 Type wsiType,
92 const VkAllocationCallbacks* pAllocator = DE_NULL)
93 {
94 vector<string> extensions;
95
96 extensions.push_back("VK_KHR_surface");
97 extensions.push_back(getExtensionName(wsiType));
98
99 checkAllSupported(supportedExtensions, extensions);
100
101 return createDefaultInstance(vkp, vector<string>(), extensions, pAllocator);
102 }
103
getDeviceFeaturesForWsi(void)104 VkPhysicalDeviceFeatures getDeviceFeaturesForWsi (void)
105 {
106 VkPhysicalDeviceFeatures features;
107 deMemset(&features, 0, sizeof(features));
108 return features;
109 }
110
createDeviceWithWsi(const InstanceInterface & vki,VkPhysicalDevice physicalDevice,const Extensions & supportedExtensions,const deUint32 queueFamilyIndex,const VkAllocationCallbacks * pAllocator=DE_NULL)111 Move<VkDevice> createDeviceWithWsi (const InstanceInterface& vki,
112 VkPhysicalDevice physicalDevice,
113 const Extensions& supportedExtensions,
114 const deUint32 queueFamilyIndex,
115 const VkAllocationCallbacks* pAllocator = DE_NULL)
116 {
117 const float queuePriorities[] = { 1.0f };
118 const VkDeviceQueueCreateInfo queueInfos[] =
119 {
120 {
121 VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
122 DE_NULL,
123 (VkDeviceQueueCreateFlags)0,
124 queueFamilyIndex,
125 DE_LENGTH_OF_ARRAY(queuePriorities),
126 &queuePriorities[0]
127 }
128 };
129 const VkPhysicalDeviceFeatures features = getDeviceFeaturesForWsi();
130 const char* const extensions[] = { "VK_KHR_swapchain" };
131 const VkDeviceCreateInfo deviceParams =
132 {
133 VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
134 DE_NULL,
135 (VkDeviceCreateFlags)0,
136 DE_LENGTH_OF_ARRAY(queueInfos),
137 &queueInfos[0],
138 0u, // enabledLayerCount
139 DE_NULL, // ppEnabledLayerNames
140 DE_LENGTH_OF_ARRAY(extensions), // enabledExtensionCount
141 DE_ARRAY_BEGIN(extensions), // ppEnabledExtensionNames
142 &features
143 };
144
145 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(extensions); ++ndx)
146 {
147 if (!isExtensionSupported(supportedExtensions, RequiredExtension(extensions[ndx])))
148 TCU_THROW(NotSupportedError, (string(extensions[ndx]) + " is not supported").c_str());
149 }
150
151 return createDevice(vki, physicalDevice, &deviceParams, pAllocator);
152 }
153
getNumQueueFamilyIndices(const InstanceInterface & vki,VkPhysicalDevice physicalDevice)154 deUint32 getNumQueueFamilyIndices (const InstanceInterface& vki, VkPhysicalDevice physicalDevice)
155 {
156 deUint32 numFamilies = 0;
157
158 vki.getPhysicalDeviceQueueFamilyProperties(physicalDevice, &numFamilies, DE_NULL);
159
160 return numFamilies;
161 }
162
getSupportedQueueFamilyIndices(const InstanceInterface & vki,VkPhysicalDevice physicalDevice,VkSurfaceKHR surface)163 vector<deUint32> getSupportedQueueFamilyIndices (const InstanceInterface& vki, VkPhysicalDevice physicalDevice, VkSurfaceKHR surface)
164 {
165 const deUint32 numTotalFamilyIndices = getNumQueueFamilyIndices(vki, physicalDevice);
166 vector<deUint32> supportedFamilyIndices;
167
168 for (deUint32 queueFamilyNdx = 0; queueFamilyNdx < numTotalFamilyIndices; ++queueFamilyNdx)
169 {
170 if (getPhysicalDeviceSurfaceSupport(vki, physicalDevice, queueFamilyNdx, surface) != VK_FALSE)
171 supportedFamilyIndices.push_back(queueFamilyNdx);
172 }
173
174 return supportedFamilyIndices;
175 }
176
chooseQueueFamilyIndex(const InstanceInterface & vki,VkPhysicalDevice physicalDevice,VkSurfaceKHR surface)177 deUint32 chooseQueueFamilyIndex (const InstanceInterface& vki, VkPhysicalDevice physicalDevice, VkSurfaceKHR surface)
178 {
179 const vector<deUint32> supportedFamilyIndices = getSupportedQueueFamilyIndices(vki, physicalDevice, surface);
180
181 if (supportedFamilyIndices.empty())
182 TCU_THROW(NotSupportedError, "Device doesn't support presentation");
183
184 return supportedFamilyIndices[0];
185 }
186
187 struct InstanceHelper
188 {
189 const vector<VkExtensionProperties> supportedExtensions;
190 const Unique<VkInstance> instance;
191 const InstanceDriver vki;
192
InstanceHelpervkt::wsi::__anonc9b0035a0111::InstanceHelper193 InstanceHelper (Context& context, Type wsiType, const VkAllocationCallbacks* pAllocator = DE_NULL)
194 : supportedExtensions (enumerateInstanceExtensionProperties(context.getPlatformInterface(),
195 DE_NULL))
196 , instance (createInstanceWithWsi(context.getPlatformInterface(),
197 supportedExtensions,
198 wsiType,
199 pAllocator))
200 , vki (context.getPlatformInterface(), *instance)
201 {}
202 };
203
getDeviceQueue(const DeviceInterface & vkd,VkDevice device,deUint32 queueFamilyIndex,deUint32 queueIndex)204 VkQueue getDeviceQueue (const DeviceInterface& vkd, VkDevice device, deUint32 queueFamilyIndex, deUint32 queueIndex)
205 {
206 VkQueue queue = (VkQueue)0;
207 vkd.getDeviceQueue(device, queueFamilyIndex, queueIndex, &queue);
208 return queue;
209 }
210
211 struct DeviceHelper
212 {
213 const VkPhysicalDevice physicalDevice;
214 const deUint32 queueFamilyIndex;
215 const Unique<VkDevice> device;
216 const DeviceDriver vkd;
217 const VkQueue queue;
218
DeviceHelpervkt::wsi::__anonc9b0035a0111::DeviceHelper219 DeviceHelper (Context& context,
220 const InstanceInterface& vki,
221 VkInstance instance,
222 VkSurfaceKHR surface,
223 const VkAllocationCallbacks* pAllocator = DE_NULL)
224 : physicalDevice (chooseDevice(vki, instance, context.getTestContext().getCommandLine()))
225 , queueFamilyIndex (chooseQueueFamilyIndex(vki, physicalDevice, surface))
226 , device (createDeviceWithWsi(vki,
227 physicalDevice,
228 enumerateDeviceExtensionProperties(vki, physicalDevice, DE_NULL),
229 queueFamilyIndex,
230 pAllocator))
231 , vkd (vki, *device)
232 , queue (getDeviceQueue(vkd, *device, queueFamilyIndex, 0))
233 {
234 }
235 };
236
createDisplay(const vk::Platform & platform,const Extensions & supportedExtensions,Type wsiType)237 MovePtr<Display> createDisplay (const vk::Platform& platform,
238 const Extensions& supportedExtensions,
239 Type wsiType)
240 {
241 try
242 {
243 return MovePtr<Display>(platform.createWsiDisplay(wsiType));
244 }
245 catch (const tcu::NotSupportedError& e)
246 {
247 if (isExtensionSupported(supportedExtensions, RequiredExtension(getExtensionName(wsiType))))
248 {
249 // If VK_KHR_{platform}_surface was supported, vk::Platform implementation
250 // must support creating native display & window for that WSI type.
251 throw tcu::TestError(e.getMessage());
252 }
253 else
254 throw;
255 }
256 }
257
createWindow(const Display & display,const Maybe<UVec2> & initialSize)258 MovePtr<Window> createWindow (const Display& display, const Maybe<UVec2>& initialSize)
259 {
260 try
261 {
262 return MovePtr<Window>(display.createWindow(initialSize));
263 }
264 catch (const tcu::NotSupportedError& e)
265 {
266 // See createDisplay - assuming that wsi::Display was supported platform port
267 // should also support creating a window.
268 throw tcu::TestError(e.getMessage());
269 }
270 }
271
272 struct NativeObjects
273 {
274 const UniquePtr<Display> display;
275 const UniquePtr<Window> window;
276
NativeObjectsvkt::wsi::__anonc9b0035a0111::NativeObjects277 NativeObjects (Context& context,
278 const Extensions& supportedExtensions,
279 Type wsiType,
280 const Maybe<UVec2>& initialWindowSize = tcu::nothing<UVec2>())
281 : display (createDisplay(context.getTestContext().getPlatform().getVulkanPlatform(), supportedExtensions, wsiType))
282 , window (createWindow(*display, initialWindowSize))
283 {}
284 };
285
286 enum TestDimension
287 {
288 TEST_DIMENSION_MIN_IMAGE_COUNT = 0, //!< Test all supported image counts
289 TEST_DIMENSION_IMAGE_FORMAT, //!< Test all supported formats
290 TEST_DIMENSION_IMAGE_EXTENT, //!< Test various (supported) extents
291 TEST_DIMENSION_IMAGE_ARRAY_LAYERS,
292 TEST_DIMENSION_IMAGE_USAGE,
293 TEST_DIMENSION_IMAGE_SHARING_MODE,
294 TEST_DIMENSION_PRE_TRANSFORM,
295 TEST_DIMENSION_COMPOSITE_ALPHA,
296 TEST_DIMENSION_PRESENT_MODE,
297 TEST_DIMENSION_CLIPPED,
298
299 TEST_DIMENSION_LAST
300 };
301
getTestDimensionName(TestDimension dimension)302 const char* getTestDimensionName (TestDimension dimension)
303 {
304 static const char* const s_names[] =
305 {
306 "min_image_count",
307 "image_format",
308 "image_extent",
309 "image_array_layers",
310 "image_usage",
311 "image_sharing_mode",
312 "pre_transform",
313 "composite_alpha",
314 "present_mode",
315 "clipped"
316 };
317 return de::getSizedArrayElement<TEST_DIMENSION_LAST>(s_names, dimension);
318 }
319
320 struct TestParameters
321 {
322 Type wsiType;
323 TestDimension dimension;
324
TestParametersvkt::wsi::__anonc9b0035a0111::TestParameters325 TestParameters (Type wsiType_, TestDimension dimension_)
326 : wsiType (wsiType_)
327 , dimension (dimension_)
328 {}
329
TestParametersvkt::wsi::__anonc9b0035a0111::TestParameters330 TestParameters (void)
331 : wsiType (TYPE_LAST)
332 , dimension (TEST_DIMENSION_LAST)
333 {}
334 };
335
generateSwapchainParameterCases(Type wsiType,TestDimension dimension,const VkSurfaceCapabilitiesKHR & capabilities,const vector<VkSurfaceFormatKHR> & formats,const vector<VkPresentModeKHR> & presentModes)336 vector<VkSwapchainCreateInfoKHR> generateSwapchainParameterCases (Type wsiType,
337 TestDimension dimension,
338 const VkSurfaceCapabilitiesKHR& capabilities,
339 const vector<VkSurfaceFormatKHR>& formats,
340 const vector<VkPresentModeKHR>& presentModes)
341 {
342 const PlatformProperties& platformProperties = getPlatformProperties(wsiType);
343 vector<VkSwapchainCreateInfoKHR> cases;
344 const VkSurfaceTransformFlagBitsKHR defaultTransform = (capabilities.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) ? VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR : capabilities.currentTransform;
345 const VkSwapchainCreateInfoKHR baseParameters =
346 {
347 VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
348 DE_NULL,
349 (VkSwapchainCreateFlagsKHR)0,
350 (VkSurfaceKHR)0,
351 capabilities.minImageCount,
352 formats[0].format,
353 formats[0].colorSpace,
354 (platformProperties.swapchainExtent == PlatformProperties::SWAPCHAIN_EXTENT_SETS_WINDOW_SIZE
355 ? capabilities.minImageExtent : capabilities.currentExtent),
356 1u, // imageArrayLayers
357 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
358 VK_SHARING_MODE_EXCLUSIVE,
359 0u,
360 (const deUint32*)DE_NULL,
361 defaultTransform,
362 VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
363 VK_PRESENT_MODE_FIFO_KHR,
364 VK_FALSE, // clipped
365 (VkSwapchainKHR)0 // oldSwapchain
366 };
367
368 switch (dimension)
369 {
370 case TEST_DIMENSION_MIN_IMAGE_COUNT:
371 {
372 const deUint32 maxImageCountToTest = de::clamp(16u, capabilities.minImageCount, (capabilities.maxImageCount > 0) ? capabilities.maxImageCount : capabilities.minImageCount + 16u);
373
374 for (deUint32 imageCount = capabilities.minImageCount; imageCount <= maxImageCountToTest; ++imageCount)
375 {
376 cases.push_back(baseParameters);
377 cases.back().minImageCount = imageCount;
378 }
379
380 break;
381 }
382
383 case TEST_DIMENSION_IMAGE_FORMAT:
384 {
385 for (vector<VkSurfaceFormatKHR>::const_iterator curFmt = formats.begin(); curFmt != formats.end(); ++curFmt)
386 {
387 cases.push_back(baseParameters);
388 cases.back().imageFormat = curFmt->format;
389 cases.back().imageColorSpace = curFmt->colorSpace;
390 }
391
392 break;
393 }
394
395 case TEST_DIMENSION_IMAGE_EXTENT:
396 {
397 static const VkExtent2D s_testSizes[] =
398 {
399 { 1, 1 },
400 { 16, 32 },
401 { 32, 16 },
402 { 632, 231 },
403 { 117, 998 },
404 };
405
406 if (platformProperties.swapchainExtent == PlatformProperties::SWAPCHAIN_EXTENT_SETS_WINDOW_SIZE ||
407 platformProperties.swapchainExtent == PlatformProperties::SWAPCHAIN_EXTENT_SCALED_TO_WINDOW_SIZE)
408 {
409 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(s_testSizes); ++ndx)
410 {
411 cases.push_back(baseParameters);
412 cases.back().imageExtent.width = de::clamp(s_testSizes[ndx].width, capabilities.minImageExtent.width, capabilities.maxImageExtent.width);
413 cases.back().imageExtent.height = de::clamp(s_testSizes[ndx].height, capabilities.minImageExtent.height, capabilities.maxImageExtent.height);
414 }
415 }
416
417 if (platformProperties.swapchainExtent != PlatformProperties::SWAPCHAIN_EXTENT_SETS_WINDOW_SIZE)
418 {
419 cases.push_back(baseParameters);
420 cases.back().imageExtent = capabilities.currentExtent;
421 }
422
423 if (platformProperties.swapchainExtent != PlatformProperties::SWAPCHAIN_EXTENT_MUST_MATCH_WINDOW_SIZE)
424 {
425 cases.push_back(baseParameters);
426 cases.back().imageExtent = capabilities.minImageExtent;
427
428 cases.push_back(baseParameters);
429 cases.back().imageExtent = capabilities.maxImageExtent;
430 }
431
432 break;
433 }
434
435 case TEST_DIMENSION_IMAGE_ARRAY_LAYERS:
436 {
437 const deUint32 maxLayers = de::min(capabilities.maxImageArrayLayers, 16u);
438
439 for (deUint32 numLayers = 1; numLayers <= maxLayers; ++numLayers)
440 {
441 cases.push_back(baseParameters);
442 cases.back().imageArrayLayers = numLayers;
443 }
444
445 break;
446 }
447
448 case TEST_DIMENSION_IMAGE_USAGE:
449 {
450 for (deUint32 flags = 1u; flags <= capabilities.supportedUsageFlags; ++flags)
451 {
452 if ((flags & ~capabilities.supportedUsageFlags) == 0)
453 {
454 cases.push_back(baseParameters);
455 cases.back().imageUsage = flags;
456 }
457 }
458
459 break;
460 }
461
462 case TEST_DIMENSION_IMAGE_SHARING_MODE:
463 {
464 cases.push_back(baseParameters);
465 cases.back().imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
466
467 cases.push_back(baseParameters);
468 cases.back().imageSharingMode = VK_SHARING_MODE_CONCURRENT;
469
470 break;
471 }
472
473 case TEST_DIMENSION_PRE_TRANSFORM:
474 {
475 for (deUint32 transform = 1u;
476 transform <= capabilities.supportedTransforms;
477 transform = transform<<1u)
478 {
479 if ((transform & capabilities.supportedTransforms) != 0)
480 {
481 cases.push_back(baseParameters);
482 cases.back().preTransform = (VkSurfaceTransformFlagBitsKHR)transform;
483 }
484 }
485
486 break;
487 }
488
489 case TEST_DIMENSION_COMPOSITE_ALPHA:
490 {
491 for (deUint32 alphaMode = 1u;
492 alphaMode <= capabilities.supportedCompositeAlpha;
493 alphaMode = alphaMode<<1u)
494 {
495 if ((alphaMode & capabilities.supportedCompositeAlpha) != 0)
496 {
497 cases.push_back(baseParameters);
498 cases.back().compositeAlpha = (VkCompositeAlphaFlagBitsKHR)alphaMode;
499 }
500 }
501
502 break;
503 }
504
505 case TEST_DIMENSION_PRESENT_MODE:
506 {
507 for (vector<VkPresentModeKHR>::const_iterator curMode = presentModes.begin(); curMode != presentModes.end(); ++curMode)
508 {
509 cases.push_back(baseParameters);
510 cases.back().presentMode = *curMode;
511 }
512
513 break;
514 }
515
516 case TEST_DIMENSION_CLIPPED:
517 {
518 cases.push_back(baseParameters);
519 cases.back().clipped = VK_FALSE;
520
521 cases.push_back(baseParameters);
522 cases.back().clipped = VK_TRUE;
523
524 break;
525 }
526
527 default:
528 DE_FATAL("Impossible");
529 }
530
531 DE_ASSERT(!cases.empty());
532 return cases;
533 }
534
generateSwapchainParameterCases(Type wsiType,TestDimension dimension,const InstanceInterface & vki,VkPhysicalDevice physicalDevice,VkSurfaceKHR surface)535 vector<VkSwapchainCreateInfoKHR> generateSwapchainParameterCases (Type wsiType,
536 TestDimension dimension,
537 const InstanceInterface& vki,
538 VkPhysicalDevice physicalDevice,
539 VkSurfaceKHR surface)
540 {
541 const VkSurfaceCapabilitiesKHR capabilities = getPhysicalDeviceSurfaceCapabilities(vki,
542 physicalDevice,
543 surface);
544 const vector<VkSurfaceFormatKHR> formats = getPhysicalDeviceSurfaceFormats(vki,
545 physicalDevice,
546 surface);
547 const vector<VkPresentModeKHR> presentModes = getPhysicalDeviceSurfacePresentModes(vki,
548 physicalDevice,
549 surface);
550
551 return generateSwapchainParameterCases(wsiType, dimension, capabilities, formats, presentModes);
552 }
553
createSwapchainTest(Context & context,TestParameters params)554 tcu::TestStatus createSwapchainTest (Context& context, TestParameters params)
555 {
556 const InstanceHelper instHelper (context, params.wsiType);
557 const NativeObjects native (context, instHelper.supportedExtensions, params.wsiType);
558 const Unique<VkSurfaceKHR> surface (createSurface(instHelper.vki, *instHelper.instance, params.wsiType, *native.display, *native.window));
559 const DeviceHelper devHelper (context, instHelper.vki, *instHelper.instance, *surface);
560 const vector<VkSwapchainCreateInfoKHR> cases (generateSwapchainParameterCases(params.wsiType, params.dimension, instHelper.vki, devHelper.physicalDevice, *surface));
561
562 for (size_t caseNdx = 0; caseNdx < cases.size(); ++caseNdx)
563 {
564 VkSwapchainCreateInfoKHR curParams = cases[caseNdx];
565
566 curParams.surface = *surface;
567 curParams.queueFamilyIndexCount = 1u;
568 curParams.pQueueFamilyIndices = &devHelper.queueFamilyIndex;
569
570 context.getTestContext().getLog()
571 << TestLog::Message << "Sub-case " << (caseNdx+1) << " / " << cases.size() << ": " << curParams << TestLog::EndMessage;
572
573 {
574 const Unique<VkSwapchainKHR> swapchain (createSwapchainKHR(devHelper.vkd, *devHelper.device, &curParams));
575 }
576 }
577
578 return tcu::TestStatus::pass("Creating swapchain succeeded");
579 }
580
581 class CreateSwapchainSimulateOOMTest : public TestInstance
582 {
583 public:
CreateSwapchainSimulateOOMTest(Context & context,TestParameters params)584 CreateSwapchainSimulateOOMTest (Context& context, TestParameters params)
585 : TestInstance (context)
586 , m_params (params)
587 , m_numPassingAllocs (0)
588 {
589 }
590
591 tcu::TestStatus iterate (void);
592
593 private:
594 const TestParameters m_params;
595 deUint32 m_numPassingAllocs;
596 };
597
iterate(void)598 tcu::TestStatus CreateSwapchainSimulateOOMTest::iterate (void)
599 {
600 tcu::TestLog& log = m_context.getTestContext().getLog();
601
602 // \note This is a little counter-intuitive order (iterating on callback count until all cases pass)
603 // but since cases depend on what device reports, it is the only easy way. In practice
604 // we should see same number of total callbacks (and executed code) regardless of the
605 // loop order.
606
607 if (m_numPassingAllocs <= 16*1024u)
608 {
609 AllocationCallbackRecorder allocationRecorder (getSystemAllocator());
610 DeterministicFailAllocator failingAllocator (allocationRecorder.getCallbacks(), m_numPassingAllocs);
611 bool gotOOM = false;
612
613 log << TestLog::Message << "Testing with " << m_numPassingAllocs << " first allocations succeeding" << TestLog::EndMessage;
614
615 try
616 {
617 const InstanceHelper instHelper (m_context, m_params.wsiType, failingAllocator.getCallbacks());
618 const NativeObjects native (m_context, instHelper.supportedExtensions, m_params.wsiType);
619 const Unique<VkSurfaceKHR> surface (createSurface(instHelper.vki,
620 *instHelper.instance,
621 m_params.wsiType,
622 *native.display,
623 *native.window,
624 failingAllocator.getCallbacks()));
625 const DeviceHelper devHelper (m_context, instHelper.vki, *instHelper.instance, *surface, failingAllocator.getCallbacks());
626 const vector<VkSwapchainCreateInfoKHR> cases (generateSwapchainParameterCases(m_params.wsiType, m_params.dimension, instHelper.vki, devHelper.physicalDevice, *surface));
627
628 for (size_t caseNdx = 0; caseNdx < cases.size(); ++caseNdx)
629 {
630 VkSwapchainCreateInfoKHR curParams = cases[caseNdx];
631
632 curParams.surface = *surface;
633 curParams.queueFamilyIndexCount = 1u;
634 curParams.pQueueFamilyIndices = &devHelper.queueFamilyIndex;
635
636 log
637 << TestLog::Message << "Sub-case " << (caseNdx+1) << " / " << cases.size() << TestLog::EndMessage;
638
639 {
640 const Unique<VkSwapchainKHR> swapchain (createSwapchainKHR(devHelper.vkd, *devHelper.device, &curParams, failingAllocator.getCallbacks()));
641 }
642 }
643 }
644 catch (const OutOfMemoryError& e)
645 {
646 log << TestLog::Message << "Got " << e.getError() << TestLog::EndMessage;
647 gotOOM = true;
648 }
649
650 if (!validateAndLog(log, allocationRecorder, 0u))
651 return tcu::TestStatus::fail("Detected invalid system allocation callback");
652
653 if (!gotOOM)
654 {
655 log << TestLog::Message << "Creating surface succeeded!" << TestLog::EndMessage;
656
657 if (m_numPassingAllocs == 0)
658 return tcu::TestStatus(QP_TEST_RESULT_QUALITY_WARNING, "Allocation callbacks were not used");
659 else
660 return tcu::TestStatus::pass("OOM simulation completed");
661 }
662
663 m_numPassingAllocs++;
664 return tcu::TestStatus::incomplete();
665 }
666 else
667 return tcu::TestStatus(QP_TEST_RESULT_QUALITY_WARNING, "Creating swapchain did not succeed, callback limit exceeded");
668 }
669
670 struct GroupParameters
671 {
672 typedef FunctionInstance1<TestParameters>::Function Function;
673
674 Type wsiType;
675 Function function;
676
GroupParametersvkt::wsi::__anonc9b0035a0111::GroupParameters677 GroupParameters (Type wsiType_, Function function_)
678 : wsiType (wsiType_)
679 , function (function_)
680 {}
681
GroupParametersvkt::wsi::__anonc9b0035a0111::GroupParameters682 GroupParameters (void)
683 : wsiType (TYPE_LAST)
684 , function ((Function)DE_NULL)
685 {}
686 };
687
populateSwapchainGroup(tcu::TestCaseGroup * testGroup,GroupParameters params)688 void populateSwapchainGroup (tcu::TestCaseGroup* testGroup, GroupParameters params)
689 {
690 for (int dimensionNdx = 0; dimensionNdx < TEST_DIMENSION_LAST; ++dimensionNdx)
691 {
692 const TestDimension testDimension = (TestDimension)dimensionNdx;
693
694 addFunctionCase(testGroup, getTestDimensionName(testDimension), "", params.function, TestParameters(params.wsiType, testDimension));
695 }
696 }
697
populateSwapchainOOMGroup(tcu::TestCaseGroup * testGroup,Type wsiType)698 void populateSwapchainOOMGroup (tcu::TestCaseGroup* testGroup, Type wsiType)
699 {
700 for (int dimensionNdx = 0; dimensionNdx < TEST_DIMENSION_LAST; ++dimensionNdx)
701 {
702 const TestDimension testDimension = (TestDimension)dimensionNdx;
703
704 testGroup->addChild(new InstanceFactory1<CreateSwapchainSimulateOOMTest, TestParameters>(testGroup->getTestContext(), tcu::NODETYPE_SELF_VALIDATE, getTestDimensionName(testDimension), "", TestParameters(wsiType, testDimension)));
705 }
706 }
707
getBasicSwapchainParameters(Type wsiType,const InstanceInterface & vki,VkPhysicalDevice physicalDevice,VkSurfaceKHR surface,const tcu::UVec2 & desiredSize,deUint32 desiredImageCount)708 VkSwapchainCreateInfoKHR getBasicSwapchainParameters (Type wsiType,
709 const InstanceInterface& vki,
710 VkPhysicalDevice physicalDevice,
711 VkSurfaceKHR surface,
712 const tcu::UVec2& desiredSize,
713 deUint32 desiredImageCount)
714 {
715 const VkSurfaceCapabilitiesKHR capabilities = getPhysicalDeviceSurfaceCapabilities(vki,
716 physicalDevice,
717 surface);
718 const vector<VkSurfaceFormatKHR> formats = getPhysicalDeviceSurfaceFormats(vki,
719 physicalDevice,
720 surface);
721 const PlatformProperties& platformProperties = getPlatformProperties(wsiType);
722 const VkSurfaceTransformFlagBitsKHR transform = (capabilities.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) ? VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR : capabilities.currentTransform;
723 const VkSwapchainCreateInfoKHR parameters =
724 {
725 VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
726 DE_NULL,
727 (VkSwapchainCreateFlagsKHR)0,
728 surface,
729 de::clamp(desiredImageCount, capabilities.minImageCount, capabilities.maxImageCount > 0 ? capabilities.maxImageCount : capabilities.minImageCount + desiredImageCount),
730 formats[0].format,
731 formats[0].colorSpace,
732 (platformProperties.swapchainExtent == PlatformProperties::SWAPCHAIN_EXTENT_MUST_MATCH_WINDOW_SIZE
733 ? capabilities.currentExtent : vk::makeExtent2D(desiredSize.x(), desiredSize.y())),
734 1u, // imageArrayLayers
735 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
736 VK_SHARING_MODE_EXCLUSIVE,
737 0u,
738 (const deUint32*)DE_NULL,
739 transform,
740 VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
741 VK_PRESENT_MODE_FIFO_KHR,
742 VK_FALSE, // clipped
743 (VkSwapchainKHR)0 // oldSwapchain
744 };
745
746 return parameters;
747 }
748
749 typedef de::SharedPtr<Unique<VkImageView> > ImageViewSp;
750 typedef de::SharedPtr<Unique<VkFramebuffer> > FramebufferSp;
751
752 class TriangleRenderer
753 {
754 public:
755 TriangleRenderer (const DeviceInterface& vkd,
756 const VkDevice device,
757 Allocator& allocator,
758 const BinaryCollection& binaryRegistry,
759 const vector<VkImage> swapchainImages,
760 const VkFormat framebufferFormat,
761 const UVec2& renderSize);
762 ~TriangleRenderer (void);
763
764 void recordFrame (VkCommandBuffer cmdBuffer,
765 deUint32 imageNdx,
766 deUint32 frameNdx) const;
767
768 static void getPrograms (SourceCollections& dst);
769
770 private:
771 static Move<VkRenderPass> createRenderPass (const DeviceInterface& vkd,
772 const VkDevice device,
773 const VkFormat colorAttachmentFormat);
774 static Move<VkPipelineLayout> createPipelineLayout(const DeviceInterface& vkd,
775 VkDevice device);
776 static Move<VkPipeline> createPipeline (const DeviceInterface& vkd,
777 const VkDevice device,
778 const VkRenderPass renderPass,
779 const VkPipelineLayout pipelineLayout,
780 const BinaryCollection& binaryCollection,
781 const UVec2& renderSize);
782
783 static Move<VkImageView> createAttachmentView(const DeviceInterface& vkd,
784 const VkDevice device,
785 const VkImage image,
786 const VkFormat format);
787 static Move<VkFramebuffer> createFramebuffer (const DeviceInterface& vkd,
788 const VkDevice device,
789 const VkRenderPass renderPass,
790 const VkImageView colorAttachment,
791 const UVec2& renderSize);
792
793 static Move<VkBuffer> createBuffer (const DeviceInterface& vkd,
794 VkDevice device,
795 VkDeviceSize size,
796 VkBufferUsageFlags usage);
797
798 const DeviceInterface& m_vkd;
799
800 const vector<VkImage> m_swapchainImages;
801 const tcu::UVec2 m_renderSize;
802
803 const Unique<VkRenderPass> m_renderPass;
804 const Unique<VkPipelineLayout> m_pipelineLayout;
805 const Unique<VkPipeline> m_pipeline;
806
807 const Unique<VkBuffer> m_vertexBuffer;
808 const UniquePtr<Allocation> m_vertexBufferMemory;
809
810 vector<ImageViewSp> m_attachmentViews;
811 vector<FramebufferSp> m_framebuffers;
812 };
813
createRenderPass(const DeviceInterface & vkd,const VkDevice device,const VkFormat colorAttachmentFormat)814 Move<VkRenderPass> TriangleRenderer::createRenderPass (const DeviceInterface& vkd,
815 const VkDevice device,
816 const VkFormat colorAttachmentFormat)
817 {
818 const VkAttachmentDescription colorAttDesc =
819 {
820 (VkAttachmentDescriptionFlags)0,
821 colorAttachmentFormat,
822 VK_SAMPLE_COUNT_1_BIT,
823 VK_ATTACHMENT_LOAD_OP_CLEAR,
824 VK_ATTACHMENT_STORE_OP_STORE,
825 VK_ATTACHMENT_LOAD_OP_DONT_CARE,
826 VK_ATTACHMENT_STORE_OP_DONT_CARE,
827 VK_IMAGE_LAYOUT_UNDEFINED,
828 VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
829 };
830 const VkAttachmentReference colorAttRef =
831 {
832 0u,
833 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
834 };
835 const VkSubpassDescription subpassDesc =
836 {
837 (VkSubpassDescriptionFlags)0u,
838 VK_PIPELINE_BIND_POINT_GRAPHICS,
839 0u, // inputAttachmentCount
840 DE_NULL, // pInputAttachments
841 1u, // colorAttachmentCount
842 &colorAttRef, // pColorAttachments
843 DE_NULL, // pResolveAttachments
844 DE_NULL, // depthStencilAttachment
845 0u, // preserveAttachmentCount
846 DE_NULL, // pPreserveAttachments
847 };
848 const VkSubpassDependency dependencies[] =
849 {
850 {
851 VK_SUBPASS_EXTERNAL, // srcSubpass
852 0u, // dstSubpass
853 VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
854 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
855 VK_ACCESS_MEMORY_READ_BIT,
856 (VK_ACCESS_COLOR_ATTACHMENT_READ_BIT|
857 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT),
858 VK_DEPENDENCY_BY_REGION_BIT
859 },
860 {
861 0u, // srcSubpass
862 VK_SUBPASS_EXTERNAL, // dstSubpass
863 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
864 VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
865 (VK_ACCESS_COLOR_ATTACHMENT_READ_BIT|
866 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT),
867 VK_ACCESS_MEMORY_READ_BIT,
868 VK_DEPENDENCY_BY_REGION_BIT
869 },
870 };
871 const VkRenderPassCreateInfo renderPassParams =
872 {
873 VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
874 DE_NULL,
875 (VkRenderPassCreateFlags)0,
876 1u,
877 &colorAttDesc,
878 1u,
879 &subpassDesc,
880 DE_LENGTH_OF_ARRAY(dependencies),
881 dependencies,
882 };
883
884 return vk::createRenderPass(vkd, device, &renderPassParams);
885 }
886
createPipelineLayout(const DeviceInterface & vkd,const VkDevice device)887 Move<VkPipelineLayout> TriangleRenderer::createPipelineLayout (const DeviceInterface& vkd,
888 const VkDevice device)
889 {
890 const VkPushConstantRange pushConstantRange =
891 {
892 VK_SHADER_STAGE_VERTEX_BIT,
893 0u, // offset
894 (deUint32)sizeof(deUint32), // size
895 };
896 const VkPipelineLayoutCreateInfo pipelineLayoutParams =
897 {
898 VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
899 DE_NULL,
900 (vk::VkPipelineLayoutCreateFlags)0,
901 0u, // setLayoutCount
902 DE_NULL, // pSetLayouts
903 1u,
904 &pushConstantRange,
905 };
906
907 return vk::createPipelineLayout(vkd, device, &pipelineLayoutParams);
908 }
909
createPipeline(const DeviceInterface & vkd,const VkDevice device,const VkRenderPass renderPass,const VkPipelineLayout pipelineLayout,const BinaryCollection & binaryCollection,const UVec2 & renderSize)910 Move<VkPipeline> TriangleRenderer::createPipeline (const DeviceInterface& vkd,
911 const VkDevice device,
912 const VkRenderPass renderPass,
913 const VkPipelineLayout pipelineLayout,
914 const BinaryCollection& binaryCollection,
915 const UVec2& renderSize)
916 {
917 // \note VkShaderModules are fully consumed by vkCreateGraphicsPipelines()
918 // and can be deleted immediately following that call.
919 const Unique<VkShaderModule> vertShaderModule (createShaderModule(vkd, device, binaryCollection.get("tri-vert"), 0));
920 const Unique<VkShaderModule> fragShaderModule (createShaderModule(vkd, device, binaryCollection.get("tri-frag"), 0));
921
922 const VkSpecializationInfo emptyShaderSpecParams =
923 {
924 0u, // mapEntryCount
925 DE_NULL, // pMap
926 0, // dataSize
927 DE_NULL, // pData
928 };
929 const VkPipelineShaderStageCreateInfo shaderStageParams[] =
930 {
931 {
932 VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
933 DE_NULL,
934 (VkPipelineShaderStageCreateFlags)0,
935 VK_SHADER_STAGE_VERTEX_BIT,
936 *vertShaderModule,
937 "main",
938 &emptyShaderSpecParams,
939 },
940 {
941 VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
942 DE_NULL,
943 (VkPipelineShaderStageCreateFlags)0,
944 VK_SHADER_STAGE_FRAGMENT_BIT,
945 *fragShaderModule,
946 "main",
947 &emptyShaderSpecParams,
948 }
949 };
950 const VkPipelineDepthStencilStateCreateInfo depthStencilParams =
951 {
952 VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,
953 DE_NULL,
954 (VkPipelineDepthStencilStateCreateFlags)0,
955 DE_FALSE, // depthTestEnable
956 DE_FALSE, // depthWriteEnable
957 VK_COMPARE_OP_ALWAYS, // depthCompareOp
958 DE_FALSE, // depthBoundsTestEnable
959 DE_FALSE, // stencilTestEnable
960 {
961 VK_STENCIL_OP_KEEP, // failOp
962 VK_STENCIL_OP_KEEP, // passOp
963 VK_STENCIL_OP_KEEP, // depthFailOp
964 VK_COMPARE_OP_ALWAYS, // compareOp
965 0u, // compareMask
966 0u, // writeMask
967 0u, // reference
968 }, // front
969 {
970 VK_STENCIL_OP_KEEP, // failOp
971 VK_STENCIL_OP_KEEP, // passOp
972 VK_STENCIL_OP_KEEP, // depthFailOp
973 VK_COMPARE_OP_ALWAYS, // compareOp
974 0u, // compareMask
975 0u, // writeMask
976 0u, // reference
977 }, // back
978 -1.0f, // minDepthBounds
979 +1.0f, // maxDepthBounds
980 };
981 const VkViewport viewport0 =
982 {
983 0.0f, // x
984 0.0f, // y
985 (float)renderSize.x(), // width
986 (float)renderSize.y(), // height
987 0.0f, // minDepth
988 1.0f, // maxDepth
989 };
990 const VkRect2D scissor0 =
991 {
992 { 0u, 0u, }, // offset
993 { renderSize.x(), renderSize.y() }, // extent
994 };
995 const VkPipelineViewportStateCreateInfo viewportParams =
996 {
997 VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
998 DE_NULL,
999 (VkPipelineViewportStateCreateFlags)0,
1000 1u,
1001 &viewport0,
1002 1u,
1003 &scissor0
1004 };
1005 const VkPipelineMultisampleStateCreateInfo multisampleParams =
1006 {
1007 VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
1008 DE_NULL,
1009 (VkPipelineMultisampleStateCreateFlags)0,
1010 VK_SAMPLE_COUNT_1_BIT, // rasterizationSamples
1011 VK_FALSE, // sampleShadingEnable
1012 0.0f, // minSampleShading
1013 (const VkSampleMask*)DE_NULL, // sampleMask
1014 VK_FALSE, // alphaToCoverageEnable
1015 VK_FALSE, // alphaToOneEnable
1016 };
1017 const VkPipelineRasterizationStateCreateInfo rasterParams =
1018 {
1019 VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
1020 DE_NULL,
1021 (VkPipelineRasterizationStateCreateFlags)0,
1022 VK_FALSE, // depthClampEnable
1023 VK_FALSE, // rasterizerDiscardEnable
1024 VK_POLYGON_MODE_FILL, // polygonMode
1025 VK_CULL_MODE_NONE, // cullMode
1026 VK_FRONT_FACE_COUNTER_CLOCKWISE, // frontFace
1027 VK_FALSE, // depthBiasEnable
1028 0.0f, // depthBiasConstantFactor
1029 0.0f, // depthBiasClamp
1030 0.0f, // depthBiasSlopeFactor
1031 1.0f, // lineWidth
1032 };
1033 const VkPipelineInputAssemblyStateCreateInfo inputAssemblyParams =
1034 {
1035 VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
1036 DE_NULL,
1037 (VkPipelineInputAssemblyStateCreateFlags)0,
1038 VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
1039 DE_FALSE, // primitiveRestartEnable
1040 };
1041 const VkVertexInputBindingDescription vertexBinding0 =
1042 {
1043 0u, // binding
1044 (deUint32)sizeof(tcu::Vec4), // stride
1045 VK_VERTEX_INPUT_RATE_VERTEX, // inputRate
1046 };
1047 const VkVertexInputAttributeDescription vertexAttrib0 =
1048 {
1049 0u, // location
1050 0u, // binding
1051 VK_FORMAT_R32G32B32A32_SFLOAT, // format
1052 0u, // offset
1053 };
1054 const VkPipelineVertexInputStateCreateInfo vertexInputStateParams =
1055 {
1056 VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
1057 DE_NULL,
1058 (VkPipelineVertexInputStateCreateFlags)0,
1059 1u,
1060 &vertexBinding0,
1061 1u,
1062 &vertexAttrib0,
1063 };
1064 const VkPipelineColorBlendAttachmentState attBlendParams0 =
1065 {
1066 VK_FALSE, // blendEnable
1067 VK_BLEND_FACTOR_ONE, // srcColorBlendFactor
1068 VK_BLEND_FACTOR_ZERO, // dstColorBlendFactor
1069 VK_BLEND_OP_ADD, // colorBlendOp
1070 VK_BLEND_FACTOR_ONE, // srcAlphaBlendFactor
1071 VK_BLEND_FACTOR_ZERO, // dstAlphaBlendFactor
1072 VK_BLEND_OP_ADD, // alphaBlendOp
1073 (VK_COLOR_COMPONENT_R_BIT|
1074 VK_COLOR_COMPONENT_G_BIT|
1075 VK_COLOR_COMPONENT_B_BIT|
1076 VK_COLOR_COMPONENT_A_BIT), // colorWriteMask
1077 };
1078 const VkPipelineColorBlendStateCreateInfo blendParams =
1079 {
1080 VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
1081 DE_NULL,
1082 (VkPipelineColorBlendStateCreateFlags)0,
1083 VK_FALSE, // logicOpEnable
1084 VK_LOGIC_OP_COPY,
1085 1u,
1086 &attBlendParams0,
1087 { 0.0f, 0.0f, 0.0f, 0.0f }, // blendConstants[4]
1088 };
1089 const VkGraphicsPipelineCreateInfo pipelineParams =
1090 {
1091 VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
1092 DE_NULL,
1093 (VkPipelineCreateFlags)0,
1094 (deUint32)DE_LENGTH_OF_ARRAY(shaderStageParams),
1095 shaderStageParams,
1096 &vertexInputStateParams,
1097 &inputAssemblyParams,
1098 (const VkPipelineTessellationStateCreateInfo*)DE_NULL,
1099 &viewportParams,
1100 &rasterParams,
1101 &multisampleParams,
1102 &depthStencilParams,
1103 &blendParams,
1104 (const VkPipelineDynamicStateCreateInfo*)DE_NULL,
1105 pipelineLayout,
1106 renderPass,
1107 0u, // subpass
1108 DE_NULL, // basePipelineHandle
1109 0u, // basePipelineIndex
1110 };
1111
1112 return vk::createGraphicsPipeline(vkd, device, (VkPipelineCache)0, &pipelineParams);
1113 }
1114
createAttachmentView(const DeviceInterface & vkd,const VkDevice device,const VkImage image,const VkFormat format)1115 Move<VkImageView> TriangleRenderer::createAttachmentView (const DeviceInterface& vkd,
1116 const VkDevice device,
1117 const VkImage image,
1118 const VkFormat format)
1119 {
1120 const VkImageViewCreateInfo viewParams =
1121 {
1122 VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
1123 DE_NULL,
1124 (VkImageViewCreateFlags)0,
1125 image,
1126 VK_IMAGE_VIEW_TYPE_2D,
1127 format,
1128 vk::makeComponentMappingRGBA(),
1129 {
1130 VK_IMAGE_ASPECT_COLOR_BIT,
1131 0u, // baseMipLevel
1132 1u, // levelCount
1133 0u, // baseArrayLayer
1134 1u, // layerCount
1135 },
1136 };
1137
1138 return vk::createImageView(vkd, device, &viewParams);
1139 }
1140
createFramebuffer(const DeviceInterface & vkd,const VkDevice device,const VkRenderPass renderPass,const VkImageView colorAttachment,const UVec2 & renderSize)1141 Move<VkFramebuffer> TriangleRenderer::createFramebuffer (const DeviceInterface& vkd,
1142 const VkDevice device,
1143 const VkRenderPass renderPass,
1144 const VkImageView colorAttachment,
1145 const UVec2& renderSize)
1146 {
1147 const VkFramebufferCreateInfo framebufferParams =
1148 {
1149 VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
1150 DE_NULL,
1151 (VkFramebufferCreateFlags)0,
1152 renderPass,
1153 1u,
1154 &colorAttachment,
1155 renderSize.x(),
1156 renderSize.y(),
1157 1u, // layers
1158 };
1159
1160 return vk::createFramebuffer(vkd, device, &framebufferParams);
1161 }
1162
createBuffer(const DeviceInterface & vkd,VkDevice device,VkDeviceSize size,VkBufferUsageFlags usage)1163 Move<VkBuffer> TriangleRenderer::createBuffer (const DeviceInterface& vkd,
1164 VkDevice device,
1165 VkDeviceSize size,
1166 VkBufferUsageFlags usage)
1167 {
1168 const VkBufferCreateInfo bufferParams =
1169 {
1170 VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
1171 DE_NULL,
1172 (VkBufferCreateFlags)0,
1173 size,
1174 usage,
1175 VK_SHARING_MODE_EXCLUSIVE,
1176 0,
1177 DE_NULL
1178 };
1179
1180 return vk::createBuffer(vkd, device, &bufferParams);
1181 }
1182
TriangleRenderer(const DeviceInterface & vkd,const VkDevice device,Allocator & allocator,const BinaryCollection & binaryRegistry,const vector<VkImage> swapchainImages,const VkFormat framebufferFormat,const UVec2 & renderSize)1183 TriangleRenderer::TriangleRenderer (const DeviceInterface& vkd,
1184 const VkDevice device,
1185 Allocator& allocator,
1186 const BinaryCollection& binaryRegistry,
1187 const vector<VkImage> swapchainImages,
1188 const VkFormat framebufferFormat,
1189 const UVec2& renderSize)
1190 : m_vkd (vkd)
1191 , m_swapchainImages (swapchainImages)
1192 , m_renderSize (renderSize)
1193 , m_renderPass (createRenderPass(vkd, device, framebufferFormat))
1194 , m_pipelineLayout (createPipelineLayout(vkd, device))
1195 , m_pipeline (createPipeline(vkd, device, *m_renderPass, *m_pipelineLayout, binaryRegistry, renderSize))
1196 , m_vertexBuffer (createBuffer(vkd, device, (VkDeviceSize)(sizeof(float)*4*3), VK_BUFFER_USAGE_VERTEX_BUFFER_BIT))
1197 , m_vertexBufferMemory (allocator.allocate(getBufferMemoryRequirements(vkd, device, *m_vertexBuffer),
1198 MemoryRequirement::HostVisible))
1199 {
1200 m_attachmentViews.resize(swapchainImages.size());
1201 m_framebuffers.resize(swapchainImages.size());
1202
1203 for (size_t imageNdx = 0; imageNdx < swapchainImages.size(); ++imageNdx)
1204 {
1205 m_attachmentViews[imageNdx] = ImageViewSp(new Unique<VkImageView>(createAttachmentView(vkd, device, swapchainImages[imageNdx], framebufferFormat)));
1206 m_framebuffers[imageNdx] = FramebufferSp(new Unique<VkFramebuffer>(createFramebuffer(vkd, device, *m_renderPass, **m_attachmentViews[imageNdx], renderSize)));
1207 }
1208
1209 VK_CHECK(vkd.bindBufferMemory(device, *m_vertexBuffer, m_vertexBufferMemory->getMemory(), m_vertexBufferMemory->getOffset()));
1210
1211 {
1212 const VkMappedMemoryRange memRange =
1213 {
1214 VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,
1215 DE_NULL,
1216 m_vertexBufferMemory->getMemory(),
1217 m_vertexBufferMemory->getOffset(),
1218 VK_WHOLE_SIZE
1219 };
1220 const tcu::Vec4 vertices[] =
1221 {
1222 tcu::Vec4(-0.5f, -0.5f, 0.0f, 1.0f),
1223 tcu::Vec4(+0.5f, -0.5f, 0.0f, 1.0f),
1224 tcu::Vec4( 0.0f, +0.5f, 0.0f, 1.0f)
1225 };
1226 DE_STATIC_ASSERT(sizeof(vertices) == sizeof(float)*4*3);
1227
1228 deMemcpy(m_vertexBufferMemory->getHostPtr(), &vertices[0], sizeof(vertices));
1229 VK_CHECK(vkd.flushMappedMemoryRanges(device, 1u, &memRange));
1230 }
1231 }
1232
~TriangleRenderer(void)1233 TriangleRenderer::~TriangleRenderer (void)
1234 {
1235 }
1236
recordFrame(VkCommandBuffer cmdBuffer,deUint32 imageNdx,deUint32 frameNdx) const1237 void TriangleRenderer::recordFrame (VkCommandBuffer cmdBuffer,
1238 deUint32 imageNdx,
1239 deUint32 frameNdx) const
1240 {
1241 const VkFramebuffer curFramebuffer = **m_framebuffers[imageNdx];
1242
1243 {
1244 const VkCommandBufferBeginInfo cmdBufBeginParams =
1245 {
1246 VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
1247 DE_NULL,
1248 (VkCommandBufferUsageFlags)0,
1249 (const VkCommandBufferInheritanceInfo*)DE_NULL,
1250 };
1251 VK_CHECK(m_vkd.beginCommandBuffer(cmdBuffer, &cmdBufBeginParams));
1252 }
1253
1254 {
1255 const VkClearValue clearValue = makeClearValueColorF32(0.125f, 0.25f, 0.75f, 1.0f);
1256 const VkRenderPassBeginInfo passBeginParams =
1257 {
1258 VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
1259 DE_NULL,
1260 *m_renderPass,
1261 curFramebuffer,
1262 {
1263 { 0, 0 },
1264 { (deUint32)m_renderSize.x(), (deUint32)m_renderSize.y() }
1265 }, // renderArea
1266 1u, // clearValueCount
1267 &clearValue, // pClearValues
1268 };
1269 m_vkd.cmdBeginRenderPass(cmdBuffer, &passBeginParams, VK_SUBPASS_CONTENTS_INLINE);
1270 }
1271
1272 m_vkd.cmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
1273
1274 {
1275 const VkDeviceSize bindingOffset = 0;
1276 m_vkd.cmdBindVertexBuffers(cmdBuffer, 0u, 1u, &m_vertexBuffer.get(), &bindingOffset);
1277 }
1278
1279 m_vkd.cmdPushConstants(cmdBuffer, *m_pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 0u, (deUint32)sizeof(deUint32), &frameNdx);
1280 m_vkd.cmdDraw(cmdBuffer, 3u, 1u, 0u, 0u);
1281 m_vkd.cmdEndRenderPass(cmdBuffer);
1282
1283 VK_CHECK(m_vkd.endCommandBuffer(cmdBuffer));
1284 }
1285
getPrograms(SourceCollections & dst)1286 void TriangleRenderer::getPrograms (SourceCollections& dst)
1287 {
1288 dst.glslSources.add("tri-vert") << glu::VertexSource(
1289 "#version 310 es\n"
1290 "layout(location = 0) in highp vec4 a_position;\n"
1291 "layout(push_constant) uniform FrameData\n"
1292 "{\n"
1293 " highp uint frameNdx;\n"
1294 "} frameData;\n"
1295 "void main (void)\n"
1296 "{\n"
1297 " highp float angle = float(frameData.frameNdx) / 100.0;\n"
1298 " highp float c = cos(angle);\n"
1299 " highp float s = sin(angle);\n"
1300 " highp mat4 t = mat4( c, -s, 0, 0,\n"
1301 " s, c, 0, 0,\n"
1302 " 0, 0, 1, 0,\n"
1303 " 0, 0, 0, 1);\n"
1304 " gl_Position = t * a_position;\n"
1305 "}\n");
1306 dst.glslSources.add("tri-frag") << glu::FragmentSource(
1307 "#version 310 es\n"
1308 "layout(location = 0) out lowp vec4 o_color;\n"
1309 "void main (void) { o_color = vec4(1.0, 0.0, 1.0, 1.0); }\n");
1310 }
1311
1312 typedef de::SharedPtr<Unique<VkCommandBuffer> > CommandBufferSp;
1313 typedef de::SharedPtr<Unique<VkFence> > FenceSp;
1314 typedef de::SharedPtr<Unique<VkSemaphore> > SemaphoreSp;
1315
createFence(const DeviceInterface & vkd,const VkDevice device)1316 Move<VkFence> createFence (const DeviceInterface& vkd,
1317 const VkDevice device)
1318 {
1319 const VkFenceCreateInfo fenceParams =
1320 {
1321 VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
1322 DE_NULL,
1323 (VkFenceCreateFlags)0,
1324 };
1325 return vk::createFence(vkd, device, &fenceParams);
1326 }
1327
createFences(const DeviceInterface & vkd,const VkDevice device,size_t numFences)1328 vector<FenceSp> createFences (const DeviceInterface& vkd,
1329 const VkDevice device,
1330 size_t numFences)
1331 {
1332 vector<FenceSp> fences(numFences);
1333
1334 for (size_t ndx = 0; ndx < numFences; ++ndx)
1335 fences[ndx] = FenceSp(new Unique<VkFence>(createFence(vkd, device)));
1336
1337 return fences;
1338 }
1339
createSemaphore(const DeviceInterface & vkd,const VkDevice device)1340 Move<VkSemaphore> createSemaphore (const DeviceInterface& vkd,
1341 const VkDevice device)
1342 {
1343 const VkSemaphoreCreateInfo semaphoreParams =
1344 {
1345 VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
1346 DE_NULL,
1347 (VkSemaphoreCreateFlags)0,
1348 };
1349 return vk::createSemaphore(vkd, device, &semaphoreParams);
1350 }
1351
createSemaphores(const DeviceInterface & vkd,const VkDevice device,size_t numSemaphores)1352 vector<SemaphoreSp> createSemaphores (const DeviceInterface& vkd,
1353 const VkDevice device,
1354 size_t numSemaphores)
1355 {
1356 vector<SemaphoreSp> semaphores(numSemaphores);
1357
1358 for (size_t ndx = 0; ndx < numSemaphores; ++ndx)
1359 semaphores[ndx] = SemaphoreSp(new Unique<VkSemaphore>(createSemaphore(vkd, device)));
1360
1361 return semaphores;
1362 }
1363
createCommandPool(const DeviceInterface & vkd,const VkDevice device,VkCommandPoolCreateFlags flags,deUint32 queueFamilyIndex)1364 Move<VkCommandPool> createCommandPool (const DeviceInterface& vkd,
1365 const VkDevice device,
1366 VkCommandPoolCreateFlags flags,
1367 deUint32 queueFamilyIndex)
1368 {
1369 const VkCommandPoolCreateInfo commandPoolParams =
1370 {
1371 VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
1372 DE_NULL,
1373 flags,
1374 queueFamilyIndex
1375 };
1376
1377 return createCommandPool(vkd, device, &commandPoolParams);
1378 }
1379
allocateCommandBuffers(const DeviceInterface & vkd,const VkDevice device,const VkCommandPool commandPool,const VkCommandBufferLevel level,const size_t numCommandBuffers)1380 vector<CommandBufferSp> allocateCommandBuffers (const DeviceInterface& vkd,
1381 const VkDevice device,
1382 const VkCommandPool commandPool,
1383 const VkCommandBufferLevel level,
1384 const size_t numCommandBuffers)
1385 {
1386 const VkCommandBufferAllocateInfo allocInfo =
1387 {
1388 VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
1389 DE_NULL,
1390 commandPool,
1391 level,
1392 1u,
1393 };
1394
1395 vector<CommandBufferSp> buffers (numCommandBuffers);
1396
1397 for (size_t ndx = 0; ndx < numCommandBuffers; ++ndx)
1398 buffers[ndx] = CommandBufferSp(new Unique<VkCommandBuffer>(allocateCommandBuffer(vkd, device, &allocInfo)));
1399
1400 return buffers;
1401 }
1402
basicRenderTest(Context & context,Type wsiType)1403 tcu::TestStatus basicRenderTest (Context& context, Type wsiType)
1404 {
1405 const tcu::UVec2 desiredSize (256, 256);
1406 const InstanceHelper instHelper (context, wsiType);
1407 const NativeObjects native (context, instHelper.supportedExtensions, wsiType, tcu::just(desiredSize));
1408 const Unique<VkSurfaceKHR> surface (createSurface(instHelper.vki, *instHelper.instance, wsiType, *native.display, *native.window));
1409 const DeviceHelper devHelper (context, instHelper.vki, *instHelper.instance, *surface);
1410 const DeviceInterface& vkd = devHelper.vkd;
1411 const VkDevice device = *devHelper.device;
1412 SimpleAllocator allocator (vkd, device, getPhysicalDeviceMemoryProperties(instHelper.vki, devHelper.physicalDevice));
1413 const VkSwapchainCreateInfoKHR swapchainInfo = getBasicSwapchainParameters(wsiType, instHelper.vki, devHelper.physicalDevice, *surface, desiredSize, 2);
1414 const Unique<VkSwapchainKHR> swapchain (createSwapchainKHR(vkd, device, &swapchainInfo));
1415 const vector<VkImage> swapchainImages = getSwapchainImages(vkd, device, *swapchain);
1416
1417 const TriangleRenderer renderer (vkd,
1418 device,
1419 allocator,
1420 context.getBinaryCollection(),
1421 swapchainImages,
1422 swapchainInfo.imageFormat,
1423 tcu::UVec2(swapchainInfo.imageExtent.width, swapchainInfo.imageExtent.height));
1424
1425 const Unique<VkCommandPool> commandPool (createCommandPool(vkd, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, devHelper.queueFamilyIndex));
1426
1427 const size_t maxQueuedFrames = swapchainImages.size()*2;
1428
1429 // We need to keep hold of fences from vkAcquireNextImageKHR to actually
1430 // limit number of frames we allow to be queued.
1431 const vector<FenceSp> imageReadyFences (createFences(vkd, device, maxQueuedFrames));
1432
1433 // We need maxQueuedFrames+1 for imageReadySemaphores pool as we need to pass
1434 // the semaphore in same time as the fence we use to meter rendering.
1435 const vector<SemaphoreSp> imageReadySemaphores (createSemaphores(vkd, device, maxQueuedFrames+1));
1436
1437 // For rest we simply need maxQueuedFrames as we will wait for image
1438 // from frameNdx-maxQueuedFrames to become available to us, guaranteeing that
1439 // previous uses must have completed.
1440 const vector<SemaphoreSp> renderingCompleteSemaphores (createSemaphores(vkd, device, maxQueuedFrames));
1441 const vector<CommandBufferSp> commandBuffers (allocateCommandBuffers(vkd, device, *commandPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY, maxQueuedFrames));
1442
1443 try
1444 {
1445 const deUint32 numFramesToRender = 60*10;
1446
1447 for (deUint32 frameNdx = 0; frameNdx < numFramesToRender; ++frameNdx)
1448 {
1449 const VkFence imageReadyFence = **imageReadyFences[frameNdx%imageReadyFences.size()];
1450 const VkSemaphore imageReadySemaphore = **imageReadySemaphores[frameNdx%imageReadySemaphores.size()];
1451 deUint32 imageNdx = ~0u;
1452
1453 if (frameNdx >= maxQueuedFrames)
1454 VK_CHECK(vkd.waitForFences(device, 1u, &imageReadyFence, VK_TRUE, std::numeric_limits<deUint64>::max()));
1455
1456 VK_CHECK(vkd.resetFences(device, 1, &imageReadyFence));
1457
1458 {
1459 const VkResult acquireResult = vkd.acquireNextImageKHR(device,
1460 *swapchain,
1461 std::numeric_limits<deUint64>::max(),
1462 imageReadySemaphore,
1463 imageReadyFence,
1464 &imageNdx);
1465
1466 if (acquireResult == VK_SUBOPTIMAL_KHR)
1467 context.getTestContext().getLog() << TestLog::Message << "Got " << acquireResult << " at frame " << frameNdx << TestLog::EndMessage;
1468 else
1469 VK_CHECK(acquireResult);
1470 }
1471
1472 TCU_CHECK((size_t)imageNdx < swapchainImages.size());
1473
1474 {
1475 const VkSemaphore renderingCompleteSemaphore = **renderingCompleteSemaphores[frameNdx%renderingCompleteSemaphores.size()];
1476 const VkCommandBuffer commandBuffer = **commandBuffers[frameNdx%commandBuffers.size()];
1477 const VkPipelineStageFlags waitDstStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
1478 const VkSubmitInfo submitInfo =
1479 {
1480 VK_STRUCTURE_TYPE_SUBMIT_INFO,
1481 DE_NULL,
1482 1u,
1483 &imageReadySemaphore,
1484 &waitDstStage,
1485 1u,
1486 &commandBuffer,
1487 1u,
1488 &renderingCompleteSemaphore
1489 };
1490 const VkPresentInfoKHR presentInfo =
1491 {
1492 VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
1493 DE_NULL,
1494 1u,
1495 &renderingCompleteSemaphore,
1496 1u,
1497 &*swapchain,
1498 &imageNdx,
1499 (VkResult*)DE_NULL
1500 };
1501
1502 renderer.recordFrame(commandBuffer, imageNdx, frameNdx);
1503 VK_CHECK(vkd.queueSubmit(devHelper.queue, 1u, &submitInfo, (VkFence)0));
1504 VK_CHECK(vkd.queuePresentKHR(devHelper.queue, &presentInfo));
1505 }
1506 }
1507
1508 VK_CHECK(vkd.deviceWaitIdle(device));
1509 }
1510 catch (...)
1511 {
1512 // Make sure device is idle before destroying resources
1513 vkd.deviceWaitIdle(device);
1514 throw;
1515 }
1516
1517 return tcu::TestStatus::pass("Rendering tests suceeded");
1518 }
1519
getSwapchainSizeSequence(const VkSurfaceCapabilitiesKHR & capabilities,const tcu::UVec2 & defaultSize)1520 vector<tcu::UVec2> getSwapchainSizeSequence (const VkSurfaceCapabilitiesKHR& capabilities, const tcu::UVec2& defaultSize)
1521 {
1522 vector<tcu::UVec2> sizes(3);
1523 sizes[0] = defaultSize / 2u;
1524 sizes[1] = defaultSize;
1525 sizes[2] = defaultSize * 2u;
1526
1527 for (deUint32 i = 0; i < sizes.size(); ++i)
1528 {
1529 sizes[i].x() = de::clamp(sizes[i].x(), capabilities.minImageExtent.width, capabilities.maxImageExtent.width);
1530 sizes[i].y() = de::clamp(sizes[i].y(), capabilities.minImageExtent.height, capabilities.maxImageExtent.height);
1531 }
1532
1533 return sizes;
1534 }
1535
resizeSwapchainTest(Context & context,Type wsiType)1536 tcu::TestStatus resizeSwapchainTest (Context& context, Type wsiType)
1537 {
1538 const tcu::UVec2 desiredSize (256, 256);
1539 const InstanceHelper instHelper (context, wsiType);
1540 const NativeObjects native (context, instHelper.supportedExtensions, wsiType, tcu::just(desiredSize));
1541 const Unique<VkSurfaceKHR> surface (createSurface(instHelper.vki, *instHelper.instance, wsiType, *native.display, *native.window));
1542 const DeviceHelper devHelper (context, instHelper.vki, *instHelper.instance, *surface);
1543 const PlatformProperties& platformProperties = getPlatformProperties(wsiType);
1544 const VkSurfaceCapabilitiesKHR capabilities = getPhysicalDeviceSurfaceCapabilities(instHelper.vki, devHelper.physicalDevice, *surface);
1545 const DeviceInterface& vkd = devHelper.vkd;
1546 const VkDevice device = *devHelper.device;
1547 SimpleAllocator allocator (vkd, device, getPhysicalDeviceMemoryProperties(instHelper.vki, devHelper.physicalDevice));
1548 vector<tcu::UVec2> sizes = getSwapchainSizeSequence(capabilities, desiredSize);
1549 Move<VkSwapchainKHR> prevSwapchain;
1550
1551 DE_ASSERT(platformProperties.swapchainExtent != PlatformProperties::SWAPCHAIN_EXTENT_MUST_MATCH_WINDOW_SIZE);
1552
1553 for (deUint32 sizeNdx = 0; sizeNdx < sizes.size(); ++sizeNdx)
1554 {
1555 // \todo [2016-05-30 jesse] This test currently waits for idle and
1556 // recreates way more than necessary when recreating the swapchain. Make
1557 // it match expected real app behavior better by smoothly switching from
1558 // old to new swapchain. Once that is done, it will also be possible to
1559 // test creating a new swapchain while images from the previous one are
1560 // still acquired.
1561
1562 VkSwapchainCreateInfoKHR swapchainInfo = getBasicSwapchainParameters(wsiType, instHelper.vki, devHelper.physicalDevice, *surface, sizes[sizeNdx], 2);
1563 swapchainInfo.oldSwapchain = *prevSwapchain;
1564
1565 Move<VkSwapchainKHR> swapchain (createSwapchainKHR(vkd, device, &swapchainInfo));
1566 const vector<VkImage> swapchainImages = getSwapchainImages(vkd, device, *swapchain);
1567 const TriangleRenderer renderer (vkd,
1568 device,
1569 allocator,
1570 context.getBinaryCollection(),
1571 swapchainImages,
1572 swapchainInfo.imageFormat,
1573 tcu::UVec2(swapchainInfo.imageExtent.width, swapchainInfo.imageExtent.height));
1574 const Unique<VkCommandPool> commandPool (createCommandPool(vkd, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, devHelper.queueFamilyIndex));
1575 const size_t maxQueuedFrames = swapchainImages.size()*2;
1576
1577 // We need to keep hold of fences from vkAcquireNextImageKHR to actually
1578 // limit number of frames we allow to be queued.
1579 const vector<FenceSp> imageReadyFences (createFences(vkd, device, maxQueuedFrames));
1580
1581 // We need maxQueuedFrames+1 for imageReadySemaphores pool as we need to pass
1582 // the semaphore in same time as the fence we use to meter rendering.
1583 const vector<SemaphoreSp> imageReadySemaphores (createSemaphores(vkd, device, maxQueuedFrames+1));
1584
1585 // For rest we simply need maxQueuedFrames as we will wait for image
1586 // from frameNdx-maxQueuedFrames to become available to us, guaranteeing that
1587 // previous uses must have completed.
1588 const vector<SemaphoreSp> renderingCompleteSemaphores (createSemaphores(vkd, device, maxQueuedFrames));
1589 const vector<CommandBufferSp> commandBuffers (allocateCommandBuffers(vkd, device, *commandPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY, maxQueuedFrames));
1590
1591 try
1592 {
1593 const deUint32 numFramesToRender = 60;
1594
1595 for (deUint32 frameNdx = 0; frameNdx < numFramesToRender; ++frameNdx)
1596 {
1597 const VkFence imageReadyFence = **imageReadyFences[frameNdx%imageReadyFences.size()];
1598 const VkSemaphore imageReadySemaphore = **imageReadySemaphores[frameNdx%imageReadySemaphores.size()];
1599 deUint32 imageNdx = ~0u;
1600
1601 if (frameNdx >= maxQueuedFrames)
1602 VK_CHECK(vkd.waitForFences(device, 1u, &imageReadyFence, VK_TRUE, std::numeric_limits<deUint64>::max()));
1603
1604 VK_CHECK(vkd.resetFences(device, 1, &imageReadyFence));
1605
1606 {
1607 const VkResult acquireResult = vkd.acquireNextImageKHR(device,
1608 *swapchain,
1609 std::numeric_limits<deUint64>::max(),
1610 imageReadySemaphore,
1611 imageReadyFence,
1612 &imageNdx);
1613
1614 if (acquireResult == VK_SUBOPTIMAL_KHR)
1615 context.getTestContext().getLog() << TestLog::Message << "Got " << acquireResult << " at frame " << frameNdx << TestLog::EndMessage;
1616 else
1617 VK_CHECK(acquireResult);
1618 }
1619
1620 TCU_CHECK((size_t)imageNdx < swapchainImages.size());
1621
1622 {
1623 const VkSemaphore renderingCompleteSemaphore = **renderingCompleteSemaphores[frameNdx%renderingCompleteSemaphores.size()];
1624 const VkCommandBuffer commandBuffer = **commandBuffers[frameNdx%commandBuffers.size()];
1625 const VkPipelineStageFlags waitDstStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
1626 const VkSubmitInfo submitInfo =
1627 {
1628 VK_STRUCTURE_TYPE_SUBMIT_INFO,
1629 DE_NULL,
1630 1u,
1631 &imageReadySemaphore,
1632 &waitDstStage,
1633 1u,
1634 &commandBuffer,
1635 1u,
1636 &renderingCompleteSemaphore
1637 };
1638 const VkPresentInfoKHR presentInfo =
1639 {
1640 VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
1641 DE_NULL,
1642 1u,
1643 &renderingCompleteSemaphore,
1644 1u,
1645 &*swapchain,
1646 &imageNdx,
1647 (VkResult*)DE_NULL
1648 };
1649
1650 renderer.recordFrame(commandBuffer, imageNdx, frameNdx);
1651 VK_CHECK(vkd.queueSubmit(devHelper.queue, 1u, &submitInfo, (VkFence)0));
1652 VK_CHECK(vkd.queuePresentKHR(devHelper.queue, &presentInfo));
1653 }
1654 }
1655
1656 VK_CHECK(vkd.deviceWaitIdle(device));
1657
1658 prevSwapchain = swapchain;
1659 }
1660 catch (...)
1661 {
1662 // Make sure device is idle before destroying resources
1663 vkd.deviceWaitIdle(device);
1664 throw;
1665 }
1666 }
1667
1668 return tcu::TestStatus::pass("Resizing tests suceeded");
1669 }
1670
getBasicRenderPrograms(SourceCollections & dst,Type)1671 void getBasicRenderPrograms (SourceCollections& dst, Type)
1672 {
1673 TriangleRenderer::getPrograms(dst);
1674 }
1675
populateRenderGroup(tcu::TestCaseGroup * testGroup,Type wsiType)1676 void populateRenderGroup (tcu::TestCaseGroup* testGroup, Type wsiType)
1677 {
1678 addFunctionCaseWithPrograms(testGroup, "basic", "Basic Rendering Test", getBasicRenderPrograms, basicRenderTest, wsiType);
1679 }
1680
populateModifyGroup(tcu::TestCaseGroup * testGroup,Type wsiType)1681 void populateModifyGroup (tcu::TestCaseGroup* testGroup, Type wsiType)
1682 {
1683 const PlatformProperties& platformProperties = getPlatformProperties(wsiType);
1684
1685 if (platformProperties.swapchainExtent != PlatformProperties::SWAPCHAIN_EXTENT_MUST_MATCH_WINDOW_SIZE)
1686 {
1687 addFunctionCaseWithPrograms(testGroup, "resize", "Resize Swapchain Test", getBasicRenderPrograms, resizeSwapchainTest, wsiType);
1688 }
1689
1690 // \todo [2016-05-30 jesse] Add tests for modifying preTransform, compositeAlpha, presentMode
1691 }
1692
1693 } // anonymous
1694
createSwapchainTests(tcu::TestCaseGroup * testGroup,vk::wsi::Type wsiType)1695 void createSwapchainTests (tcu::TestCaseGroup* testGroup, vk::wsi::Type wsiType)
1696 {
1697 addTestGroup(testGroup, "create", "Create VkSwapchain with various parameters", populateSwapchainGroup, GroupParameters(wsiType, createSwapchainTest));
1698 addTestGroup(testGroup, "simulate_oom", "Simulate OOM using callbacks during swapchain construction", populateSwapchainOOMGroup, wsiType);
1699 addTestGroup(testGroup, "render", "Rendering Tests", populateRenderGroup, wsiType);
1700 addTestGroup(testGroup, "modify", "Modify VkSwapchain", populateModifyGroup, wsiType);
1701 }
1702
1703 } // wsi
1704 } // vkt
1705