• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*-------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2017 The Khronos Group Inc.
6  * Copyright (c) 2017 Samsung Electronics Co., Ltd.
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *      http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  *//*!
21  * \file
22  * \brief Protected memory interaction with VkSwapchain Tests
23  *//*--------------------------------------------------------------------*/
24 
25 #include "vktProtectedMemWsiSwapchainTests.hpp"
26 
27 #include "vktTestCaseUtil.hpp"
28 #include "vktTestGroupUtil.hpp"
29 
30 #include "vkDefs.hpp"
31 #include "vkPlatform.hpp"
32 #include "vkStrUtil.hpp"
33 #include "vkRef.hpp"
34 #include "vkRefUtil.hpp"
35 #include "vkQueryUtil.hpp"
36 #include "vkMemUtil.hpp"
37 #include "vkDeviceUtil.hpp"
38 #include "vkPrograms.hpp"
39 #include "vkTypeUtil.hpp"
40 #include "vkObjUtil.hpp"
41 #include "vkWsiPlatform.hpp"
42 #include "vkWsiUtil.hpp"
43 #include "vkAllocationCallbackUtil.hpp"
44 #include "vkCmdUtil.hpp"
45 
46 #include "tcuTestLog.hpp"
47 #include "tcuFormatUtil.hpp"
48 #include "tcuPlatform.hpp"
49 #include "tcuResultCollector.hpp"
50 
51 #include "deUniquePtr.hpp"
52 #include "deStringUtil.hpp"
53 #include "deArrayUtil.hpp"
54 #include "deSharedPtr.hpp"
55 
56 #include <limits>
57 #include <cstring>
58 
59 #include "vktProtectedMemContext.hpp"
60 #include "vktProtectedMemUtils.hpp"
61 
62 namespace vkt
63 {
64 namespace ProtectedMem
65 {
66 
67 namespace
68 {
69 
70 typedef std::vector<vk::VkExtensionProperties> Extensions;
71 
checkAllSupported(const Extensions & supportedExtensions,const std::vector<std::string> & requiredExtensions)72 void checkAllSupported (const Extensions& supportedExtensions, const std::vector<std::string>& requiredExtensions)
73 {
74 	for (std::vector<std::string>::const_iterator requiredExtName = requiredExtensions.begin();
75 		 requiredExtName != requiredExtensions.end();
76 		 ++requiredExtName)
77 	{
78 		if (!isExtensionStructSupported(supportedExtensions, vk::RequiredExtension(*requiredExtName)))
79 			TCU_THROW(NotSupportedError, (*requiredExtName + " is not supported").c_str());
80 	}
81 }
82 
getRequiredWsiExtensions(const Extensions & supportedExtensions,vk::wsi::Type wsiType)83 std::vector<std::string> getRequiredWsiExtensions (const Extensions&	supportedExtensions,
84 												   vk::wsi::Type		wsiType)
85 {
86 	std::vector<std::string>	extensions;
87 
88 	extensions.push_back("VK_KHR_surface");
89 	extensions.push_back(getExtensionName(wsiType));
90 	if (isDisplaySurface(wsiType))
91 		extensions.push_back("VK_KHR_display");
92 
93 	// VK_EXT_swapchain_colorspace adds new surface formats. Driver can enumerate
94 	// the formats regardless of whether VK_EXT_swapchain_colorspace was enabled,
95 	// but using them without enabling the extension is not allowed. Thus we have
96 	// two options:
97 	//
98 	// 1) Filter out non-core formats to stay within valid usage.
99 	//
100 	// 2) Enable VK_EXT_swapchain colorspace if advertised by the driver.
101 	//
102 	// We opt for (2) as it provides basic coverage for the extension as a bonus.
103 	if (isExtensionStructSupported(supportedExtensions, vk::RequiredExtension("VK_EXT_swapchain_colorspace")))
104 		extensions.push_back("VK_EXT_swapchain_colorspace");
105 
106 	// VK_KHR_surface_protected_capabilities adds a way to check if swapchain can be
107 	// created for protected VkSurface, so if this extension is enabled then we can
108 	// check for that capability.
109 	// To check this capability, vkGetPhysicalDeviceSurfaceCapabilities2KHR needs
110 	// to be called so add VK_KHR_get_surface_capabilities2 for this.
111 	if (isExtensionStructSupported(supportedExtensions, vk::RequiredExtension("VK_KHR_surface_protected_capabilities")))
112 	{
113 		extensions.push_back("VK_KHR_get_surface_capabilities2");
114 		extensions.push_back("VK_KHR_surface_protected_capabilities");
115 	}
116 
117 	checkAllSupported(supportedExtensions, extensions);
118 
119 	return extensions;
120 }
121 
createDisplay(const vk::Platform & platform,const Extensions & supportedExtensions,vk::wsi::Type wsiType)122 de::MovePtr<vk::wsi::Display> createDisplay (const vk::Platform&	platform,
123 											 const Extensions&		supportedExtensions,
124 											 vk::wsi::Type			wsiType)
125 {
126 	try
127 	{
128 		return de::MovePtr<vk::wsi::Display>(platform.createWsiDisplay(wsiType));
129 	}
130 	catch (const tcu::NotSupportedError& e)
131 	{
132 		if (isExtensionStructSupported(supportedExtensions, vk::RequiredExtension(getExtensionName(wsiType))) &&
133 		    platform.hasDisplay(wsiType))
134 		{
135 			// If VK_KHR_{platform}_surface was supported, vk::Platform implementation
136 			// must support creating native display & window for that WSI type.
137 			throw tcu::TestError(e.getMessage());
138 		}
139 		else
140 			throw;
141 	}
142 }
143 
createWindow(const vk::wsi::Display & display,const tcu::Maybe<tcu::UVec2> & initialSize)144 de::MovePtr<vk::wsi::Window> createWindow (const vk::wsi::Display& display, const tcu::Maybe<tcu::UVec2>& initialSize)
145 {
146 	try
147 	{
148 		return de::MovePtr<vk::wsi::Window>(display.createWindow(initialSize));
149 	}
150 	catch (const tcu::NotSupportedError& e)
151 	{
152 		// See createDisplay - assuming that wsi::Display was supported platform port
153 		// should also support creating a window.
154 		throw tcu::TestError(e.getMessage());
155 	}
156 }
157 
158 struct NativeObjects
159 {
160 	const de::UniquePtr<vk::wsi::Display>	display;
161 	const de::UniquePtr<vk::wsi::Window>	window;
162 
NativeObjectsvkt::ProtectedMem::__anon5d8586710111::NativeObjects163 	NativeObjects (Context&							context,
164 				   const Extensions&				supportedExtensions,
165 				   vk::wsi::Type					wsiType,
166 				   const tcu::Maybe<tcu::UVec2>&	initialWindowSize = tcu::Nothing)
167 		: display				(createDisplay(context.getTestContext().getPlatform().getVulkanPlatform(), supportedExtensions, wsiType))
168 		, window				(createWindow(*display, initialWindowSize))
169 	{}
170 };
171 
172 enum TestDimension
173 {
174 	TEST_DIMENSION_MIN_IMAGE_COUNT = 0,	//!< Test all supported image counts
175 	TEST_DIMENSION_IMAGE_FORMAT,		//!< Test all supported formats
176 	TEST_DIMENSION_IMAGE_EXTENT,		//!< Test various (supported) extents
177 	TEST_DIMENSION_IMAGE_ARRAY_LAYERS,
178 	TEST_DIMENSION_IMAGE_USAGE,
179 	TEST_DIMENSION_IMAGE_SHARING_MODE,
180 	TEST_DIMENSION_PRE_TRANSFORM,
181 	TEST_DIMENSION_COMPOSITE_ALPHA,
182 	TEST_DIMENSION_PRESENT_MODE,
183 	TEST_DIMENSION_CLIPPED,
184 
185 	TEST_DIMENSION_LAST
186 };
187 
getTestDimensionName(TestDimension dimension)188 const char* getTestDimensionName (TestDimension dimension)
189 {
190 	static const char* const s_names[] =
191 	{
192 		"min_image_count",
193 		"image_format",
194 		"image_extent",
195 		"image_array_layers",
196 		"image_usage",
197 		"image_sharing_mode",
198 		"pre_transform",
199 		"composite_alpha",
200 		"present_mode",
201 		"clipped"
202 	};
203 	return de::getSizedArrayElement<TEST_DIMENSION_LAST>(s_names, dimension);
204 }
205 
206 struct TestParameters
207 {
208 	vk::wsi::Type	wsiType;
209 	TestDimension	dimension;
210 
TestParametersvkt::ProtectedMem::__anon5d8586710111::TestParameters211 	TestParameters (vk::wsi::Type wsiType_, TestDimension dimension_)
212 		: wsiType	(wsiType_)
213 		, dimension	(dimension_)
214 	{}
215 
TestParametersvkt::ProtectedMem::__anon5d8586710111::TestParameters216 	TestParameters (void)
217 		: wsiType	(vk::wsi::TYPE_LAST)
218 		, dimension	(TEST_DIMENSION_LAST)
219 	{}
220 };
221 
firstSupportedCompositeAlpha(const vk::VkSurfaceCapabilitiesKHR & capabilities)222 static vk::VkCompositeAlphaFlagBitsKHR firstSupportedCompositeAlpha(const vk::VkSurfaceCapabilitiesKHR& capabilities)
223 {
224 	deUint32 alphaMode = 1u;
225 
226 	for (;alphaMode < capabilities.supportedCompositeAlpha;	alphaMode = alphaMode<<1u)
227 	{
228 		if ((alphaMode & capabilities.supportedCompositeAlpha) != 0)
229 		{
230 			break;
231 		}
232 	}
233 
234 	return (vk::VkCompositeAlphaFlagBitsKHR)alphaMode;
235 }
236 
237 using SwapchainCreationExecutor = void (*)(const vk::DeviceDriver&, vk::VkDevice, const vk::VkSwapchainCreateInfoKHR&, tcu::TestLog&, uint32_t, uint32_t);
swapchainCreateExecutor(const vk::DeviceDriver & vk,vk::VkDevice device,const vk::VkSwapchainCreateInfoKHR & createInfo,tcu::TestLog & log,uint32_t caseIndex,uint32_t caseCount)238 void swapchainCreateExecutor(const vk::DeviceDriver& vk, vk::VkDevice device, const vk::VkSwapchainCreateInfoKHR& createInfo, tcu::TestLog& log, uint32_t caseIndex, uint32_t caseCount)
239 {
240 	log << tcu::TestLog::Message << "Sub-case " << caseIndex << " / " << caseCount << ": " << createInfo << tcu::TestLog::EndMessage;
241 	const vk::Unique<vk::VkSwapchainKHR>	swapchain	(createSwapchainKHR(vk, device, &createInfo));
242 }
243 
executeSwapchainParameterCases(vk::wsi::Type wsiType,TestDimension dimension,const ProtectedContext & context,const vk::VkSurfaceCapabilitiesKHR & capabilities,const std::vector<vk::VkSurfaceFormatKHR> & formats,const std::vector<vk::VkPresentModeKHR> & presentModes,bool isExtensionForPresentModeEnabled,SwapchainCreationExecutor testExecutor)244 tcu::TestStatus executeSwapchainParameterCases (vk::wsi::Type								wsiType,
245 												TestDimension								dimension,
246 												const ProtectedContext&						context,
247 												const vk::VkSurfaceCapabilitiesKHR&			capabilities,
248 												const std::vector<vk::VkSurfaceFormatKHR>&	formats,
249 												const std::vector<vk::VkPresentModeKHR>&	presentModes,
250 												bool										isExtensionForPresentModeEnabled,
251 												SwapchainCreationExecutor					testExecutor)
252 {
253 	tcu::TestLog&								log					= context.getTestContext().getLog();
254 	const vk::DeviceInterface&					vki					= context.getDeviceInterface();
255 	const vk::DeviceDriver&						vkd					= context.getDeviceDriver();
256 	vk::VkDevice								device				= context.getDevice();
257 	const vk::wsi::PlatformProperties&			platformProperties	= getPlatformProperties(wsiType);
258 	const vk::VkSurfaceTransformFlagBitsKHR		defaultTransform	= (capabilities.supportedTransforms & vk::VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR)
259 																		? vk::VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR : capabilities.currentTransform;
260 	deUint32									queueIdx			= context.getQueueFamilyIndex();
261 	const vk::VkSurfaceKHR						surface				= context.getSurface();
262 	const vk::VkSwapchainCreateInfoKHR			baseParameters		=
263 	{
264 		vk::VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
265 		DE_NULL,
266 #ifndef NOT_PROTECTED
267 		vk::VK_SWAPCHAIN_CREATE_PROTECTED_BIT_KHR,
268 #else
269 		(vk::VkSwapchainCreateFlagsKHR)0,
270 #endif
271 		surface,
272 		capabilities.minImageCount,
273 		formats[0].format,
274 		formats[0].colorSpace,
275 		(platformProperties.swapchainExtent == vk::wsi::PlatformProperties::SWAPCHAIN_EXTENT_SETS_WINDOW_SIZE
276 			? capabilities.minImageExtent : capabilities.currentExtent),
277 		1u,									// imageArrayLayers
278 		vk::VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
279 		vk::VK_SHARING_MODE_EXCLUSIVE,
280 		1u,
281 		&queueIdx,
282 		defaultTransform,
283 		firstSupportedCompositeAlpha(capabilities),
284 		vk::VK_PRESENT_MODE_FIFO_KHR,
285 		VK_FALSE,							// clipped
286 		(vk::VkSwapchainKHR)0				// oldSwapchain
287 	};
288 
289 	vk::VkImageCreateFlags imageCreateFlag =
290 #ifndef NOT_PROTECTED
291 		vk::VK_IMAGE_CREATE_PROTECTED_BIT;
292 #else
293 		(vk::VkImageCreateFlags)0u;
294 #endif
295 
296 	switch (dimension)
297 	{
298 		case TEST_DIMENSION_MIN_IMAGE_COUNT:
299 		{
300 			// Estimate how much memory each swapchain image consumes. This isn't perfect, since
301 			// swapchain images may have additional constraints that equivalent non-swapchain
302 			// images don't have. But it's the best we can do.
303 			vk::VkMemoryRequirements				memoryRequirements;
304 			{
305 				const vk::VkImageCreateInfo			imageInfo			=
306 				{
307 					vk::VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
308 					DE_NULL,
309 					imageCreateFlag,
310 					vk::VK_IMAGE_TYPE_2D,
311 					baseParameters.imageFormat,
312 					{
313 						baseParameters.imageExtent.width,
314 						baseParameters.imageExtent.height,
315 						1,
316 					},
317 					1,	// mipLevels
318 					baseParameters.imageArrayLayers,
319 					vk::VK_SAMPLE_COUNT_1_BIT,
320 					vk::VK_IMAGE_TILING_OPTIMAL,
321 					baseParameters.imageUsage,
322 					baseParameters.imageSharingMode,
323 					baseParameters.queueFamilyIndexCount,
324 					baseParameters.pQueueFamilyIndices,
325 					vk::VK_IMAGE_LAYOUT_UNDEFINED
326 				};
327 				vk::Move<vk::VkImage>				image				= vk::createImage(vki, device, &imageInfo);
328 
329 				memoryRequirements	= vk::getImageMemoryRequirements(vki, device, *image);
330 			}
331 
332 			// Determine the maximum memory heap space available for protected images
333 			vk::VkPhysicalDeviceMemoryProperties	memoryProperties	= vk::getPhysicalDeviceMemoryProperties(context.getInstanceDriver(), context.getPhysicalDevice());
334 			vk::VkDeviceSize						protectedHeapSize	= 0;
335 			deUint32								protectedHeapMask	= 0;
336 
337 			for (deUint32 memType = 0; memType < memoryProperties.memoryTypeCount; memType++)
338 			{
339 				deUint32 heapIndex	= memoryProperties.memoryTypes[memType].heapIndex;
340 				if ((memoryRequirements.memoryTypeBits & (1u << memType)) != 0 &&
341 #ifndef NOT_PROTECTED
342 					(memoryProperties.memoryTypes[memType].propertyFlags & vk::VK_MEMORY_PROPERTY_PROTECTED_BIT) != 0 &&
343 #endif
344 					(protectedHeapMask & (1u << heapIndex)) == 0)
345 				{
346 					protectedHeapSize = de::max(protectedHeapSize, memoryProperties.memoryHeaps[heapIndex].size);
347 					protectedHeapMask |= 1u << heapIndex;
348 				}
349 			}
350 
351 			vk::VkDeviceSize	minProtectedHeapSize	= 0u;
352 			vk::VkDeviceSize	maxProtectedHeapSize	= protectedHeapSize;
353 			bool				passed					= false;
354 			// Apply binary search to see if we have suitable memory amount for test
355 			while (minProtectedHeapSize <= maxProtectedHeapSize)
356 			{
357 				// If the implementation doesn't have a max image count, min+16 means we won't clamp.
358 				// Limit it to how many protected images we estimate can be allocated
359 				const deUint32	maxImageCount		= de::min((capabilities.maxImageCount > 0u) ? capabilities.maxImageCount : capabilities.minImageCount + 16u,
360 																deUint32(protectedHeapSize / memoryRequirements.size));
361 				if (maxImageCount < capabilities.minImageCount)
362 				{
363 					minProtectedHeapSize = protectedHeapSize + 1u;
364 					protectedHeapSize = minProtectedHeapSize + (maxProtectedHeapSize - minProtectedHeapSize) / 2u;
365 					continue;
366 				}
367 
368 				try
369 				{
370 					log << tcu::TestLog::Message << "Starting test cases with protectedHeapSize of " << protectedHeapSize << tcu::TestLog::EndMessage;
371 					const deUint32	maxImageCountToTest	= de::clamp(16u, capabilities.minImageCount, maxImageCount);
372 					uint32_t		testCount			= maxImageCount - capabilities.minImageCount + 1u;
373 					uint32_t		testIndex			= 0u;
374 					// Loop downwards since we want to catch OOM errors as fast as possible
375 					for (uint32_t imageCount = maxImageCountToTest; capabilities.minImageCount <= imageCount; --imageCount)
376 					{
377 						vk::VkSwapchainCreateInfoKHR	createInfo = baseParameters;
378 						createInfo.minImageCount	= imageCount;
379 						testExecutor(vkd, device, createInfo, log, ++testIndex, testCount);
380 					}
381 					passed	= true;
382 				}
383 				catch (vk::OutOfMemoryError&)
384 				{
385 					log << tcu::TestLog::Message << "Test cases failed with OOM error. Checking if smaller heap size is possible." << tcu::TestLog::EndMessage;
386 					maxProtectedHeapSize = protectedHeapSize - 1u;
387 					protectedHeapSize = minProtectedHeapSize + (maxProtectedHeapSize - minProtectedHeapSize) / 2u;
388 					continue;
389 				}
390 
391 				break;
392 			}
393 
394 			if (!passed)
395 				TCU_THROW(NotSupportedError, "Memory heap doesn't have enough memory!");
396 
397 			break;
398 		}
399 
400 		case TEST_DIMENSION_IMAGE_FORMAT:
401 		{
402 			vk::VkPhysicalDeviceMemoryProperties	memoryProperties	= vk::getPhysicalDeviceMemoryProperties(context.getInstanceDriver(), context.getPhysicalDevice());
403 			vk::VkDeviceSize						protectedHeapSize	= 0;
404 
405 			for (deUint32 memType = 0; memType < memoryProperties.memoryTypeCount; memType++)
406 			{
407 				deUint32 heapIndex	= memoryProperties.memoryTypes[memType].heapIndex;
408 #ifndef NOT_PROTECTED
409 				if (memoryProperties.memoryTypes[memType].propertyFlags & vk::VK_MEMORY_PROPERTY_PROTECTED_BIT)
410 #endif
411 				{
412 					protectedHeapSize = de::max(protectedHeapSize, memoryProperties.memoryHeaps[heapIndex].size);
413 				}
414 			}
415 
416 			bool		atLeastOnePassed	= false;
417 			uint32_t	testIndex			= 0u;
418 			uint32_t	testCount			= static_cast<uint32_t>(formats.size());
419 			for (std::vector<vk::VkSurfaceFormatKHR>::const_iterator curFmt = formats.begin(); curFmt != formats.end(); ++curFmt)
420 			{
421 				vk::VkMemoryRequirements memoryRequirements;
422 				{
423 					const vk::VkImageCreateInfo imageInfo =
424 					{
425 						vk::VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
426 						DE_NULL,
427 						imageCreateFlag,
428 						vk::VK_IMAGE_TYPE_2D,
429 						curFmt->format,
430 						{
431 							platformProperties.swapchainExtent == vk::wsi::PlatformProperties::SWAPCHAIN_EXTENT_SETS_WINDOW_SIZE
432 								? capabilities.minImageExtent.width : capabilities.currentExtent.width,
433 							platformProperties.swapchainExtent == vk::wsi::PlatformProperties::SWAPCHAIN_EXTENT_SETS_WINDOW_SIZE
434 							? capabilities.minImageExtent.height : capabilities.currentExtent.height,
435 							1,
436 						},
437 						1,	// mipLevels
438 						baseParameters.imageArrayLayers,
439 						vk::VK_SAMPLE_COUNT_1_BIT,
440 						vk::VK_IMAGE_TILING_OPTIMAL,
441 						baseParameters.imageUsage,
442 						baseParameters.imageSharingMode,
443 						baseParameters.queueFamilyIndexCount,
444 						baseParameters.pQueueFamilyIndices,
445 						vk::VK_IMAGE_LAYOUT_UNDEFINED
446 					};
447 
448 						vk::Move<vk::VkImage> image = vk::createImage(vki, device, &imageInfo);
449 
450 						memoryRequirements = vk::getImageMemoryRequirements(vki, device, *image);
451 				}
452 
453 					// Check for the image size requirement based on double/triple buffering
454 					if (memoryRequirements.size  * capabilities.minImageCount < protectedHeapSize)
455 					{
456 						vk::VkSwapchainCreateInfoKHR	createInfo = baseParameters;
457 						createInfo.imageFormat		= curFmt->format;
458 						createInfo.imageColorSpace	= curFmt->colorSpace;
459 						try
460 						{
461 							testExecutor(vkd, device, createInfo, log, ++testIndex, testCount);
462 							atLeastOnePassed	|= true;
463 						}
464 						catch (vk::OutOfMemoryError&)
465 						{
466 							log << tcu::TestLog::Message << "Previous test case failed with OOM error." << tcu::TestLog::EndMessage;
467 							continue;
468 						}
469 					}
470 					else
471 						log << tcu::TestLog::Message << "Skipping test case " << ++testIndex << "/" << testCount << tcu::TestLog::EndMessage;
472 			}
473 
474 			if (!atLeastOnePassed)
475 				TCU_THROW(NotSupportedError, "Memory heap doesn't have enough memory!");
476 
477 			break;
478 		}
479 
480 		case TEST_DIMENSION_IMAGE_EXTENT:
481 		{
482 			static const vk::VkExtent2D	s_testSizes[]	=
483 			{
484 				{ 1, 1 },
485 				{ 16, 32 },
486 				{ 32, 16 },
487 				{ 632, 231 },
488 				{ 117, 998 },
489 			};
490 
491 			vk::VkPhysicalDeviceMemoryProperties	memoryProperties	= vk::getPhysicalDeviceMemoryProperties(context.getInstanceDriver(), context.getPhysicalDevice());
492 			vk::VkDeviceSize						protectedHeapSize	= 0;
493 
494 			for (deUint32 memType = 0; memType < memoryProperties.memoryTypeCount; memType++)
495 			{
496 				deUint32 heapIndex	= memoryProperties.memoryTypes[memType].heapIndex;
497 #ifndef NOT_PROTECTED
498 				if (memoryProperties.memoryTypes[memType].propertyFlags & vk::VK_MEMORY_PROPERTY_PROTECTED_BIT)
499 #endif
500 				{
501 					protectedHeapSize = de::max(protectedHeapSize, memoryProperties.memoryHeaps[heapIndex].size);
502 				}
503 			}
504 
505 			bool	atLeastOnePassed	= false;
506 			if (platformProperties.swapchainExtent == vk::wsi::PlatformProperties::SWAPCHAIN_EXTENT_SETS_WINDOW_SIZE ||
507 				platformProperties.swapchainExtent == vk::wsi::PlatformProperties::SWAPCHAIN_EXTENT_SCALED_TO_WINDOW_SIZE)
508 			{
509 				uint32_t	testCount	= DE_LENGTH_OF_ARRAY(s_testSizes);
510 				for (uint32_t ndx = 0; ndx < testCount; ++ndx)
511 				{
512 					vk::VkMemoryRequirements memoryRequirements;
513 					{
514 						const vk::VkImageCreateInfo imageInfo =
515 						{
516 							vk::VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
517 							DE_NULL,
518 							imageCreateFlag,
519 							vk::VK_IMAGE_TYPE_2D,
520 							baseParameters.imageFormat,
521 							{
522 								s_testSizes[ndx].width,
523 								s_testSizes[ndx].height,
524 								1,
525 							},
526 							1,	// mipLevels
527 							baseParameters.imageArrayLayers,
528 							vk::VK_SAMPLE_COUNT_1_BIT,
529 							vk::VK_IMAGE_TILING_OPTIMAL,
530 							baseParameters.imageUsage,
531 							baseParameters.imageSharingMode,
532 							baseParameters.queueFamilyIndexCount,
533 							baseParameters.pQueueFamilyIndices,
534 							vk::VK_IMAGE_LAYOUT_UNDEFINED
535 						};
536 
537 						vk::Move<vk::VkImage> image = vk::createImage(vki, device, &imageInfo);
538 
539 						memoryRequirements = vk::getImageMemoryRequirements(vki, device, *image);
540 					}
541 
542 					// Check for the image size requirement based on double/triple buffering
543 					if (memoryRequirements.size  * capabilities.minImageCount < protectedHeapSize)
544 					{
545 						vk::VkSwapchainCreateInfoKHR	createInfo = baseParameters;
546 						createInfo.imageExtent.width	= de::clamp(s_testSizes[ndx].width, capabilities.minImageExtent.width, capabilities.maxImageExtent.width);
547 						createInfo.imageExtent.height	= de::clamp(s_testSizes[ndx].height, capabilities.minImageExtent.height, capabilities.maxImageExtent.height);
548 						try
549 						{
550 							testExecutor(vkd, device, createInfo, log, ndx + 1u, testCount);
551 							atLeastOnePassed	|= true;
552 						}
553 						catch (vk::OutOfMemoryError&)
554 						{
555 							log << tcu::TestLog::Message << "Previous test case failed with OOM error." << tcu::TestLog::EndMessage;
556 							continue;
557 						}
558 					}
559 					else
560 						log << tcu::TestLog::Message << "Skipping test case " << ndx + 1u << "/" << testCount << tcu::TestLog::EndMessage;
561 				}
562 			}
563 
564 			if (platformProperties.swapchainExtent != vk::wsi::PlatformProperties::SWAPCHAIN_EXTENT_SETS_WINDOW_SIZE)
565 			{
566 				vk::VkMemoryRequirements memoryRequirements;
567 				{
568 					const vk::VkImageCreateInfo imageInfo =
569 					{
570 						vk::VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
571 						DE_NULL,
572 						imageCreateFlag,
573 						vk::VK_IMAGE_TYPE_2D,
574 						baseParameters.imageFormat,
575 						{
576 							capabilities.currentExtent.width,
577 							capabilities.currentExtent.height,
578 							1,
579 						},
580 						1,	// mipLevels
581 						baseParameters.imageArrayLayers,
582 						vk::VK_SAMPLE_COUNT_1_BIT,
583 						vk::VK_IMAGE_TILING_OPTIMAL,
584 						baseParameters.imageUsage,
585 						baseParameters.imageSharingMode,
586 						baseParameters.queueFamilyIndexCount,
587 						baseParameters.pQueueFamilyIndices,
588 						vk::VK_IMAGE_LAYOUT_UNDEFINED
589 					};
590 
591 					vk::Move<vk::VkImage> image = vk::createImage(vki, device, &imageInfo);
592 
593 					memoryRequirements = vk::getImageMemoryRequirements(vki, device, *image);
594 				}
595 
596 				// Check for the image size requirement based on double/triple buffering
597 				if (memoryRequirements.size  * capabilities.minImageCount < protectedHeapSize)
598 				{
599 					vk::VkSwapchainCreateInfoKHR	createInfo = baseParameters;
600 					createInfo.imageExtent	= capabilities.currentExtent;
601 					try
602 					{
603 						testExecutor(vkd, device, createInfo, log, 1u, 1u);
604 						atLeastOnePassed	|= true;
605 					}
606 					catch (vk::OutOfMemoryError&)
607 					{
608 						log << tcu::TestLog::Message << "Previous test case failed with OOM error." << tcu::TestLog::EndMessage;
609 					}
610 				}
611 				else
612 					log << tcu::TestLog::Message << "Skipping test case " << 1u << "/" << 1u << tcu::TestLog::EndMessage;
613 			}
614 
615 			if (platformProperties.swapchainExtent != vk::wsi::PlatformProperties::SWAPCHAIN_EXTENT_MUST_MATCH_WINDOW_SIZE)
616 			{
617 				static const vk::VkExtent2D	s_testExtentSizes[]	=
618 				{
619 					{ capabilities.minImageExtent.width, capabilities.minImageExtent.height },
620 					{ capabilities.maxImageExtent.width, capabilities.maxImageExtent.height },
621 				};
622 
623 				uint32_t	testCount	= DE_LENGTH_OF_ARRAY(s_testExtentSizes);
624 				for (uint32_t ndx = 0; ndx < testCount; ++ndx)
625 				{
626 					vk::VkMemoryRequirements memoryRequirements;
627 					{
628 						const vk::VkImageCreateInfo	imageInfo =
629 						{
630 							vk::VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
631 							DE_NULL,
632 							imageCreateFlag,
633 							vk::VK_IMAGE_TYPE_2D,
634 							baseParameters.imageFormat,
635 							{
636 								s_testExtentSizes[ndx].width,
637 								s_testExtentSizes[ndx].height,
638 								1,
639 							},
640 							1,	// mipLevels
641 							baseParameters.imageArrayLayers,
642 							vk::VK_SAMPLE_COUNT_1_BIT,
643 							vk::VK_IMAGE_TILING_OPTIMAL,
644 							baseParameters.imageUsage,
645 							baseParameters.imageSharingMode,
646 							baseParameters.queueFamilyIndexCount,
647 							baseParameters.pQueueFamilyIndices,
648 							vk::VK_IMAGE_LAYOUT_UNDEFINED
649 						};
650 
651 						vk::Move<vk::VkImage> image = vk::createImage(vki, device, &imageInfo);
652 
653 						memoryRequirements = vk::getImageMemoryRequirements(vki, device, *image);
654 					}
655 
656 					// Check for the image size requirement based on double/triple buffering
657 					if (memoryRequirements.size  * capabilities.minImageCount < protectedHeapSize)
658 					{
659 						vk::VkSwapchainCreateInfoKHR	createInfo = baseParameters;
660 						createInfo.imageExtent	= s_testExtentSizes[ndx];
661 						try
662 						{
663 							testExecutor(vkd, device, createInfo, log, ndx + 1u, testCount);
664 							atLeastOnePassed	|= true;
665 						}
666 						catch (vk::OutOfMemoryError&)
667 						{
668 							log << tcu::TestLog::Message << "Previous test case failed with OOM error." << tcu::TestLog::EndMessage;
669 							continue;
670 						}
671 					}
672 					else
673 						log << tcu::TestLog::Message << "Skipping test case " << ndx + 1u << "/" << testCount << tcu::TestLog::EndMessage;
674 				}
675 			}
676 
677 			if (!atLeastOnePassed)
678 				TCU_THROW(NotSupportedError, "Memory heap doesn't have enough memory!");
679 
680 			break;
681 		}
682 
683 		case TEST_DIMENSION_IMAGE_ARRAY_LAYERS:
684 		{
685 			const deUint32	maxLayers	= de::min(capabilities.maxImageArrayLayers, 16u);
686 
687 			for (deUint32 numLayers = 1; numLayers <= maxLayers; ++numLayers)
688 			{
689 				vk::VkSwapchainCreateInfoKHR	createInfo = baseParameters;
690 				createInfo.imageArrayLayers	= numLayers;
691 				testExecutor(vkd, device, createInfo, log, numLayers, maxLayers + 1u);
692 			}
693 
694 			break;
695 		}
696 
697 		case TEST_DIMENSION_IMAGE_USAGE:
698 		{
699 			uint32_t	testIndex	= 0u;
700 			uint32_t	testCount	= 0u;
701 			for (deUint32 flags = 1u; flags <= capabilities.supportedUsageFlags; ++flags)
702 			{
703 				if ((flags & ~capabilities.supportedUsageFlags) == 0)
704 					testCount++;
705 			}
706 
707 			for (deUint32 flags = 1u; flags <= capabilities.supportedUsageFlags; ++flags)
708 			{
709 				if ((flags & ~capabilities.supportedUsageFlags) == 0)
710 				{
711 					vk::VkSwapchainCreateInfoKHR	createInfo = baseParameters;
712 					createInfo.imageUsage	= flags;
713 					testExecutor(vkd, device, createInfo, log, ++testIndex, testCount);
714 				}
715 			}
716 
717 			break;
718 		}
719 
720 		case TEST_DIMENSION_IMAGE_SHARING_MODE:
721 		{
722 			vk::VkSwapchainCreateInfoKHR	createInfo = baseParameters;
723 			createInfo.imageSharingMode	= vk::VK_SHARING_MODE_EXCLUSIVE;
724 			testExecutor(vkd, device, createInfo, log, 1u, 2u);
725 
726 			uint32_t	additionalQueueIndex	= std::numeric_limits<uint32_t>::max();
727 			{
728 				const vk::InstanceDriver&					instanceDriver	= context.getInstanceDriver();
729 				const vk::VkPhysicalDevice					physicalDevice	= context.getPhysicalDevice();
730 				std::vector<vk::VkQueueFamilyProperties>	properties;
731 				deUint32									numFamilies		= 0;
732 
733 				instanceDriver.getPhysicalDeviceQueueFamilyProperties(physicalDevice, &numFamilies, DE_NULL);
734 				DE_ASSERT(numFamilies > 0);
735 				properties.resize(numFamilies);
736 
737 				instanceDriver.getPhysicalDeviceQueueFamilyProperties(physicalDevice, &numFamilies, properties.data());
738 
739 				vk::VkQueueFlags	requiredFlags = vk::VK_QUEUE_PROTECTED_BIT;
740 				for (size_t idx = 0; idx < properties.size(); ++idx)
741 				{
742 					vk::VkQueueFlags	flags = properties[idx].queueFlags;
743 
744 					if ((flags & requiredFlags) == requiredFlags && idx != queueIdx)
745 					{
746 						additionalQueueIndex	= static_cast<uint32_t>(idx);
747 						break;
748 					}
749 				}
750 			}
751 
752 			// Can only test if we have multiple queues with required flags
753 			if (additionalQueueIndex != std::numeric_limits<uint32_t>::max())
754 			{
755 				uint32_t	queueIndices[2]	= { queueIdx, additionalQueueIndex };
756 				createInfo.imageSharingMode			= vk::VK_SHARING_MODE_CONCURRENT;
757 				createInfo.queueFamilyIndexCount	= 2u;
758 				createInfo.pQueueFamilyIndices		= queueIndices;
759 				testExecutor(vkd, device, createInfo, log, 2u, 2u);
760 			}
761 			else
762 				log << tcu::TestLog::Message << "No 2 queues with required flags (VK_QUEUE_PROTECTED_BIT) found. Skipping test case " << 2u << "/" << 2u << tcu::TestLog::EndMessage;
763 
764 			break;
765 		}
766 
767 		case TEST_DIMENSION_PRE_TRANSFORM:
768 		{
769 			uint32_t	testIndex	= 0u;
770 			uint32_t	testCount	= 0u;
771 			for (deUint32 transform = 1u;
772 				 transform <= capabilities.supportedTransforms;
773 				 transform = transform<<1u)
774 			{
775 				if ((transform & capabilities.supportedTransforms) != 0)
776 					testCount++;
777 			}
778 
779 			for (deUint32 transform = 1u;
780 				 transform <= capabilities.supportedTransforms;
781 				 transform = transform<<1u)
782 			{
783 				if ((transform & capabilities.supportedTransforms) != 0)
784 				{
785 					vk::VkSwapchainCreateInfoKHR	createInfo = baseParameters;
786 					createInfo.preTransform	= (vk::VkSurfaceTransformFlagBitsKHR)transform;
787 					testExecutor(vkd, device, createInfo, log, ++testIndex, testCount);
788 				}
789 			}
790 
791 			break;
792 		}
793 
794 		case TEST_DIMENSION_COMPOSITE_ALPHA:
795 		{
796 			uint32_t	testIndex	= 0u;
797 			uint32_t	testCount	= 0u;
798 			for (deUint32 alphaMode = 1u;
799 				 alphaMode <= capabilities.supportedCompositeAlpha;
800 				 alphaMode = alphaMode<<1u)
801 			{
802 				if ((alphaMode & capabilities.supportedCompositeAlpha) != 0)
803 					testCount++;
804 			}
805 
806 			for (deUint32 alphaMode = 1u;
807 				 alphaMode <= capabilities.supportedCompositeAlpha;
808 				 alphaMode = alphaMode<<1u)
809 			{
810 				if ((alphaMode & capabilities.supportedCompositeAlpha) != 0)
811 				{
812 					vk::VkSwapchainCreateInfoKHR	createInfo = baseParameters;
813 					createInfo.compositeAlpha	= (vk::VkCompositeAlphaFlagBitsKHR)alphaMode;
814 					testExecutor(vkd, device, createInfo, log, ++testIndex, testCount);
815 				}
816 			}
817 
818 			break;
819 		}
820 
821 		case TEST_DIMENSION_PRESENT_MODE:
822 		{
823 			uint32_t	testIndex	= 0u;
824 			uint32_t	testCount	= static_cast<uint32_t>(presentModes.size());
825 			for (std::vector<vk::VkPresentModeKHR>::const_iterator curMode = presentModes.begin(); curMode != presentModes.end(); ++curMode)
826 			{
827 				vk::VkSwapchainCreateInfoKHR	createInfo = baseParameters;
828 				if (*curMode == vk::VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR || *curMode == vk::VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR)
829 				{
830 					if (isExtensionForPresentModeEnabled)
831 						createInfo.minImageCount = 1u; // Required by VUID-VkSwapchainCreateInfoKHR-minImageCount-01383
832 					else
833 					{
834 						log << tcu::TestLog::Message << "Present mode (" << *curMode <<") not supported. Skipping test case " << ++testIndex << "/" << testCount << tcu::TestLog::EndMessage;
835 						continue;
836 					}
837 				}
838 				createInfo.presentMode	= *curMode;
839 				testExecutor(vkd, device, createInfo, log, ++testIndex, testCount);
840 			}
841 
842 			break;
843 		}
844 
845 		case TEST_DIMENSION_CLIPPED:
846 		{
847 			vk::VkSwapchainCreateInfoKHR	createInfo = baseParameters;
848 			createInfo.clipped	= VK_FALSE;
849 			testExecutor(vkd, device, createInfo, log, 1u, 2u);
850 
851 			createInfo.clipped	= VK_TRUE;
852 			testExecutor(vkd, device, createInfo, log, 2u, 2u);
853 
854 			break;
855 		}
856 
857 		default:
858 			DE_FATAL("Impossible");
859 	}
860 
861 	return tcu::TestStatus::pass("Creating swapchain succeeded");
862 }
863 
executeSwapchainParameterCases(vk::wsi::Type wsiType,TestDimension dimension,const ProtectedContext & context,vk::VkSurfaceKHR surface,bool isExtensionForPresentModeEnabled,SwapchainCreationExecutor testExecutor)864 tcu::TestStatus executeSwapchainParameterCases (vk::wsi::Type				wsiType,
865 												TestDimension				dimension,
866 												const ProtectedContext&		context,
867 												vk::VkSurfaceKHR			surface,
868 												bool						isExtensionForPresentModeEnabled,
869 												SwapchainCreationExecutor	testExecutor)
870 {
871 	const vk::InstanceInterface&				vki				= context.getInstanceDriver();
872 	vk::VkPhysicalDevice						physicalDevice	= context.getPhysicalDevice();
873 	const vk::VkSurfaceCapabilitiesKHR			capabilities	= vk::wsi::getPhysicalDeviceSurfaceCapabilities(vki,
874 																											   physicalDevice,
875 																											   surface);
876 	const std::vector<vk::VkSurfaceFormatKHR>	formats			= vk::wsi::getPhysicalDeviceSurfaceFormats(vki,
877 																										   physicalDevice,
878 																										   surface);
879 	const std::vector<vk::VkPresentModeKHR>		presentModes	= vk::wsi::getPhysicalDeviceSurfacePresentModes(vki,
880 																											    physicalDevice,
881 																											    surface);
882 
883 	return executeSwapchainParameterCases(wsiType, dimension, context, capabilities, formats, presentModes, isExtensionForPresentModeEnabled, testExecutor);
884 }
885 
createSwapchainTest(Context & baseCtx,TestParameters params)886 tcu::TestStatus createSwapchainTest (Context& baseCtx, TestParameters params)
887 {
888 	bool											isExtensionForPresentModeEnabled	= false;
889 	std::vector<vk::VkExtensionProperties>			supportedExtensions (enumerateInstanceExtensionProperties(baseCtx.getPlatformInterface(), DE_NULL));
890 	std::vector<std::string>						instExts	= getRequiredWsiExtensions(supportedExtensions, params.wsiType);
891 	std::vector<std::string>						devExts;
892 	devExts.push_back("VK_KHR_swapchain");
893 
894 	// Try to enable VK_KHR_shared_presentable_image for its respective present mode testing
895 	if (params.dimension == TEST_DIMENSION_PRESENT_MODE)
896 	{
897 		Extensions	deviceExtensions	= vk::enumerateDeviceExtensionProperties(baseCtx.getInstanceInterface(), baseCtx.getPhysicalDevice(), DE_NULL);
898 		for (size_t i = 0u; i < deviceExtensions.size(); ++i)
899 		{
900 			if (std::strcmp(deviceExtensions[i].extensionName, "VK_KHR_shared_presentable_image") == 0)
901 			{
902 				devExts.emplace_back("VK_KHR_shared_presentable_image");
903 				isExtensionForPresentModeEnabled	= true;
904 				break;
905 			}
906 		}
907 	}
908 
909 	const NativeObjects								native		(baseCtx, supportedExtensions, params.wsiType);
910 	ProtectedContext								context		(baseCtx, params.wsiType, *native.display, *native.window, instExts, devExts);
911 	vk::VkSurfaceKHR								surface		= context.getSurface();
912 
913 	return executeSwapchainParameterCases(params.wsiType, params.dimension, context, surface, isExtensionForPresentModeEnabled, swapchainCreateExecutor);
914 }
915 
916 struct GroupParameters
917 {
918 	typedef FunctionInstance1<TestParameters>::Function	Function;
919 
920 	vk::wsi::Type	wsiType;
921 	Function		function;
922 
GroupParametersvkt::ProtectedMem::__anon5d8586710111::GroupParameters923 	GroupParameters (vk::wsi::Type wsiType_, Function function_)
924 		: wsiType	(wsiType_)
925 		, function	(function_)
926 	{}
927 
GroupParametersvkt::ProtectedMem::__anon5d8586710111::GroupParameters928 	GroupParameters (void)
929 		: wsiType	(vk::wsi::TYPE_LAST)
930 		, function	((Function)DE_NULL)
931 	{}
932 };
933 
checkSupport(Context & context,TestParameters)934 void checkSupport (Context& context, TestParameters)
935 {
936 	checkProtectedQueueSupport(context);
937 }
938 
populateSwapchainGroup(tcu::TestCaseGroup * testGroup,GroupParameters params)939 void populateSwapchainGroup (tcu::TestCaseGroup* testGroup, GroupParameters params)
940 {
941 	for (int dimensionNdx = 0; dimensionNdx < TEST_DIMENSION_LAST; ++dimensionNdx)
942 	{
943 		const TestDimension		testDimension	= (TestDimension)dimensionNdx;
944 
945 		addFunctionCase(testGroup, getTestDimensionName(testDimension), checkSupport, params.function, TestParameters(params.wsiType, testDimension));
946 	}
947 }
948 
getBasicSwapchainParameters(vk::wsi::Type wsiType,const vk::InstanceInterface & vki,vk::VkPhysicalDevice physicalDevice,vk::VkSurfaceKHR surface,const tcu::UVec2 & desiredSize,deUint32 desiredImageCount)949 vk::VkSwapchainCreateInfoKHR getBasicSwapchainParameters (vk::wsi::Type					wsiType,
950 														  const vk::InstanceInterface&	vki,
951 														  vk::VkPhysicalDevice			physicalDevice,
952 														  vk::VkSurfaceKHR				surface,
953 														  const tcu::UVec2&				desiredSize,
954 														  deUint32						desiredImageCount)
955 {
956 	const vk::VkSurfaceCapabilitiesKHR			capabilities		= vk::wsi::getPhysicalDeviceSurfaceCapabilities(vki,
957 																												    physicalDevice,
958 																												    surface);
959 	const std::vector<vk::VkSurfaceFormatKHR>	formats				= vk::wsi::getPhysicalDeviceSurfaceFormats(vki,
960 																											   physicalDevice,
961 																											   surface);
962 	const vk::wsi::PlatformProperties&			platformProperties	= vk::wsi::getPlatformProperties(wsiType);
963 	const vk::VkSurfaceTransformFlagBitsKHR		transform			= (capabilities.supportedTransforms & vk::VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR)
964 																		? vk::VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR : capabilities.currentTransform;
965 	const vk::VkSwapchainCreateInfoKHR			parameters			=
966 	{
967 		vk::VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
968 		DE_NULL,
969 		vk::VK_SWAPCHAIN_CREATE_PROTECTED_BIT_KHR,
970 		surface,
971 		de::clamp(desiredImageCount, capabilities.minImageCount, capabilities.maxImageCount > 0 ? capabilities.maxImageCount : capabilities.minImageCount + desiredImageCount),
972 		formats[0].format,
973 		formats[0].colorSpace,
974 		(platformProperties.swapchainExtent == vk::wsi::PlatformProperties::SWAPCHAIN_EXTENT_MUST_MATCH_WINDOW_SIZE
975 			? capabilities.currentExtent : vk::makeExtent2D(desiredSize.x(), desiredSize.y())),
976 		1u,									// imageArrayLayers
977 		vk::VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
978 		vk::VK_SHARING_MODE_EXCLUSIVE,
979 		0u,
980 		(const deUint32*)DE_NULL,
981 		transform,
982 		firstSupportedCompositeAlpha(capabilities),
983 		vk::VK_PRESENT_MODE_FIFO_KHR,
984 		VK_FALSE,							// clipped
985 		(vk::VkSwapchainKHR)0				// oldSwapchain
986 	};
987 
988 	return parameters;
989 }
990 
991 typedef de::SharedPtr<vk::Unique<vk::VkImageView> >		ImageViewSp;
992 typedef de::SharedPtr<vk::Unique<vk::VkFramebuffer> >	FramebufferSp;
993 
994 class TriangleRenderer
995 {
996 public:
997 												TriangleRenderer	(ProtectedContext&				context,
998 																	 const vk::BinaryCollection&	binaryRegistry,
999 																	 const std::vector<vk::VkImage>	swapchainImages,
1000 																	 const vk::VkFormat				framebufferFormat,
1001 																	 const tcu::UVec2&				renderSize);
1002 												~TriangleRenderer	(void);
1003 
1004 	void										recordFrame			(vk::VkCommandBuffer			cmdBuffer,
1005 																	 deUint32						imageNdx,
1006 																	 deUint32						frameNdx) const;
1007 
1008 	static void									getPrograms			(vk::SourceCollections&			dst);
1009 
1010 private:
1011 	static vk::Move<vk::VkRenderPass>			createRenderPass	(const vk::DeviceInterface&		vkd,
1012 																	 const vk::VkDevice				device,
1013 																	 const vk::VkFormat				colorAttachmentFormat);
1014 	static vk::Move<vk::VkPipelineLayout>		createPipelineLayout(const vk::DeviceInterface&		vkd,
1015 																	 vk::VkDevice					device);
1016 	static vk::Move<vk::VkPipeline>				createPipeline		(const vk::DeviceInterface&		vkd,
1017 																	 const vk::VkDevice				device,
1018 																	 const vk::VkRenderPass			renderPass,
1019 																	 const vk::VkPipelineLayout		pipelineLayout,
1020 																	 const vk::BinaryCollection&	binaryCollection,
1021 																	 const tcu::UVec2&				renderSize);
1022 
1023 	const vk::DeviceInterface&					m_vkd;
1024 
1025 	const std::vector<vk::VkImage>				m_swapchainImages;
1026 	const tcu::UVec2							m_renderSize;
1027 
1028 	const vk::Unique<vk::VkRenderPass>			m_renderPass;
1029 	const vk::Unique<vk::VkPipelineLayout>		m_pipelineLayout;
1030 	const vk::Unique<vk::VkPipeline>			m_pipeline;
1031 
1032 	const de::UniquePtr<vk::BufferWithMemory>	m_vertexBuffer;
1033 
1034 	std::vector<ImageViewSp>					m_attachmentViews;
1035 	std::vector<FramebufferSp>					m_framebuffers;
1036 };
1037 
createRenderPass(const vk::DeviceInterface & vkd,const vk::VkDevice device,const vk::VkFormat colorAttachmentFormat)1038 vk::Move<vk::VkRenderPass> TriangleRenderer::createRenderPass (const vk::DeviceInterface&	vkd,
1039 															   const vk::VkDevice			device,
1040 															   const vk::VkFormat			colorAttachmentFormat)
1041 {
1042 	const vk::VkAttachmentDescription	colorAttDesc		=
1043 	{
1044 		(vk::VkAttachmentDescriptionFlags)0,
1045 		colorAttachmentFormat,
1046 		vk::VK_SAMPLE_COUNT_1_BIT,
1047 		vk::VK_ATTACHMENT_LOAD_OP_CLEAR,
1048 		vk::VK_ATTACHMENT_STORE_OP_STORE,
1049 		vk::VK_ATTACHMENT_LOAD_OP_DONT_CARE,
1050 		vk::VK_ATTACHMENT_STORE_OP_DONT_CARE,
1051 		vk::VK_IMAGE_LAYOUT_UNDEFINED,
1052 		vk::VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
1053 	};
1054 	const vk::VkAttachmentReference		colorAttRef			=
1055 	{
1056 		0u,
1057 		vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
1058 	};
1059 	const vk::VkSubpassDescription		subpassDesc			=
1060 	{
1061 		(vk::VkSubpassDescriptionFlags)0u,
1062 		vk::VK_PIPELINE_BIND_POINT_GRAPHICS,
1063 		0u,							// inputAttachmentCount
1064 		DE_NULL,					// pInputAttachments
1065 		1u,							// colorAttachmentCount
1066 		&colorAttRef,				// pColorAttachments
1067 		DE_NULL,					// pResolveAttachments
1068 		DE_NULL,					// depthStencilAttachment
1069 		0u,							// preserveAttachmentCount
1070 		DE_NULL,					// pPreserveAttachments
1071 	};
1072 	const vk::VkSubpassDependency		dependencies[]		=
1073 	{
1074 		{
1075 			VK_SUBPASS_EXTERNAL,	// srcSubpass
1076 			0u,						// dstSubpass
1077 			vk::VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
1078 			vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
1079 			vk::VK_ACCESS_MEMORY_READ_BIT,
1080 			(vk::VK_ACCESS_COLOR_ATTACHMENT_READ_BIT|
1081 			 vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT),
1082 			vk::VK_DEPENDENCY_BY_REGION_BIT
1083 		},
1084 		{
1085 			0u,						// srcSubpass
1086 			VK_SUBPASS_EXTERNAL,	// dstSubpass
1087 			vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
1088 			vk::VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
1089 			(vk::VK_ACCESS_COLOR_ATTACHMENT_READ_BIT|
1090 			 vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT),
1091 			vk::VK_ACCESS_MEMORY_READ_BIT,
1092 			vk::VK_DEPENDENCY_BY_REGION_BIT
1093 		},
1094 	};
1095 	const vk::VkRenderPassCreateInfo	renderPassParams	=
1096 	{
1097 		vk::VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
1098 		DE_NULL,
1099 		(vk::VkRenderPassCreateFlags)0,
1100 		1u,
1101 		&colorAttDesc,
1102 		1u,
1103 		&subpassDesc,
1104 		DE_LENGTH_OF_ARRAY(dependencies),
1105 		dependencies,
1106 	};
1107 
1108 	return vk::createRenderPass(vkd, device, &renderPassParams);
1109 }
1110 
createPipelineLayout(const vk::DeviceInterface & vkd,const vk::VkDevice device)1111 vk::Move<vk::VkPipelineLayout> TriangleRenderer::createPipelineLayout (const vk::DeviceInterface&	vkd,
1112 																	   const vk::VkDevice			device)
1113 {
1114 	const vk::VkPushConstantRange					pushConstantRange		=
1115 	{
1116 		vk::VK_SHADER_STAGE_VERTEX_BIT,
1117 		0u,											// offset
1118 		(deUint32)sizeof(deUint32),					// size
1119 	};
1120 	const vk::VkPipelineLayoutCreateInfo			pipelineLayoutParams	=
1121 	{
1122 		vk::VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
1123 		DE_NULL,
1124 		(vk::VkPipelineLayoutCreateFlags)0,
1125 		0u,											// setLayoutCount
1126 		DE_NULL,									// pSetLayouts
1127 		1u,
1128 		&pushConstantRange,
1129 	};
1130 
1131 	return vk::createPipelineLayout(vkd, device, &pipelineLayoutParams);
1132 }
1133 
createPipeline(const vk::DeviceInterface & vkd,const vk::VkDevice device,const vk::VkRenderPass renderPass,const vk::VkPipelineLayout pipelineLayout,const vk::BinaryCollection & binaryCollection,const tcu::UVec2 & renderSize)1134 vk::Move<vk::VkPipeline> TriangleRenderer::createPipeline (const vk::DeviceInterface&	vkd,
1135 														   const vk::VkDevice			device,
1136 														   const vk::VkRenderPass		renderPass,
1137 														   const vk::VkPipelineLayout	pipelineLayout,
1138 														   const vk::BinaryCollection&	binaryCollection,
1139 														   const tcu::UVec2&			renderSize)
1140 {
1141 	// \note VkShaderModules are fully consumed by vkCreateGraphicsPipelines()
1142 	//		 and can be deleted immediately following that call.
1143 	const vk::Unique<vk::VkShaderModule>				vertShaderModule		(createShaderModule(vkd, device, binaryCollection.get("tri-vert"), 0));
1144 	const vk::Unique<vk::VkShaderModule>				fragShaderModule		(createShaderModule(vkd, device, binaryCollection.get("tri-frag"), 0));
1145 	const std::vector<vk::VkViewport>					viewports				(1, vk::makeViewport(renderSize));
1146 	const std::vector<vk::VkRect2D>						scissors				(1, vk::makeRect2D(renderSize));
1147 
1148 	return vk::makeGraphicsPipeline(vkd,				// const DeviceInterface&            vk
1149 									device,				// const VkDevice                    device
1150 									pipelineLayout,		// const VkPipelineLayout            pipelineLayout
1151 									*vertShaderModule,	// const VkShaderModule              vertexShaderModule
1152 									DE_NULL,			// const VkShaderModule              tessellationControlShaderModule
1153 									DE_NULL,			// const VkShaderModule              tessellationEvalShaderModule
1154 									DE_NULL,			// const VkShaderModule              geometryShaderModule
1155 									*fragShaderModule,	// const VkShaderModule              fragmentShaderModule
1156 									renderPass,			// const VkRenderPass                renderPass
1157 									viewports,			// const std::vector<VkViewport>&    viewports
1158 									scissors);			// const std::vector<VkRect2D>&      scissors
1159 }
1160 
TriangleRenderer(ProtectedContext & context,const vk::BinaryCollection & binaryRegistry,const std::vector<vk::VkImage> swapchainImages,const vk::VkFormat framebufferFormat,const tcu::UVec2 & renderSize)1161 TriangleRenderer::TriangleRenderer (ProtectedContext&				context,
1162 									const vk::BinaryCollection&		binaryRegistry,
1163 									const std::vector<vk::VkImage>	swapchainImages,
1164 									const vk::VkFormat				framebufferFormat,
1165 									const tcu::UVec2&				renderSize)
1166 	: m_vkd					(context.getDeviceInterface())
1167 	, m_swapchainImages		(swapchainImages)
1168 	, m_renderSize			(renderSize)
1169 	, m_renderPass			(createRenderPass(m_vkd, context.getDevice(), framebufferFormat))
1170 	, m_pipelineLayout		(createPipelineLayout(m_vkd, context.getDevice()))
1171 	, m_pipeline			(createPipeline(m_vkd, context.getDevice(), *m_renderPass, *m_pipelineLayout, binaryRegistry, renderSize))
1172 	, m_vertexBuffer		(makeBuffer(context,
1173 									PROTECTION_DISABLED,
1174 									context.getQueueFamilyIndex(),
1175 									(deUint32)(sizeof(float)*4*3),
1176 									vk::VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
1177 									vk::MemoryRequirement::HostVisible))
1178 {
1179 	m_attachmentViews.resize(swapchainImages.size());
1180 	m_framebuffers.resize(swapchainImages.size());
1181 
1182 	for (size_t imageNdx = 0; imageNdx < swapchainImages.size(); ++imageNdx)
1183 	{
1184 		m_attachmentViews[imageNdx]	= ImageViewSp(new vk::Unique<vk::VkImageView>(createImageView(context, swapchainImages[imageNdx], framebufferFormat)));
1185 		m_framebuffers[imageNdx]	= FramebufferSp(new vk::Unique<vk::VkFramebuffer>(createFramebuffer(context,
1186 																										renderSize.x(),
1187 																										renderSize.y(),
1188 																										*m_renderPass,
1189 																										**m_attachmentViews[imageNdx])));
1190 	}
1191 
1192 	// Upload vertex data
1193 	{
1194 		const tcu::Vec4				vertices[]	=
1195 		{
1196 			tcu::Vec4(-0.5f, -0.5f, 0.0f, 1.0f),
1197 			tcu::Vec4(+0.5f, -0.5f, 0.0f, 1.0f),
1198 			tcu::Vec4( 0.0f, +0.5f, 0.0f, 1.0f)
1199 		};
1200 		DE_STATIC_ASSERT(sizeof(vertices) == sizeof(float)*4*3);
1201 
1202 		deMemcpy(m_vertexBuffer->getAllocation().getHostPtr(), &vertices[0], sizeof(vertices));
1203 		flushAlloc(m_vkd, context.getDevice(), m_vertexBuffer->getAllocation());
1204 	}
1205 }
1206 
~TriangleRenderer(void)1207 TriangleRenderer::~TriangleRenderer (void)
1208 {
1209 }
1210 
recordFrame(vk::VkCommandBuffer cmdBuffer,deUint32 imageNdx,deUint32 frameNdx) const1211 void TriangleRenderer::recordFrame (vk::VkCommandBuffer	cmdBuffer,
1212 									deUint32			imageNdx,
1213 									deUint32			frameNdx) const
1214 {
1215 	const vk::VkFramebuffer	curFramebuffer	= **m_framebuffers[imageNdx];
1216 
1217 	beginCommandBuffer(m_vkd, cmdBuffer, 0u);
1218 
1219 	beginRenderPass(m_vkd, cmdBuffer, *m_renderPass, curFramebuffer, vk::makeRect2D(0, 0, m_renderSize.x(), m_renderSize.y()), tcu::Vec4(0.125f, 0.25f, 0.75f, 1.0f));
1220 	m_vkd.cmdBindPipeline(cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
1221 
1222 	{
1223 		const vk::VkDeviceSize bindingOffset = 0;
1224 		m_vkd.cmdBindVertexBuffers(cmdBuffer, 0u, 1u, &m_vertexBuffer->get(), &bindingOffset);
1225 	}
1226 
1227 	m_vkd.cmdPushConstants(cmdBuffer, *m_pipelineLayout, vk::VK_SHADER_STAGE_VERTEX_BIT, 0u, (deUint32)sizeof(deUint32), &frameNdx);
1228 	m_vkd.cmdDraw(cmdBuffer, 3u, 1u, 0u, 0u);
1229 	endRenderPass(m_vkd, cmdBuffer);
1230 
1231 	endCommandBuffer(m_vkd, cmdBuffer);
1232 }
1233 
getPrograms(vk::SourceCollections & dst)1234 void TriangleRenderer::getPrograms (vk::SourceCollections& dst)
1235 {
1236 	dst.glslSources.add("tri-vert") << glu::VertexSource(
1237 		"#version 310 es\n"
1238 		"layout(location = 0) in highp vec4 a_position;\n"
1239 		"layout(push_constant) uniform FrameData\n"
1240 		"{\n"
1241 		"    highp uint frameNdx;\n"
1242 		"} frameData;\n"
1243 		"void main (void)\n"
1244 		"{\n"
1245 		"    highp float angle = float(frameData.frameNdx) / 100.0;\n"
1246 		"    highp float c     = cos(angle);\n"
1247 		"    highp float s     = sin(angle);\n"
1248 		"    highp mat4  t     = mat4( c, -s,  0,  0,\n"
1249 		"                              s,  c,  0,  0,\n"
1250 		"                              0,  0,  1,  0,\n"
1251 		"                              0,  0,  0,  1);\n"
1252 		"    gl_Position = t * a_position;\n"
1253 		"}\n");
1254 	dst.glslSources.add("tri-frag") << glu::FragmentSource(
1255 		"#version 310 es\n"
1256 		"layout(location = 0) out lowp vec4 o_color;\n"
1257 		"void main (void) { o_color = vec4(1.0, 0.0, 1.0, 1.0); }\n");
1258 }
1259 
1260 typedef de::SharedPtr<vk::Unique<vk::VkCommandBuffer> >	CommandBufferSp;
1261 typedef de::SharedPtr<vk::Unique<vk::VkFence> >			FenceSp;
1262 typedef de::SharedPtr<vk::Unique<vk::VkSemaphore> >		SemaphoreSp;
1263 
createFences(const vk::DeviceInterface & vkd,const vk::VkDevice device,size_t numFences)1264 std::vector<FenceSp> createFences (const vk::DeviceInterface&	vkd,
1265 								   const vk::VkDevice			device,
1266 								   size_t						numFences)
1267 {
1268 	std::vector<FenceSp> fences(numFences);
1269 
1270 	for (size_t ndx = 0; ndx < numFences; ++ndx)
1271 		fences[ndx] = FenceSp(new vk::Unique<vk::VkFence>(createFence(vkd, device)));
1272 
1273 	return fences;
1274 }
1275 
createSemaphores(const vk::DeviceInterface & vkd,const vk::VkDevice device,size_t numSemaphores)1276 std::vector<SemaphoreSp> createSemaphores (const vk::DeviceInterface&	vkd,
1277 										   const vk::VkDevice			device,
1278 										   size_t						numSemaphores)
1279 {
1280 	std::vector<SemaphoreSp> semaphores(numSemaphores);
1281 
1282 	for (size_t ndx = 0; ndx < numSemaphores; ++ndx)
1283 		semaphores[ndx] = SemaphoreSp(new vk::Unique<vk::VkSemaphore>(createSemaphore(vkd, device)));
1284 
1285 	return semaphores;
1286 }
1287 
allocateCommandBuffers(const vk::DeviceInterface & vkd,const vk::VkDevice device,const vk::VkCommandPool commandPool,const vk::VkCommandBufferLevel level,const size_t numCommandBuffers)1288 std::vector<CommandBufferSp> allocateCommandBuffers (const vk::DeviceInterface&		vkd,
1289 													 const vk::VkDevice				device,
1290 													 const vk::VkCommandPool		commandPool,
1291 													 const vk::VkCommandBufferLevel	level,
1292 													 const size_t					numCommandBuffers)
1293 {
1294 	std::vector<CommandBufferSp>			buffers		(numCommandBuffers);
1295 
1296 	for (size_t ndx = 0; ndx < numCommandBuffers; ++ndx)
1297 		buffers[ndx] = CommandBufferSp(new vk::Unique<vk::VkCommandBuffer>(allocateCommandBuffer(vkd, device, commandPool, level)));
1298 
1299 	return buffers;
1300 }
1301 
basicRenderTest(Context & baseCtx,vk::wsi::Type wsiType)1302 tcu::TestStatus basicRenderTest (Context& baseCtx, vk::wsi::Type wsiType)
1303 {
1304 	std::vector<vk::VkExtensionProperties>	supportedExtensions			(enumerateInstanceExtensionProperties(baseCtx.getPlatformInterface(), DE_NULL));
1305 	std::vector<std::string>				instExts					= getRequiredWsiExtensions(supportedExtensions, wsiType);
1306 	std::vector<std::string>				devExts;
1307 	devExts.push_back("VK_KHR_swapchain");
1308 
1309 	const tcu::UVec2						desiredSize					(256, 256);
1310 	const NativeObjects						native						(baseCtx,  supportedExtensions, wsiType, tcu::just(desiredSize));
1311 	ProtectedContext						context						(baseCtx, wsiType, *native.display, *native.window, instExts, devExts);
1312 	vk::VkSurfaceKHR						surface						= context.getSurface();
1313 	const vk::DeviceInterface&				vkd							= context.getDeviceInterface();
1314 	const vk::VkDevice						device						= context.getDevice();
1315 	const vk::VkSwapchainCreateInfoKHR		swapchainInfo				= getBasicSwapchainParameters(wsiType,
1316 																								  context.getInstanceDriver(),
1317 																								  context.getPhysicalDevice(),
1318 																								  surface,
1319 																								  desiredSize,
1320 																								  2);
1321 	const vk::Unique<vk::VkSwapchainKHR>	swapchain					(createSwapchainKHR(vkd, device, &swapchainInfo));
1322 	const std::vector<vk::VkImage>			swapchainImages				= vk::wsi::getSwapchainImages(vkd, device, *swapchain);
1323 
1324 	const TriangleRenderer					renderer					(context,
1325 																		 context.getBinaryCollection(),
1326 																		 swapchainImages,
1327 																		 swapchainInfo.imageFormat,
1328 																		 tcu::UVec2(swapchainInfo.imageExtent.width, swapchainInfo.imageExtent.height));
1329 
1330 	const vk::Unique<vk::VkCommandPool>		commandPool					(makeCommandPool(vkd, device, PROTECTION_ENABLED,
1331 																					 context.getQueueFamilyIndex()));
1332 
1333 	const size_t							maxQueuedFrames				= swapchainImages.size()*2;
1334 
1335 	// We need to keep hold of fences from vkAcquireNextImageKHR to actually
1336 	// limit number of frames we allow to be queued.
1337 	const std::vector<FenceSp>				imageReadyFences			(createFences(vkd, device, maxQueuedFrames));
1338 
1339 	// We need maxQueuedFrames+1 for imageReadySemaphores pool as we need to pass
1340 	// the semaphore in same time as the fence we use to meter rendering.
1341 	const std::vector<SemaphoreSp>			imageReadySemaphores		(createSemaphores(vkd, device, maxQueuedFrames+1));
1342 
1343 	// For rest we simply need maxQueuedFrames as we will wait for image
1344 	// from frameNdx-maxQueuedFrames to become available to us, guaranteeing that
1345 	// previous uses must have completed.
1346 	const std::vector<SemaphoreSp>			renderingCompleteSemaphores	(createSemaphores(vkd, device, maxQueuedFrames));
1347 	const std::vector<CommandBufferSp>		commandBuffers				(allocateCommandBuffers(vkd,
1348 																								device,
1349 																								*commandPool,
1350 																								vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY,
1351 																								maxQueuedFrames));
1352 
1353 	if (isExtensionStructSupported(supportedExtensions, vk::RequiredExtension("VK_KHR_surface_protected_capabilities")))
1354 	{
1355 		// Check if swapchain can be created for protected surface
1356 		const vk::InstanceInterface&			vki			= context.getInstanceDriver();
1357 		vk::VkSurfaceCapabilities2KHR			extCapabilities;
1358 		vk::VkSurfaceProtectedCapabilitiesKHR		extProtectedCapabilities;
1359 		const vk::VkPhysicalDeviceSurfaceInfo2KHR	surfaceInfo =
1360 		{
1361 			vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SURFACE_INFO_2_KHR,
1362 			DE_NULL,
1363 			surface
1364 		};
1365 
1366 		extProtectedCapabilities.sType			= vk::VK_STRUCTURE_TYPE_SURFACE_PROTECTED_CAPABILITIES_KHR;
1367 		extProtectedCapabilities.pNext			= DE_NULL;
1368 		extProtectedCapabilities.supportsProtected	= DE_FALSE;
1369 
1370 		extCapabilities.sType				= vk::VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR;
1371 		extCapabilities.pNext				= &extProtectedCapabilities;
1372 
1373 		VK_CHECK(vki.getPhysicalDeviceSurfaceCapabilities2KHR(context.getPhysicalDevice(), &surfaceInfo, &extCapabilities));
1374 
1375 		if (extProtectedCapabilities.supportsProtected == DE_FALSE)
1376 			TCU_THROW(NotSupportedError, "Swapchain creation for Protected VkSurface is not Supported.");
1377 	}
1378 
1379 	try
1380 	{
1381 		const deUint32	numFramesToRender	= 60*10;
1382 
1383 		for (deUint32 frameNdx = 0; frameNdx < numFramesToRender; ++frameNdx)
1384 		{
1385 			const vk::VkFence		imageReadyFence		= **imageReadyFences[frameNdx%imageReadyFences.size()];
1386 			const vk::VkSemaphore	imageReadySemaphore	= **imageReadySemaphores[frameNdx%imageReadySemaphores.size()];
1387 			deUint32				imageNdx			= ~0u;
1388 
1389 			if (frameNdx >= maxQueuedFrames)
1390 				VK_CHECK(vkd.waitForFences(device, 1u, &imageReadyFence, VK_TRUE, std::numeric_limits<deUint64>::max()));
1391 
1392 			VK_CHECK(vkd.resetFences(device, 1, &imageReadyFence));
1393 
1394 			{
1395 				const vk::VkResult	acquireResult	= vkd.acquireNextImageKHR(device,
1396 																			  *swapchain,
1397 																			  std::numeric_limits<deUint64>::max(),
1398 																			  imageReadySemaphore,
1399 																			  0,
1400 																			  &imageNdx);
1401 
1402 				if (acquireResult == vk::VK_SUBOPTIMAL_KHR)
1403 					context.getTestContext().getLog() << tcu::TestLog::Message << "Got " << acquireResult << " at frame " << frameNdx << tcu::TestLog::EndMessage;
1404 				else
1405 					VK_CHECK(acquireResult);
1406 			}
1407 
1408 			TCU_CHECK((size_t)imageNdx < swapchainImages.size());
1409 
1410 			{
1411 				const vk::VkSemaphore			renderingCompleteSemaphore	= **renderingCompleteSemaphores[frameNdx%renderingCompleteSemaphores.size()];
1412 				const vk::VkCommandBuffer		commandBuffer				= **commandBuffers[frameNdx%commandBuffers.size()];
1413 				const vk::VkPipelineStageFlags	waitDstStage				= vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
1414 				vk::VkSubmitInfo				submitInfo					=
1415 				{
1416 					vk::VK_STRUCTURE_TYPE_SUBMIT_INFO,
1417 					DE_NULL,
1418 					1u,
1419 					&imageReadySemaphore,
1420 					&waitDstStage,
1421 					1u,
1422 					&commandBuffer,
1423 					1u,
1424 					&renderingCompleteSemaphore
1425 				};
1426 
1427 				const vk::VkProtectedSubmitInfo		protectedInfo   =
1428 				{
1429 					vk::VK_STRUCTURE_TYPE_PROTECTED_SUBMIT_INFO,		// sType
1430 					DE_NULL,											// pNext
1431 					VK_TRUE,											// protectedSubmit
1432 				};
1433 				submitInfo.pNext = &protectedInfo;
1434 
1435 				const vk::VkPresentInfoKHR		presentInfo					=
1436 				{
1437 					vk::VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
1438 					DE_NULL,
1439 					1u,
1440 					&renderingCompleteSemaphore,
1441 					1u,
1442 					&*swapchain,
1443 					&imageNdx,
1444 					(vk::VkResult*)DE_NULL
1445 				};
1446 
1447 				renderer.recordFrame(commandBuffer, imageNdx, frameNdx);
1448 				VK_CHECK(vkd.queueSubmit(context.getQueue(), 1u, &submitInfo, imageReadyFence));
1449 				VK_CHECK_WSI(vkd.queuePresentKHR(context.getQueue(), &presentInfo));
1450 			}
1451 		}
1452 
1453 		VK_CHECK(vkd.deviceWaitIdle(device));
1454 	}
1455 	catch (...)
1456 	{
1457 		// Make sure device is idle before destroying resources
1458 		vkd.deviceWaitIdle(device);
1459 		throw;
1460 	}
1461 
1462 	return tcu::TestStatus::pass("Rendering tests succeeded");
1463 }
1464 
getBasicRenderPrograms(vk::SourceCollections & dst,vk::wsi::Type)1465 void getBasicRenderPrograms (vk::SourceCollections& dst, vk::wsi::Type)
1466 {
1467 	TriangleRenderer::getPrograms(dst);
1468 }
1469 
checkSupport(Context & context,vk::wsi::Type)1470 void checkSupport (Context& context, vk::wsi::Type)
1471 {
1472 	checkProtectedQueueSupport(context);
1473 }
1474 
populateRenderGroup(tcu::TestCaseGroup * testGroup,vk::wsi::Type wsiType)1475 void populateRenderGroup (tcu::TestCaseGroup* testGroup, vk::wsi::Type wsiType)
1476 {
1477 	addFunctionCaseWithPrograms(testGroup, "basic", checkSupport, getBasicRenderPrograms, basicRenderTest, wsiType);
1478 }
1479 
createSwapchainTests(tcu::TestCaseGroup * testGroup,vk::wsi::Type wsiType)1480 void createSwapchainTests (tcu::TestCaseGroup* testGroup, vk::wsi::Type wsiType)
1481 {
1482 	// Create VkSwapchain with various parameters
1483 	addTestGroup(testGroup, "create", populateSwapchainGroup,		GroupParameters(wsiType, createSwapchainTest));
1484 	// Rendering Tests
1485 	addTestGroup(testGroup, "render", populateRenderGroup,		wsiType);
1486 }
1487 
createTypeSpecificTests(tcu::TestCaseGroup * testGroup,vk::wsi::Type wsiType)1488 void createTypeSpecificTests (tcu::TestCaseGroup* testGroup, vk::wsi::Type wsiType)
1489 {
1490 	// VkSwapchain Tests
1491 	addTestGroup(testGroup, "swapchain", createSwapchainTests, wsiType);
1492 }
1493 
1494 } // anonymous
1495 
createSwapchainTests(tcu::TestContext & testCtx)1496 tcu::TestCaseGroup* createSwapchainTests (tcu::TestContext& testCtx)
1497 {
1498 	// WSI Tests
1499 	de::MovePtr<tcu::TestCaseGroup> wsiTestGroup (new tcu::TestCaseGroup(testCtx, "wsi"));
1500 
1501 	for (int typeNdx = 0; typeNdx < vk::wsi::TYPE_LAST; ++typeNdx)
1502 	{
1503 		const vk::wsi::Type	wsiType		= (vk::wsi::Type)typeNdx;
1504 
1505 		addTestGroup(&*wsiTestGroup, getName(wsiType), createTypeSpecificTests, wsiType);
1506 	}
1507 
1508 	return wsiTestGroup.release();
1509 }
1510 
1511 } // wsi
1512 } // vkt
1513