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