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