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