• 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 "vkWsiPlatform.hpp"
41 #include "vkWsiUtil.hpp"
42 #include "vkAllocationCallbackUtil.hpp"
43 
44 #include "tcuTestLog.hpp"
45 #include "tcuFormatUtil.hpp"
46 #include "tcuPlatform.hpp"
47 #include "tcuResultCollector.hpp"
48 
49 #include "deUniquePtr.hpp"
50 #include "deStringUtil.hpp"
51 #include "deArrayUtil.hpp"
52 #include "deSharedPtr.hpp"
53 
54 #include <limits>
55 
56 #include "vktProtectedMemContext.hpp"
57 #include "vktProtectedMemUtils.hpp"
58 
59 namespace vkt
60 {
61 namespace ProtectedMem
62 {
63 
64 namespace
65 {
66 
67 typedef std::vector<vk::VkExtensionProperties> Extensions;
68 
checkAllSupported(const Extensions & supportedExtensions,const std::vector<std::string> & requiredExtensions)69 void checkAllSupported (const Extensions& supportedExtensions, const std::vector<std::string>& requiredExtensions)
70 {
71 	for (std::vector<std::string>::const_iterator requiredExtName = requiredExtensions.begin();
72 		 requiredExtName != requiredExtensions.end();
73 		 ++requiredExtName)
74 	{
75 		if (!isExtensionSupported(supportedExtensions, vk::RequiredExtension(*requiredExtName)))
76 			TCU_THROW(NotSupportedError, (*requiredExtName + " is not supported").c_str());
77 	}
78 }
79 
getRequiredWsiExtensions(const Extensions & supportedExtensions,vk::wsi::Type wsiType)80 std::vector<std::string> getRequiredWsiExtensions (const Extensions&	supportedExtensions,
81 												   vk::wsi::Type		wsiType)
82 {
83 	std::vector<std::string>	extensions;
84 
85 	extensions.push_back("VK_KHR_surface");
86 	extensions.push_back(getExtensionName(wsiType));
87 
88 	// VK_EXT_swapchain_colorspace adds new surface formats. Driver can enumerate
89 	// the formats regardless of whether VK_EXT_swapchain_colorspace was enabled,
90 	// but using them without enabling the extension is not allowed. Thus we have
91 	// two options:
92 	//
93 	// 1) Filter out non-core formats to stay within valid usage.
94 	//
95 	// 2) Enable VK_EXT_swapchain colorspace if advertised by the driver.
96 	//
97 	// We opt for (2) as it provides basic coverage for the extension as a bonus.
98 	if (isExtensionSupported(supportedExtensions, vk::RequiredExtension("VK_EXT_swapchain_colorspace")))
99 		extensions.push_back("VK_EXT_swapchain_colorspace");
100 
101 	checkAllSupported(supportedExtensions, extensions);
102 
103 	return extensions;
104 }
105 
createDisplay(const vk::Platform & platform,const Extensions & supportedExtensions,vk::wsi::Type wsiType)106 de::MovePtr<vk::wsi::Display> createDisplay (const vk::Platform&	platform,
107 											 const Extensions&		supportedExtensions,
108 											 vk::wsi::Type			wsiType)
109 {
110 	try
111 	{
112 		return de::MovePtr<vk::wsi::Display>(platform.createWsiDisplay(wsiType));
113 	}
114 	catch (const tcu::NotSupportedError& e)
115 	{
116 		if (isExtensionSupported(supportedExtensions, vk::RequiredExtension(getExtensionName(wsiType))))
117 		{
118 			// If VK_KHR_{platform}_surface was supported, vk::Platform implementation
119 			// must support creating native display & window for that WSI type.
120 			throw tcu::TestError(e.getMessage());
121 		}
122 		else
123 			throw;
124 	}
125 }
126 
createWindow(const vk::wsi::Display & display,const tcu::Maybe<tcu::UVec2> & initialSize)127 de::MovePtr<vk::wsi::Window> createWindow (const vk::wsi::Display& display, const tcu::Maybe<tcu::UVec2>& initialSize)
128 {
129 	try
130 	{
131 		return de::MovePtr<vk::wsi::Window>(display.createWindow(initialSize));
132 	}
133 	catch (const tcu::NotSupportedError& e)
134 	{
135 		// See createDisplay - assuming that wsi::Display was supported platform port
136 		// should also support creating a window.
137 		throw tcu::TestError(e.getMessage());
138 	}
139 }
140 
141 struct NativeObjects
142 {
143 	const de::UniquePtr<vk::wsi::Display>	display;
144 	const de::UniquePtr<vk::wsi::Window>	window;
145 
NativeObjectsvkt::ProtectedMem::__anonf605912f0111::NativeObjects146 	NativeObjects (Context&							context,
147 				   const Extensions&				supportedExtensions,
148 				   vk::wsi::Type					wsiType,
149 				   const tcu::Maybe<tcu::UVec2>&	initialWindowSize = tcu::nothing<tcu::UVec2>())
150 		: display				(createDisplay(context.getTestContext().getPlatform().getVulkanPlatform(), supportedExtensions, wsiType))
151 		, window				(createWindow(*display, initialWindowSize))
152 	{}
153 };
154 
155 enum TestDimension
156 {
157 	TEST_DIMENSION_MIN_IMAGE_COUNT = 0,	//!< Test all supported image counts
158 	TEST_DIMENSION_IMAGE_FORMAT,		//!< Test all supported formats
159 	TEST_DIMENSION_IMAGE_EXTENT,		//!< Test various (supported) extents
160 	TEST_DIMENSION_IMAGE_ARRAY_LAYERS,
161 	TEST_DIMENSION_IMAGE_USAGE,
162 	TEST_DIMENSION_IMAGE_SHARING_MODE,
163 	TEST_DIMENSION_PRE_TRANSFORM,
164 	TEST_DIMENSION_COMPOSITE_ALPHA,
165 	TEST_DIMENSION_PRESENT_MODE,
166 	TEST_DIMENSION_CLIPPED,
167 
168 	TEST_DIMENSION_LAST
169 };
170 
getTestDimensionName(TestDimension dimension)171 const char* getTestDimensionName (TestDimension dimension)
172 {
173 	static const char* const s_names[] =
174 	{
175 		"min_image_count",
176 		"image_format",
177 		"image_extent",
178 		"image_array_layers",
179 		"image_usage",
180 		"image_sharing_mode",
181 		"pre_transform",
182 		"composite_alpha",
183 		"present_mode",
184 		"clipped"
185 	};
186 	return de::getSizedArrayElement<TEST_DIMENSION_LAST>(s_names, dimension);
187 }
188 
189 struct TestParameters
190 {
191 	vk::wsi::Type	wsiType;
192 	TestDimension	dimension;
193 
TestParametersvkt::ProtectedMem::__anonf605912f0111::TestParameters194 	TestParameters (vk::wsi::Type wsiType_, TestDimension dimension_)
195 		: wsiType	(wsiType_)
196 		, dimension	(dimension_)
197 	{}
198 
TestParametersvkt::ProtectedMem::__anonf605912f0111::TestParameters199 	TestParameters (void)
200 		: wsiType	(vk::wsi::TYPE_LAST)
201 		, dimension	(TEST_DIMENSION_LAST)
202 	{}
203 };
204 
generateSwapchainParameterCases(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)205 std::vector<vk::VkSwapchainCreateInfoKHR> generateSwapchainParameterCases (vk::wsi::Type								wsiType,
206 																		   TestDimension								dimension,
207 																		   const ProtectedContext&						context,
208 																		   const vk::VkSurfaceCapabilitiesKHR&			capabilities,
209 																		   const std::vector<vk::VkSurfaceFormatKHR>&	formats,
210 																		   const std::vector<vk::VkPresentModeKHR>&		presentModes)
211 {
212 	std::vector<vk::VkSwapchainCreateInfoKHR>	cases;
213 	const vk::wsi::PlatformProperties&			platformProperties	= getPlatformProperties(wsiType);
214 	const vk::VkSurfaceTransformFlagBitsKHR		defaultTransform	= (capabilities.supportedTransforms & vk::VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR)
215 																		? vk::VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR : capabilities.currentTransform;
216 	const vk::VkSwapchainCreateInfoKHR			baseParameters		=
217 	{
218 		vk::VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
219 		DE_NULL,
220 		vk::VK_SWAPCHAIN_CREATE_PROTECTED_BIT_KHR,
221 		(vk::VkSurfaceKHR)0,
222 		capabilities.minImageCount,
223 		formats[0].format,
224 		formats[0].colorSpace,
225 		(platformProperties.swapchainExtent == vk::wsi::PlatformProperties::SWAPCHAIN_EXTENT_SETS_WINDOW_SIZE
226 			? capabilities.minImageExtent : capabilities.currentExtent),
227 		1u,									// imageArrayLayers
228 		vk::VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
229 		vk::VK_SHARING_MODE_EXCLUSIVE,
230 		0u,
231 		(const deUint32*)DE_NULL,
232 		defaultTransform,
233 		vk::VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
234 		vk::VK_PRESENT_MODE_FIFO_KHR,
235 		VK_FALSE,							// clipped
236 		(vk::VkSwapchainKHR)0				// oldSwapchain
237 	};
238 
239 	switch (dimension)
240 	{
241 		case TEST_DIMENSION_MIN_IMAGE_COUNT:
242 		{
243 			// Estimate how much memory each swapchain image consumes. This isn't perfect, since
244 			// swapchain images may have additional constraints that equivalent non-swapchain
245 			// images don't have. But it's the best we can do.
246 			const vk::DeviceInterface&				vkd					= context.getDeviceInterface();
247 			vk::VkDevice							device				= context.getDevice();
248 			vk::VkMemoryRequirements				memoryRequirements;
249 			{
250 				const vk::VkImageCreateInfo			imageInfo			=
251 				{
252 					vk::VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
253 					DE_NULL,
254 					vk::VK_IMAGE_CREATE_PROTECTED_BIT,
255 					vk::VK_IMAGE_TYPE_2D,
256 					baseParameters.imageFormat,
257 					{
258 						baseParameters.imageExtent.width,
259 						baseParameters.imageExtent.height,
260 						1,
261 					},
262 					1,	// mipLevels
263 					baseParameters.imageArrayLayers,
264 					vk::VK_SAMPLE_COUNT_1_BIT,
265 					vk::VK_IMAGE_TILING_OPTIMAL,
266 					baseParameters.imageUsage,
267 					baseParameters.imageSharingMode,
268 					baseParameters.queueFamilyIndexCount,
269 					baseParameters.pQueueFamilyIndices,
270 					vk::VK_IMAGE_LAYOUT_UNDEFINED
271 				};
272 				vk::Move<vk::VkImage>				image				= vk::createImage(vkd, device, &imageInfo);
273 
274 				memoryRequirements	= vk::getImageMemoryRequirements(vkd, device, *image);
275 			}
276 
277 			// Determine the maximum memory heap space available for protected images
278 			vk::VkPhysicalDeviceMemoryProperties	memoryProperties	= vk::getPhysicalDeviceMemoryProperties(context.getInstanceDriver(), context.getPhysicalDevice());
279 			vk::VkDeviceSize						protectedHeapSize	= 0;
280 			deUint32								protectedHeapMask	= 0;
281 			for (deUint32 memType = 0; memType < memoryProperties.memoryTypeCount; memType++)
282 			{
283 				deUint32 heapIndex	= memoryProperties.memoryTypes[memType].heapIndex;
284 				if ((memoryRequirements.memoryTypeBits & (1u << memType)) != 0 &&
285 					(memoryProperties.memoryTypes[memType].propertyFlags & vk::VK_MEMORY_PROPERTY_PROTECTED_BIT) != 0 &&
286 					(protectedHeapMask & (1u << heapIndex)) == 0)
287 				{
288 					protectedHeapSize = de::max(protectedHeapSize, memoryProperties.memoryHeaps[heapIndex].size);
289 					protectedHeapMask |= 1u << heapIndex;
290 				}
291 			}
292 
293 			// If the implementation doesn't have a max image count, min+16 means we won't clamp.
294 			// Limit it to how many protected images we estimate can be allocated, with one image
295 			// worth of slack for alignment, swapchain-specific constraints, etc.
296 			const deUint32	maxImageCount		= de::min((capabilities.maxImageCount > 0) ? capabilities.maxImageCount : capabilities.minImageCount + 16u,
297 														  deUint32(protectedHeapSize / memoryRequirements.size) - 1);
298 			const deUint32	maxImageCountToTest	= de::clamp(16u, capabilities.minImageCount, maxImageCount);
299 			for (deUint32 imageCount = capabilities.minImageCount; imageCount <= maxImageCountToTest; ++imageCount)
300 			{
301 				cases.push_back(baseParameters);
302 				cases.back().minImageCount = imageCount;
303 			}
304 
305 			break;
306 		}
307 
308 		case TEST_DIMENSION_IMAGE_FORMAT:
309 		{
310 			for (std::vector<vk::VkSurfaceFormatKHR>::const_iterator curFmt = formats.begin(); curFmt != formats.end(); ++curFmt)
311 			{
312 				cases.push_back(baseParameters);
313 				cases.back().imageFormat		= curFmt->format;
314 				cases.back().imageColorSpace	= curFmt->colorSpace;
315 			}
316 
317 			break;
318 		}
319 
320 		case TEST_DIMENSION_IMAGE_EXTENT:
321 		{
322 			static const vk::VkExtent2D	s_testSizes[]	=
323 			{
324 				{ 1, 1 },
325 				{ 16, 32 },
326 				{ 32, 16 },
327 				{ 632, 231 },
328 				{ 117, 998 },
329 			};
330 
331 			if (platformProperties.swapchainExtent == vk::wsi::PlatformProperties::SWAPCHAIN_EXTENT_SETS_WINDOW_SIZE ||
332 				platformProperties.swapchainExtent == vk::wsi::PlatformProperties::SWAPCHAIN_EXTENT_SCALED_TO_WINDOW_SIZE)
333 			{
334 				for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(s_testSizes); ++ndx)
335 				{
336 					cases.push_back(baseParameters);
337 					cases.back().imageExtent.width	= de::clamp(s_testSizes[ndx].width, capabilities.minImageExtent.width, capabilities.maxImageExtent.width);
338 					cases.back().imageExtent.height	= de::clamp(s_testSizes[ndx].height, capabilities.minImageExtent.height, capabilities.maxImageExtent.height);
339 				}
340 			}
341 
342 			if (platformProperties.swapchainExtent != vk::wsi::PlatformProperties::SWAPCHAIN_EXTENT_SETS_WINDOW_SIZE)
343 			{
344 				cases.push_back(baseParameters);
345 				cases.back().imageExtent = capabilities.currentExtent;
346 			}
347 
348 			if (platformProperties.swapchainExtent != vk::wsi::PlatformProperties::SWAPCHAIN_EXTENT_MUST_MATCH_WINDOW_SIZE)
349 			{
350 				cases.push_back(baseParameters);
351 				cases.back().imageExtent = capabilities.minImageExtent;
352 
353 				cases.push_back(baseParameters);
354 				cases.back().imageExtent = capabilities.maxImageExtent;
355 			}
356 
357 			break;
358 		}
359 
360 		case TEST_DIMENSION_IMAGE_ARRAY_LAYERS:
361 		{
362 			const deUint32	maxLayers	= de::min(capabilities.maxImageArrayLayers, 16u);
363 
364 			for (deUint32 numLayers = 1; numLayers <= maxLayers; ++numLayers)
365 			{
366 				cases.push_back(baseParameters);
367 				cases.back().imageArrayLayers = numLayers;
368 			}
369 
370 			break;
371 		}
372 
373 		case TEST_DIMENSION_IMAGE_USAGE:
374 		{
375 			for (deUint32 flags = 1u; flags <= capabilities.supportedUsageFlags; ++flags)
376 			{
377 				if ((flags & ~capabilities.supportedUsageFlags) == 0)
378 				{
379 					cases.push_back(baseParameters);
380 					cases.back().imageUsage = flags;
381 				}
382 			}
383 
384 			break;
385 		}
386 
387 		case TEST_DIMENSION_IMAGE_SHARING_MODE:
388 		{
389 			cases.push_back(baseParameters);
390 			cases.back().imageSharingMode = vk::VK_SHARING_MODE_EXCLUSIVE;
391 
392 			cases.push_back(baseParameters);
393 			cases.back().imageSharingMode = vk::VK_SHARING_MODE_CONCURRENT;
394 
395 			break;
396 		}
397 
398 		case TEST_DIMENSION_PRE_TRANSFORM:
399 		{
400 			for (deUint32 transform = 1u;
401 				 transform <= capabilities.supportedTransforms;
402 				 transform = transform<<1u)
403 			{
404 				if ((transform & capabilities.supportedTransforms) != 0)
405 				{
406 					cases.push_back(baseParameters);
407 					cases.back().preTransform = (vk::VkSurfaceTransformFlagBitsKHR)transform;
408 				}
409 			}
410 
411 			break;
412 		}
413 
414 		case TEST_DIMENSION_COMPOSITE_ALPHA:
415 		{
416 			for (deUint32 alphaMode = 1u;
417 				 alphaMode <= capabilities.supportedCompositeAlpha;
418 				 alphaMode = alphaMode<<1u)
419 			{
420 				if ((alphaMode & capabilities.supportedCompositeAlpha) != 0)
421 				{
422 					cases.push_back(baseParameters);
423 					cases.back().compositeAlpha = (vk::VkCompositeAlphaFlagBitsKHR)alphaMode;
424 				}
425 			}
426 
427 			break;
428 		}
429 
430 		case TEST_DIMENSION_PRESENT_MODE:
431 		{
432 			for (std::vector<vk::VkPresentModeKHR>::const_iterator curMode = presentModes.begin(); curMode != presentModes.end(); ++curMode)
433 			{
434 				cases.push_back(baseParameters);
435 				cases.back().presentMode = *curMode;
436 			}
437 
438 			break;
439 		}
440 
441 		case TEST_DIMENSION_CLIPPED:
442 		{
443 			cases.push_back(baseParameters);
444 			cases.back().clipped = VK_FALSE;
445 
446 			cases.push_back(baseParameters);
447 			cases.back().clipped = VK_TRUE;
448 
449 			break;
450 		}
451 
452 		default:
453 			DE_FATAL("Impossible");
454 	}
455 
456 	DE_ASSERT(!cases.empty());
457 	return cases;
458 }
459 
generateSwapchainParameterCases(vk::wsi::Type wsiType,TestDimension dimension,const ProtectedContext & context,vk::VkSurfaceKHR surface)460 std::vector<vk::VkSwapchainCreateInfoKHR> generateSwapchainParameterCases (vk::wsi::Type					wsiType,
461 																		   TestDimension					dimension,
462 																		   const ProtectedContext&			context,
463 																		   vk::VkSurfaceKHR					surface)
464 {
465 	const vk::InstanceInterface&				vki				= context.getInstanceDriver();
466 	vk::VkPhysicalDevice						physicalDevice	= context.getPhysicalDevice();
467 	const vk::VkSurfaceCapabilitiesKHR			capabilities	= vk::wsi::getPhysicalDeviceSurfaceCapabilities(vki,
468 																											   physicalDevice,
469 																											   surface);
470 	const std::vector<vk::VkSurfaceFormatKHR>	formats			= vk::wsi::getPhysicalDeviceSurfaceFormats(vki,
471 																										   physicalDevice,
472 																										   surface);
473 	const std::vector<vk::VkPresentModeKHR>		presentModes	= vk::wsi::getPhysicalDeviceSurfacePresentModes(vki,
474 																											    physicalDevice,
475 																											    surface);
476 
477 	return generateSwapchainParameterCases(wsiType, dimension, context, capabilities, formats, presentModes);
478 }
479 
createSwapchainTest(Context & baseCtx,TestParameters params)480 tcu::TestStatus createSwapchainTest (Context& baseCtx, TestParameters params)
481 {
482 	std::vector<vk::VkExtensionProperties>			supportedExtensions (enumerateInstanceExtensionProperties(baseCtx.getPlatformInterface(), DE_NULL));
483 	std::vector<std::string>						instExts	= getRequiredWsiExtensions(supportedExtensions, params.wsiType);
484 	std::vector<std::string>						devExts;
485 	devExts.push_back("VK_KHR_swapchain");
486 
487 	const NativeObjects								native		(baseCtx, supportedExtensions, params.wsiType);
488 	ProtectedContext								context		(baseCtx, params.wsiType, *native.display, *native.window, instExts, devExts);
489 	vk::VkSurfaceKHR								surface		= context.getSurface();
490 	const std::vector<vk::VkSwapchainCreateInfoKHR>	cases		(generateSwapchainParameterCases(params.wsiType,
491 																								 params.dimension,
492 																								 context,
493 																								 surface));
494 	deUint32										queueIdx	= context.getQueueFamilyIndex();
495 	for (size_t caseNdx = 0; caseNdx < cases.size(); ++caseNdx)
496 	{
497 		vk::VkSwapchainCreateInfoKHR	curParams	= cases[caseNdx];
498 
499 		curParams.surface				= surface;
500 		curParams.queueFamilyIndexCount	= 1u;
501 		curParams.pQueueFamilyIndices	= &queueIdx;
502 
503 		context.getTestContext().getLog()
504 			<< tcu::TestLog::Message << "Sub-case " << (caseNdx+1) << " / " << cases.size() << ": " << curParams << tcu::TestLog::EndMessage;
505 
506 		{
507 			const vk::Unique<vk::VkSwapchainKHR>	swapchain	(createSwapchainKHR(context.getDeviceDriver(), context.getDevice(), &curParams));
508 		}
509 	}
510 
511 	return tcu::TestStatus::pass("Creating swapchain succeeded");
512 }
513 
514 struct GroupParameters
515 {
516 	typedef FunctionInstance1<TestParameters>::Function	Function;
517 
518 	vk::wsi::Type	wsiType;
519 	Function		function;
520 
GroupParametersvkt::ProtectedMem::__anonf605912f0111::GroupParameters521 	GroupParameters (vk::wsi::Type wsiType_, Function function_)
522 		: wsiType	(wsiType_)
523 		, function	(function_)
524 	{}
525 
GroupParametersvkt::ProtectedMem::__anonf605912f0111::GroupParameters526 	GroupParameters (void)
527 		: wsiType	(vk::wsi::TYPE_LAST)
528 		, function	((Function)DE_NULL)
529 	{}
530 };
531 
populateSwapchainGroup(tcu::TestCaseGroup * testGroup,GroupParameters params)532 void populateSwapchainGroup (tcu::TestCaseGroup* testGroup, GroupParameters params)
533 {
534 	for (int dimensionNdx = 0; dimensionNdx < TEST_DIMENSION_LAST; ++dimensionNdx)
535 	{
536 		const TestDimension		testDimension	= (TestDimension)dimensionNdx;
537 
538 		addFunctionCase(testGroup, getTestDimensionName(testDimension), "", params.function, TestParameters(params.wsiType, testDimension));
539 	}
540 }
541 
getBasicSwapchainParameters(vk::wsi::Type wsiType,const vk::InstanceInterface & vki,vk::VkPhysicalDevice physicalDevice,vk::VkSurfaceKHR surface,const tcu::UVec2 & desiredSize,deUint32 desiredImageCount)542 vk::VkSwapchainCreateInfoKHR getBasicSwapchainParameters (vk::wsi::Type					wsiType,
543 														  const vk::InstanceInterface&	vki,
544 														  vk::VkPhysicalDevice			physicalDevice,
545 														  vk::VkSurfaceKHR				surface,
546 														  const tcu::UVec2&				desiredSize,
547 														  deUint32						desiredImageCount)
548 {
549 	const vk::VkSurfaceCapabilitiesKHR			capabilities		= vk::wsi::getPhysicalDeviceSurfaceCapabilities(vki,
550 																												    physicalDevice,
551 																												    surface);
552 	const std::vector<vk::VkSurfaceFormatKHR>	formats				= vk::wsi::getPhysicalDeviceSurfaceFormats(vki,
553 																											   physicalDevice,
554 																											   surface);
555 	const vk::wsi::PlatformProperties&			platformProperties	= vk::wsi::getPlatformProperties(wsiType);
556 	const vk::VkSurfaceTransformFlagBitsKHR		transform			= (capabilities.supportedTransforms & vk::VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR)
557 																		? vk::VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR : capabilities.currentTransform;
558 	const vk::VkSwapchainCreateInfoKHR			parameters			=
559 	{
560 		vk::VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
561 		DE_NULL,
562 		vk::VK_SWAPCHAIN_CREATE_PROTECTED_BIT_KHR,
563 		surface,
564 		de::clamp(desiredImageCount, capabilities.minImageCount, capabilities.maxImageCount > 0 ? capabilities.maxImageCount : capabilities.minImageCount + desiredImageCount),
565 		formats[0].format,
566 		formats[0].colorSpace,
567 		(platformProperties.swapchainExtent == vk::wsi::PlatformProperties::SWAPCHAIN_EXTENT_MUST_MATCH_WINDOW_SIZE
568 			? capabilities.currentExtent : vk::makeExtent2D(desiredSize.x(), desiredSize.y())),
569 		1u,									// imageArrayLayers
570 		vk::VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
571 		vk::VK_SHARING_MODE_EXCLUSIVE,
572 		0u,
573 		(const deUint32*)DE_NULL,
574 		transform,
575 		vk::VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
576 		vk::VK_PRESENT_MODE_FIFO_KHR,
577 		VK_FALSE,							// clipped
578 		(vk::VkSwapchainKHR)0				// oldSwapchain
579 	};
580 
581 	return parameters;
582 }
583 
584 typedef de::SharedPtr<vk::Unique<vk::VkImageView> >		ImageViewSp;
585 typedef de::SharedPtr<vk::Unique<vk::VkFramebuffer> >	FramebufferSp;
586 
587 class TriangleRenderer
588 {
589 public:
590 												TriangleRenderer	(ProtectedContext&				context,
591 																	 const vk::BinaryCollection&	binaryRegistry,
592 																	 const std::vector<vk::VkImage>	swapchainImages,
593 																	 const vk::VkFormat				framebufferFormat,
594 																	 const tcu::UVec2&				renderSize);
595 												~TriangleRenderer	(void);
596 
597 	void										recordFrame			(vk::VkCommandBuffer			cmdBuffer,
598 																	 deUint32						imageNdx,
599 																	 deUint32						frameNdx) const;
600 
601 	static void									getPrograms			(vk::SourceCollections&			dst);
602 
603 private:
604 	static vk::Move<vk::VkRenderPass>			createRenderPass	(const vk::DeviceInterface&		vkd,
605 																	 const vk::VkDevice				device,
606 																	 const vk::VkFormat				colorAttachmentFormat);
607 	static vk::Move<vk::VkPipelineLayout>		createPipelineLayout(const vk::DeviceInterface&		vkd,
608 																	 vk::VkDevice					device);
609 	static vk::Move<vk::VkPipeline>				createPipeline		(const vk::DeviceInterface&		vkd,
610 																	 const vk::VkDevice				device,
611 																	 const vk::VkRenderPass			renderPass,
612 																	 const vk::VkPipelineLayout		pipelineLayout,
613 																	 const vk::BinaryCollection&	binaryCollection,
614 																	 const tcu::UVec2&				renderSize);
615 
616 	const vk::DeviceInterface&					m_vkd;
617 
618 	const std::vector<vk::VkImage>				m_swapchainImages;
619 	const tcu::UVec2							m_renderSize;
620 
621 	const vk::Unique<vk::VkRenderPass>			m_renderPass;
622 	const vk::Unique<vk::VkPipelineLayout>		m_pipelineLayout;
623 	const vk::Unique<vk::VkPipeline>			m_pipeline;
624 
625 	const de::UniquePtr<vk::BufferWithMemory>	m_vertexBuffer;
626 
627 	std::vector<ImageViewSp>					m_attachmentViews;
628 	std::vector<FramebufferSp>					m_framebuffers;
629 };
630 
createRenderPass(const vk::DeviceInterface & vkd,const vk::VkDevice device,const vk::VkFormat colorAttachmentFormat)631 vk::Move<vk::VkRenderPass> TriangleRenderer::createRenderPass (const vk::DeviceInterface&	vkd,
632 															   const vk::VkDevice			device,
633 															   const vk::VkFormat			colorAttachmentFormat)
634 {
635 	const vk::VkAttachmentDescription	colorAttDesc		=
636 	{
637 		(vk::VkAttachmentDescriptionFlags)0,
638 		colorAttachmentFormat,
639 		vk::VK_SAMPLE_COUNT_1_BIT,
640 		vk::VK_ATTACHMENT_LOAD_OP_CLEAR,
641 		vk::VK_ATTACHMENT_STORE_OP_STORE,
642 		vk::VK_ATTACHMENT_LOAD_OP_DONT_CARE,
643 		vk::VK_ATTACHMENT_STORE_OP_DONT_CARE,
644 		vk::VK_IMAGE_LAYOUT_UNDEFINED,
645 		vk::VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
646 	};
647 	const vk::VkAttachmentReference		colorAttRef			=
648 	{
649 		0u,
650 		vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
651 	};
652 	const vk::VkSubpassDescription		subpassDesc			=
653 	{
654 		(vk::VkSubpassDescriptionFlags)0u,
655 		vk::VK_PIPELINE_BIND_POINT_GRAPHICS,
656 		0u,							// inputAttachmentCount
657 		DE_NULL,					// pInputAttachments
658 		1u,							// colorAttachmentCount
659 		&colorAttRef,				// pColorAttachments
660 		DE_NULL,					// pResolveAttachments
661 		DE_NULL,					// depthStencilAttachment
662 		0u,							// preserveAttachmentCount
663 		DE_NULL,					// pPreserveAttachments
664 	};
665 	const vk::VkSubpassDependency		dependencies[]		=
666 	{
667 		{
668 			VK_SUBPASS_EXTERNAL,	// srcSubpass
669 			0u,						// dstSubpass
670 			vk::VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
671 			vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
672 			vk::VK_ACCESS_MEMORY_READ_BIT,
673 			(vk::VK_ACCESS_COLOR_ATTACHMENT_READ_BIT|
674 			 vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT),
675 			vk::VK_DEPENDENCY_BY_REGION_BIT
676 		},
677 		{
678 			0u,						// srcSubpass
679 			VK_SUBPASS_EXTERNAL,	// dstSubpass
680 			vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
681 			vk::VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
682 			(vk::VK_ACCESS_COLOR_ATTACHMENT_READ_BIT|
683 			 vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT),
684 			vk::VK_ACCESS_MEMORY_READ_BIT,
685 			vk::VK_DEPENDENCY_BY_REGION_BIT
686 		},
687 	};
688 	const vk::VkRenderPassCreateInfo	renderPassParams	=
689 	{
690 		vk::VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
691 		DE_NULL,
692 		(vk::VkRenderPassCreateFlags)0,
693 		1u,
694 		&colorAttDesc,
695 		1u,
696 		&subpassDesc,
697 		DE_LENGTH_OF_ARRAY(dependencies),
698 		dependencies,
699 	};
700 
701 	return vk::createRenderPass(vkd, device, &renderPassParams);
702 }
703 
createPipelineLayout(const vk::DeviceInterface & vkd,const vk::VkDevice device)704 vk::Move<vk::VkPipelineLayout> TriangleRenderer::createPipelineLayout (const vk::DeviceInterface&	vkd,
705 																	   const vk::VkDevice			device)
706 {
707 	const vk::VkPushConstantRange					pushConstantRange		=
708 	{
709 		vk::VK_SHADER_STAGE_VERTEX_BIT,
710 		0u,											// offset
711 		(deUint32)sizeof(deUint32),					// size
712 	};
713 	const vk::VkPipelineLayoutCreateInfo			pipelineLayoutParams	=
714 	{
715 		vk::VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
716 		DE_NULL,
717 		(vk::VkPipelineLayoutCreateFlags)0,
718 		0u,											// setLayoutCount
719 		DE_NULL,									// pSetLayouts
720 		1u,
721 		&pushConstantRange,
722 	};
723 
724 	return vk::createPipelineLayout(vkd, device, &pipelineLayoutParams);
725 }
726 
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)727 vk::Move<vk::VkPipeline> TriangleRenderer::createPipeline (const vk::DeviceInterface&	vkd,
728 														   const vk::VkDevice			device,
729 														   const vk::VkRenderPass		renderPass,
730 														   const vk::VkPipelineLayout	pipelineLayout,
731 														   const vk::BinaryCollection&	binaryCollection,
732 														   const tcu::UVec2&			renderSize)
733 {
734 	// \note VkShaderModules are fully consumed by vkCreateGraphicsPipelines()
735 	//		 and can be deleted immediately following that call.
736 	const vk::Unique<vk::VkShaderModule>				vertShaderModule		(createShaderModule(vkd, device, binaryCollection.get("tri-vert"), 0));
737 	const vk::Unique<vk::VkShaderModule>				fragShaderModule		(createShaderModule(vkd, device, binaryCollection.get("tri-frag"), 0));
738 
739 	const vk::VkPipelineShaderStageCreateInfo			shaderStageParams[]		=
740 	{
741 		{
742 			vk::VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
743 			DE_NULL,
744 			(vk::VkPipelineShaderStageCreateFlags)0,
745 			vk::VK_SHADER_STAGE_VERTEX_BIT,
746 			*vertShaderModule,
747 			"main",
748 			DE_NULL
749 		},
750 		{
751 			vk::VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
752 			DE_NULL,
753 			(vk::VkPipelineShaderStageCreateFlags)0,
754 			vk::VK_SHADER_STAGE_FRAGMENT_BIT,
755 			*fragShaderModule,
756 			"main",
757 			DE_NULL
758 		}
759 	};
760 	const vk::VkPipelineDepthStencilStateCreateInfo		depthStencilParams		=
761 	{
762 		vk::VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,
763 		DE_NULL,
764 		(vk::VkPipelineDepthStencilStateCreateFlags)0,
765 		DE_FALSE,									// depthTestEnable
766 		DE_FALSE,									// depthWriteEnable
767 		vk::VK_COMPARE_OP_ALWAYS,					// depthCompareOp
768 		DE_FALSE,									// depthBoundsTestEnable
769 		DE_FALSE,									// stencilTestEnable
770 		{
771 			vk::VK_STENCIL_OP_KEEP,						// failOp
772 			vk::VK_STENCIL_OP_KEEP,						// passOp
773 			vk::VK_STENCIL_OP_KEEP,						// depthFailOp
774 			vk::VK_COMPARE_OP_ALWAYS,					// compareOp
775 			0u,											// compareMask
776 			0u,											// writeMask
777 			0u,											// reference
778 		},											// front
779 		{
780 			vk::VK_STENCIL_OP_KEEP,						// failOp
781 			vk::VK_STENCIL_OP_KEEP,						// passOp
782 			vk::VK_STENCIL_OP_KEEP,						// depthFailOp
783 			vk::VK_COMPARE_OP_ALWAYS,					// compareOp
784 			0u,											// compareMask
785 			0u,											// writeMask
786 			0u,											// reference
787 		},											// back
788 		-1.0f,										// minDepthBounds
789 		+1.0f,										// maxDepthBounds
790 	};
791 	const vk::VkViewport								viewport0				=
792 	{
793 		0.0f,										// x
794 		0.0f,										// y
795 		(float)renderSize.x(),						// width
796 		(float)renderSize.y(),						// height
797 		0.0f,										// minDepth
798 		1.0f,										// maxDepth
799 	};
800 	const vk::VkRect2D									scissor0				=
801 	{
802 		{ 0u, 0u, },								// offset
803 		{ renderSize.x(), renderSize.y() },			// extent
804 	};
805 	const vk::VkPipelineViewportStateCreateInfo			viewportParams			=
806 	{
807 		vk::VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
808 		DE_NULL,
809 		(vk::VkPipelineViewportStateCreateFlags)0,
810 		1u,
811 		&viewport0,
812 		1u,
813 		&scissor0
814 	};
815 	const vk::VkPipelineMultisampleStateCreateInfo		multisampleParams		=
816 	{
817 		vk::VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
818 		DE_NULL,
819 		(vk::VkPipelineMultisampleStateCreateFlags)0,
820 		vk::VK_SAMPLE_COUNT_1_BIT,					// rasterizationSamples
821 		VK_FALSE,									// sampleShadingEnable
822 		0.0f,										// minSampleShading
823 		(const vk::VkSampleMask*)DE_NULL,			// sampleMask
824 		VK_FALSE,									// alphaToCoverageEnable
825 		VK_FALSE,									// alphaToOneEnable
826 	};
827 	const vk::VkPipelineRasterizationStateCreateInfo	rasterParams			=
828 	{
829 		vk::VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
830 		DE_NULL,
831 		(vk::VkPipelineRasterizationStateCreateFlags)0,
832 		VK_FALSE,										// depthClampEnable
833 		VK_FALSE,										// rasterizerDiscardEnable
834 		vk::VK_POLYGON_MODE_FILL,						// polygonMode
835 		vk::VK_CULL_MODE_NONE,							// cullMode
836 		vk::VK_FRONT_FACE_COUNTER_CLOCKWISE,			// frontFace
837 		VK_FALSE,										// depthBiasEnable
838 		0.0f,											// depthBiasConstantFactor
839 		0.0f,											// depthBiasClamp
840 		0.0f,											// depthBiasSlopeFactor
841 		1.0f,											// lineWidth
842 	};
843 	const vk::VkPipelineInputAssemblyStateCreateInfo	inputAssemblyParams		=
844 	{
845 		vk::VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
846 		DE_NULL,
847 		(vk::VkPipelineInputAssemblyStateCreateFlags)0,
848 		vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
849 		DE_FALSE,									// primitiveRestartEnable
850 	};
851 	const vk::VkVertexInputBindingDescription			vertexBinding0			=
852 	{
853 		0u,											// binding
854 		(deUint32)sizeof(tcu::Vec4),				// stride
855 		vk::VK_VERTEX_INPUT_RATE_VERTEX,			// inputRate
856 	};
857 	const vk::VkVertexInputAttributeDescription			vertexAttrib0			=
858 	{
859 		0u,											// location
860 		0u,											// binding
861 		vk::VK_FORMAT_R32G32B32A32_SFLOAT,			// format
862 		0u,											// offset
863 	};
864 	const vk::VkPipelineVertexInputStateCreateInfo		vertexInputStateParams	=
865 	{
866 		vk::VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
867 		DE_NULL,
868 		(vk::VkPipelineVertexInputStateCreateFlags)0,
869 		1u,
870 		&vertexBinding0,
871 		1u,
872 		&vertexAttrib0,
873 	};
874 	const vk::VkPipelineColorBlendAttachmentState		attBlendParams0			=
875 	{
876 		VK_FALSE,									// blendEnable
877 		vk::VK_BLEND_FACTOR_ONE,					// srcColorBlendFactor
878 		vk::VK_BLEND_FACTOR_ZERO,					// dstColorBlendFactor
879 		vk::VK_BLEND_OP_ADD,						// colorBlendOp
880 		vk::VK_BLEND_FACTOR_ONE,					// srcAlphaBlendFactor
881 		vk::VK_BLEND_FACTOR_ZERO,					// dstAlphaBlendFactor
882 		vk::VK_BLEND_OP_ADD,						// alphaBlendOp
883 		(vk::VK_COLOR_COMPONENT_R_BIT|
884 		 vk::VK_COLOR_COMPONENT_G_BIT|
885 		 vk::VK_COLOR_COMPONENT_B_BIT|
886 		 vk::VK_COLOR_COMPONENT_A_BIT),				// colorWriteMask
887 	};
888 	const vk::VkPipelineColorBlendStateCreateInfo		blendParams				=
889 	{
890 		vk::VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
891 		DE_NULL,
892 		(vk::VkPipelineColorBlendStateCreateFlags)0,
893 		VK_FALSE,									// logicOpEnable
894 		vk::VK_LOGIC_OP_COPY,
895 		1u,
896 		&attBlendParams0,
897 		{ 0.0f, 0.0f, 0.0f, 0.0f },					// blendConstants[4]
898 	};
899 	const vk::VkGraphicsPipelineCreateInfo				pipelineParams			=
900 	{
901 		vk::VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
902 		DE_NULL,
903 		(vk::VkPipelineCreateFlags)0,
904 		(deUint32)DE_LENGTH_OF_ARRAY(shaderStageParams),
905 		shaderStageParams,
906 		&vertexInputStateParams,
907 		&inputAssemblyParams,
908 		(const vk::VkPipelineTessellationStateCreateInfo*)DE_NULL,
909 		&viewportParams,
910 		&rasterParams,
911 		&multisampleParams,
912 		&depthStencilParams,
913 		&blendParams,
914 		(const vk::VkPipelineDynamicStateCreateInfo*)DE_NULL,
915 		pipelineLayout,
916 		renderPass,
917 		0u,											// subpass
918 		DE_NULL,									// basePipelineHandle
919 		0u,											// basePipelineIndex
920 	};
921 
922 	return vk::createGraphicsPipeline(vkd, device, (vk::VkPipelineCache)0, &pipelineParams);
923 }
924 
TriangleRenderer(ProtectedContext & context,const vk::BinaryCollection & binaryRegistry,const std::vector<vk::VkImage> swapchainImages,const vk::VkFormat framebufferFormat,const tcu::UVec2 & renderSize)925 TriangleRenderer::TriangleRenderer (ProtectedContext&				context,
926 									const vk::BinaryCollection&		binaryRegistry,
927 									const std::vector<vk::VkImage>	swapchainImages,
928 									const vk::VkFormat				framebufferFormat,
929 									const tcu::UVec2&				renderSize)
930 	: m_vkd					(context.getDeviceInterface())
931 	, m_swapchainImages		(swapchainImages)
932 	, m_renderSize			(renderSize)
933 	, m_renderPass			(createRenderPass(m_vkd, context.getDevice(), framebufferFormat))
934 	, m_pipelineLayout		(createPipelineLayout(m_vkd, context.getDevice()))
935 	, m_pipeline			(createPipeline(m_vkd, context.getDevice(), *m_renderPass, *m_pipelineLayout, binaryRegistry, renderSize))
936 	, m_vertexBuffer		(makeBuffer(context,
937 									PROTECTION_DISABLED,
938 									context.getQueueFamilyIndex(),
939 									(deUint32)(sizeof(float)*4*3),
940 									vk::VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
941 									vk::MemoryRequirement::HostVisible))
942 {
943 	m_attachmentViews.resize(swapchainImages.size());
944 	m_framebuffers.resize(swapchainImages.size());
945 
946 	for (size_t imageNdx = 0; imageNdx < swapchainImages.size(); ++imageNdx)
947 	{
948 		m_attachmentViews[imageNdx]	= ImageViewSp(new vk::Unique<vk::VkImageView>(createImageView(context, swapchainImages[imageNdx], framebufferFormat)));
949 		m_framebuffers[imageNdx]	= FramebufferSp(new vk::Unique<vk::VkFramebuffer>(createFramebuffer(context,
950 																										renderSize.x(),
951 																										renderSize.y(),
952 																										*m_renderPass,
953 																										**m_attachmentViews[imageNdx])));
954 	}
955 
956 	// Upload vertex data
957 	{
958 		const tcu::Vec4				vertices[]	=
959 		{
960 			tcu::Vec4(-0.5f, -0.5f, 0.0f, 1.0f),
961 			tcu::Vec4(+0.5f, -0.5f, 0.0f, 1.0f),
962 			tcu::Vec4( 0.0f, +0.5f, 0.0f, 1.0f)
963 		};
964 		DE_STATIC_ASSERT(sizeof(vertices) == sizeof(float)*4*3);
965 
966 		deMemcpy(m_vertexBuffer->getAllocation().getHostPtr(), &vertices[0], sizeof(vertices));
967 		vk::flushMappedMemoryRange(m_vkd, context.getDevice(), m_vertexBuffer->getAllocation().getMemory(), m_vertexBuffer->getAllocation().getOffset(), sizeof(vertices));
968 	}
969 }
970 
~TriangleRenderer(void)971 TriangleRenderer::~TriangleRenderer (void)
972 {
973 }
974 
recordFrame(vk::VkCommandBuffer cmdBuffer,deUint32 imageNdx,deUint32 frameNdx) const975 void TriangleRenderer::recordFrame (vk::VkCommandBuffer	cmdBuffer,
976 									deUint32			imageNdx,
977 									deUint32			frameNdx) const
978 {
979 	const vk::VkFramebuffer	curFramebuffer	= **m_framebuffers[imageNdx];
980 
981 	beginCommandBuffer(m_vkd, cmdBuffer);
982 
983 	{
984 		const vk::VkClearValue			clearValue		= vk::makeClearValueColorF32(0.125f, 0.25f, 0.75f, 1.0f);
985 		const vk::VkRenderPassBeginInfo	passBeginParams	=
986 		{
987 			vk::VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
988 			DE_NULL,
989 			*m_renderPass,
990 			curFramebuffer,
991 			{
992 				{ 0, 0 },
993 				{ (deUint32)m_renderSize.x(), (deUint32)m_renderSize.y() }
994 			},													// renderArea
995 			1u,													// clearValueCount
996 			&clearValue,										// pClearValues
997 		};
998 		m_vkd.cmdBeginRenderPass(cmdBuffer, &passBeginParams, vk::VK_SUBPASS_CONTENTS_INLINE);
999 	}
1000 
1001 	m_vkd.cmdBindPipeline(cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
1002 
1003 	{
1004 		const vk::VkDeviceSize bindingOffset = 0;
1005 		m_vkd.cmdBindVertexBuffers(cmdBuffer, 0u, 1u, &m_vertexBuffer->get(), &bindingOffset);
1006 	}
1007 
1008 	m_vkd.cmdPushConstants(cmdBuffer, *m_pipelineLayout, vk::VK_SHADER_STAGE_VERTEX_BIT, 0u, (deUint32)sizeof(deUint32), &frameNdx);
1009 	m_vkd.cmdDraw(cmdBuffer, 3u, 1u, 0u, 0u);
1010 	m_vkd.cmdEndRenderPass(cmdBuffer);
1011 
1012 	VK_CHECK(m_vkd.endCommandBuffer(cmdBuffer));
1013 }
1014 
getPrograms(vk::SourceCollections & dst)1015 void TriangleRenderer::getPrograms (vk::SourceCollections& dst)
1016 {
1017 	dst.glslSources.add("tri-vert") << glu::VertexSource(
1018 		"#version 310 es\n"
1019 		"layout(location = 0) in highp vec4 a_position;\n"
1020 		"layout(push_constant) uniform FrameData\n"
1021 		"{\n"
1022 		"    highp uint frameNdx;\n"
1023 		"} frameData;\n"
1024 		"void main (void)\n"
1025 		"{\n"
1026 		"    highp float angle = float(frameData.frameNdx) / 100.0;\n"
1027 		"    highp float c     = cos(angle);\n"
1028 		"    highp float s     = sin(angle);\n"
1029 		"    highp mat4  t     = mat4( c, -s,  0,  0,\n"
1030 		"                              s,  c,  0,  0,\n"
1031 		"                              0,  0,  1,  0,\n"
1032 		"                              0,  0,  0,  1);\n"
1033 		"    gl_Position = t * a_position;\n"
1034 		"}\n");
1035 	dst.glslSources.add("tri-frag") << glu::FragmentSource(
1036 		"#version 310 es\n"
1037 		"layout(location = 0) out lowp vec4 o_color;\n"
1038 		"void main (void) { o_color = vec4(1.0, 0.0, 1.0, 1.0); }\n");
1039 }
1040 
1041 typedef de::SharedPtr<vk::Unique<vk::VkCommandBuffer> >	CommandBufferSp;
1042 typedef de::SharedPtr<vk::Unique<vk::VkFence> >			FenceSp;
1043 typedef de::SharedPtr<vk::Unique<vk::VkSemaphore> >		SemaphoreSp;
1044 
createFences(const vk::DeviceInterface & vkd,const vk::VkDevice device,size_t numFences)1045 std::vector<FenceSp> createFences (const vk::DeviceInterface&	vkd,
1046 								   const vk::VkDevice			device,
1047 								   size_t						numFences)
1048 {
1049 	std::vector<FenceSp> fences(numFences);
1050 
1051 	for (size_t ndx = 0; ndx < numFences; ++ndx)
1052 		fences[ndx] = FenceSp(new vk::Unique<vk::VkFence>(createFence(vkd, device)));
1053 
1054 	return fences;
1055 }
1056 
createSemaphores(const vk::DeviceInterface & vkd,const vk::VkDevice device,size_t numSemaphores)1057 std::vector<SemaphoreSp> createSemaphores (const vk::DeviceInterface&	vkd,
1058 										   const vk::VkDevice			device,
1059 										   size_t						numSemaphores)
1060 {
1061 	std::vector<SemaphoreSp> semaphores(numSemaphores);
1062 
1063 	for (size_t ndx = 0; ndx < numSemaphores; ++ndx)
1064 		semaphores[ndx] = SemaphoreSp(new vk::Unique<vk::VkSemaphore>(createSemaphore(vkd, device)));
1065 
1066 	return semaphores;
1067 }
1068 
allocateCommandBuffers(const vk::DeviceInterface & vkd,const vk::VkDevice device,const vk::VkCommandPool commandPool,const vk::VkCommandBufferLevel level,const size_t numCommandBuffers)1069 std::vector<CommandBufferSp> allocateCommandBuffers (const vk::DeviceInterface&		vkd,
1070 													 const vk::VkDevice				device,
1071 													 const vk::VkCommandPool		commandPool,
1072 													 const vk::VkCommandBufferLevel	level,
1073 													 const size_t					numCommandBuffers)
1074 {
1075 	std::vector<CommandBufferSp>			buffers		(numCommandBuffers);
1076 
1077 	for (size_t ndx = 0; ndx < numCommandBuffers; ++ndx)
1078 		buffers[ndx] = CommandBufferSp(new vk::Unique<vk::VkCommandBuffer>(allocateCommandBuffer(vkd, device, commandPool, level)));
1079 
1080 	return buffers;
1081 }
1082 
basicRenderTest(Context & baseCtx,vk::wsi::Type wsiType)1083 tcu::TestStatus basicRenderTest (Context& baseCtx, vk::wsi::Type wsiType)
1084 {
1085 	std::vector<vk::VkExtensionProperties>	supportedExtensions			(enumerateInstanceExtensionProperties(baseCtx.getPlatformInterface(), DE_NULL));
1086 	std::vector<std::string>				instExts					= getRequiredWsiExtensions(supportedExtensions, wsiType);
1087 	std::vector<std::string>				devExts;
1088 	devExts.push_back("VK_KHR_swapchain");
1089 
1090 	const tcu::UVec2						desiredSize					(256, 256);
1091 	const NativeObjects						native						(baseCtx,  supportedExtensions, wsiType, tcu::just(desiredSize));
1092 	ProtectedContext						context						(baseCtx, wsiType, *native.display, *native.window, instExts, devExts);
1093 	vk::VkSurfaceKHR						surface						= context.getSurface();
1094 	const vk::DeviceInterface&				vkd							= context.getDeviceInterface();
1095 	const vk::VkDevice						device						= context.getDevice();
1096 	const vk::VkSwapchainCreateInfoKHR		swapchainInfo				= getBasicSwapchainParameters(wsiType,
1097 																								  context.getInstanceDriver(),
1098 																								  context.getPhysicalDevice(),
1099 																								  surface,
1100 																								  desiredSize,
1101 																								  2);
1102 	const vk::Unique<vk::VkSwapchainKHR>	swapchain					(createSwapchainKHR(vkd, device, &swapchainInfo));
1103 	const std::vector<vk::VkImage>			swapchainImages				= vk::wsi::getSwapchainImages(vkd, device, *swapchain);
1104 
1105 	const TriangleRenderer					renderer					(context,
1106 																		 context.getBinaryCollection(),
1107 																		 swapchainImages,
1108 																		 swapchainInfo.imageFormat,
1109 																		 tcu::UVec2(swapchainInfo.imageExtent.width, swapchainInfo.imageExtent.height));
1110 
1111 	const vk::Unique<vk::VkCommandPool>		commandPool					(makeCommandPool(vkd, device, PROTECTION_ENABLED,
1112 																					 context.getQueueFamilyIndex()));
1113 
1114 	const size_t							maxQueuedFrames				= swapchainImages.size()*2;
1115 
1116 	// We need to keep hold of fences from vkAcquireNextImageKHR to actually
1117 	// limit number of frames we allow to be queued.
1118 	const std::vector<FenceSp>				imageReadyFences			(createFences(vkd, device, maxQueuedFrames));
1119 
1120 	// We need maxQueuedFrames+1 for imageReadySemaphores pool as we need to pass
1121 	// the semaphore in same time as the fence we use to meter rendering.
1122 	const std::vector<SemaphoreSp>			imageReadySemaphores		(createSemaphores(vkd, device, maxQueuedFrames+1));
1123 
1124 	// For rest we simply need maxQueuedFrames as we will wait for image
1125 	// from frameNdx-maxQueuedFrames to become available to us, guaranteeing that
1126 	// previous uses must have completed.
1127 	const std::vector<SemaphoreSp>			renderingCompleteSemaphores	(createSemaphores(vkd, device, maxQueuedFrames));
1128 	const std::vector<CommandBufferSp>		commandBuffers				(allocateCommandBuffers(vkd,
1129 																								device,
1130 																								*commandPool,
1131 																								vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY,
1132 																								maxQueuedFrames));
1133 
1134 	try
1135 	{
1136 		const deUint32	numFramesToRender	= 60*10;
1137 
1138 		for (deUint32 frameNdx = 0; frameNdx < numFramesToRender; ++frameNdx)
1139 		{
1140 			const vk::VkFence		imageReadyFence		= **imageReadyFences[frameNdx%imageReadyFences.size()];
1141 			const vk::VkSemaphore	imageReadySemaphore	= **imageReadySemaphores[frameNdx%imageReadySemaphores.size()];
1142 			deUint32				imageNdx			= ~0u;
1143 
1144 			if (frameNdx >= maxQueuedFrames)
1145 				VK_CHECK(vkd.waitForFences(device, 1u, &imageReadyFence, VK_TRUE, std::numeric_limits<deUint64>::max()));
1146 
1147 			VK_CHECK(vkd.resetFences(device, 1, &imageReadyFence));
1148 
1149 			{
1150 				const vk::VkResult	acquireResult	= vkd.acquireNextImageKHR(device,
1151 																			  *swapchain,
1152 																			  std::numeric_limits<deUint64>::max(),
1153 																			  imageReadySemaphore,
1154 																			  imageReadyFence,
1155 																			  &imageNdx);
1156 
1157 				if (acquireResult == vk::VK_SUBOPTIMAL_KHR)
1158 					context.getTestContext().getLog() << tcu::TestLog::Message << "Got " << acquireResult << " at frame " << frameNdx << tcu::TestLog::EndMessage;
1159 				else
1160 					VK_CHECK(acquireResult);
1161 			}
1162 
1163 			TCU_CHECK((size_t)imageNdx < swapchainImages.size());
1164 
1165 			{
1166 				const vk::VkSemaphore			renderingCompleteSemaphore	= **renderingCompleteSemaphores[frameNdx%renderingCompleteSemaphores.size()];
1167 				const vk::VkCommandBuffer		commandBuffer				= **commandBuffers[frameNdx%commandBuffers.size()];
1168 				const vk::VkPipelineStageFlags	waitDstStage				= vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
1169 				vk::VkSubmitInfo				submitInfo					=
1170 				{
1171 					vk::VK_STRUCTURE_TYPE_SUBMIT_INFO,
1172 					DE_NULL,
1173 					1u,
1174 					&imageReadySemaphore,
1175 					&waitDstStage,
1176 					1u,
1177 					&commandBuffer,
1178 					1u,
1179 					&renderingCompleteSemaphore
1180 				};
1181 
1182 				const vk::VkProtectedSubmitInfo		protectedInfo   =
1183 				{
1184 					vk::VK_STRUCTURE_TYPE_PROTECTED_SUBMIT_INFO,		// sType
1185 					DE_NULL,											// pNext
1186 					VK_TRUE,											// protectedSubmit
1187 				};
1188 				submitInfo.pNext = &protectedInfo;
1189 
1190 				const vk::VkPresentInfoKHR		presentInfo					=
1191 				{
1192 					vk::VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
1193 					DE_NULL,
1194 					1u,
1195 					&renderingCompleteSemaphore,
1196 					1u,
1197 					&*swapchain,
1198 					&imageNdx,
1199 					(vk::VkResult*)DE_NULL
1200 				};
1201 
1202 				renderer.recordFrame(commandBuffer, imageNdx, frameNdx);
1203 				VK_CHECK(vkd.queueSubmit(context.getQueue(), 1u, &submitInfo, (vk::VkFence)0));
1204 				VK_CHECK(vkd.queuePresentKHR(context.getQueue(), &presentInfo));
1205 			}
1206 		}
1207 
1208 		VK_CHECK(vkd.deviceWaitIdle(device));
1209 	}
1210 	catch (...)
1211 	{
1212 		// Make sure device is idle before destroying resources
1213 		vkd.deviceWaitIdle(device);
1214 		throw;
1215 	}
1216 
1217 	return tcu::TestStatus::pass("Rendering tests succeeded");
1218 }
1219 
getBasicRenderPrograms(vk::SourceCollections & dst,vk::wsi::Type)1220 void getBasicRenderPrograms (vk::SourceCollections& dst, vk::wsi::Type)
1221 {
1222 	TriangleRenderer::getPrograms(dst);
1223 }
1224 
populateRenderGroup(tcu::TestCaseGroup * testGroup,vk::wsi::Type wsiType)1225 void populateRenderGroup (tcu::TestCaseGroup* testGroup, vk::wsi::Type wsiType)
1226 {
1227 	addFunctionCaseWithPrograms(testGroup, "basic", "Basic Rendering Test", getBasicRenderPrograms, basicRenderTest, wsiType);
1228 }
1229 
createSwapchainTests(tcu::TestCaseGroup * testGroup,vk::wsi::Type wsiType)1230 void createSwapchainTests (tcu::TestCaseGroup* testGroup, vk::wsi::Type wsiType)
1231 {
1232 	addTestGroup(testGroup, "create",			"Create VkSwapchain with various parameters",					populateSwapchainGroup,		GroupParameters(wsiType, createSwapchainTest));
1233 	addTestGroup(testGroup, "render",			"Rendering Tests",												populateRenderGroup,		wsiType);
1234 }
1235 
createTypeSpecificTests(tcu::TestCaseGroup * testGroup,vk::wsi::Type wsiType)1236 void createTypeSpecificTests (tcu::TestCaseGroup* testGroup, vk::wsi::Type wsiType)
1237 {
1238 	addTestGroup(testGroup, "swapchain", "VkSwapchain Tests", createSwapchainTests, wsiType);
1239 }
1240 
1241 } // anonymous
1242 
createSwapchainTests(tcu::TestContext & testCtx)1243 tcu::TestCaseGroup* createSwapchainTests (tcu::TestContext& testCtx)
1244 {
1245 	de::MovePtr<tcu::TestCaseGroup> wsiTestGroup (new tcu::TestCaseGroup(testCtx, "wsi", "WSI Tests"));
1246 
1247 	for (int typeNdx = 0; typeNdx < vk::wsi::TYPE_LAST; ++typeNdx)
1248 	{
1249 		const vk::wsi::Type	wsiType		= (vk::wsi::Type)typeNdx;
1250 
1251 		addTestGroup(&*wsiTestGroup, getName(wsiType), "", createTypeSpecificTests, wsiType);
1252 	}
1253 
1254 	return wsiTestGroup.release();
1255 }
1256 
1257 } // wsi
1258 } // vkt
1259