• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*-------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2017 Google Inc.
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  *//*!
20  * \file
21  * \brief VkSwapchain Tests
22  *//*--------------------------------------------------------------------*/
23 
24 #include "vktWsiSwapchainTests.hpp"
25 
26 #include "vktTestCaseUtil.hpp"
27 #include "vktTestGroupUtil.hpp"
28 #include "vktCustomInstancesDevices.hpp"
29 #include "vktNativeObjectsUtil.hpp"
30 
31 #include "vkDefs.hpp"
32 #include "vkPlatform.hpp"
33 #include "vkStrUtil.hpp"
34 #include "vkRef.hpp"
35 #include "vkRefUtil.hpp"
36 #include "vkQueryUtil.hpp"
37 #include "vkMemUtil.hpp"
38 #include "vkDeviceUtil.hpp"
39 #include "vkPrograms.hpp"
40 #include "vkTypeUtil.hpp"
41 #include "vkCmdUtil.hpp"
42 #include "vkWsiPlatform.hpp"
43 #include "vkWsiUtil.hpp"
44 #include "vkAllocationCallbackUtil.hpp"
45 #include "vkCmdUtil.hpp"
46 #include "vkObjUtil.hpp"
47 #include "tcuSurface.hpp"
48 #include "vkImageUtil.hpp"
49 
50 #include "tcuTestLog.hpp"
51 #include "tcuFormatUtil.hpp"
52 #include "tcuPlatform.hpp"
53 #include "tcuResultCollector.hpp"
54 #include "tcuCommandLine.hpp"
55 
56 #include "deUniquePtr.hpp"
57 #include "deStringUtil.hpp"
58 #include "deArrayUtil.hpp"
59 #include "deSharedPtr.hpp"
60 
61 #include <limits>
62 
63 namespace vkt
64 {
65 namespace wsi
66 {
67 
68 namespace
69 {
70 
71 using namespace vk;
72 using namespace vk::wsi;
73 
74 using tcu::TestLog;
75 using tcu::Maybe;
76 using tcu::UVec2;
77 
78 using de::MovePtr;
79 using de::UniquePtr;
80 
81 using std::string;
82 using std::vector;
83 
84 typedef vector<VkExtensionProperties> Extensions;
85 
checkAllSupported(const Extensions & supportedExtensions,const vector<string> & requiredExtensions)86 void checkAllSupported (const Extensions& supportedExtensions, const vector<string>& requiredExtensions)
87 {
88 	for (vector<string>::const_iterator requiredExtName = requiredExtensions.begin();
89 		 requiredExtName != requiredExtensions.end();
90 		 ++requiredExtName)
91 	{
92 		if (!isExtensionStructSupported(supportedExtensions, RequiredExtension(*requiredExtName)))
93 			TCU_THROW(NotSupportedError, (*requiredExtName + " is not supported").c_str());
94 	}
95 }
96 
createInstanceWithWsi(Context & context,const Extensions & supportedExtensions,Type wsiType,const VkAllocationCallbacks * pAllocator=DE_NULL)97 CustomInstance createInstanceWithWsi (Context&						context,
98 									  const Extensions&				supportedExtensions,
99 									  Type							wsiType,
100 									  const VkAllocationCallbacks*	pAllocator	= DE_NULL)
101 {
102 	vector<string>	extensions;
103 
104 	extensions.push_back("VK_KHR_surface");
105 	extensions.push_back(getExtensionName(wsiType));
106 	if (isDisplaySurface(wsiType))
107 		extensions.push_back("VK_KHR_display");
108 
109 	// VK_EXT_swapchain_colorspace adds new surface formats. Driver can enumerate
110 	// the formats regardless of whether VK_EXT_swapchain_colorspace was enabled,
111 	// but using them without enabling the extension is not allowed. Thus we have
112 	// two options:
113 	//
114 	// 1) Filter out non-core formats to stay within valid usage.
115 	//
116 	// 2) Enable VK_EXT_swapchain colorspace if advertised by the driver.
117 	//
118 	// We opt for (2) as it provides basic coverage for the extension as a bonus.
119 	if (isExtensionStructSupported(supportedExtensions, RequiredExtension("VK_EXT_swapchain_colorspace")))
120 		extensions.push_back("VK_EXT_swapchain_colorspace");
121 
122 	checkAllSupported(supportedExtensions, extensions);
123 
124 	return createCustomInstanceWithExtensions(context, extensions, pAllocator);
125 }
126 
getDeviceFeaturesForWsi(void)127 VkPhysicalDeviceFeatures getDeviceFeaturesForWsi (void)
128 {
129 	VkPhysicalDeviceFeatures features;
130 	deMemset(&features, 0, sizeof(features));
131 	return features;
132 }
133 
createDeviceWithWsi(const vk::PlatformInterface & vkp,vk::VkInstance instance,const InstanceInterface & vki,VkPhysicalDevice physicalDevice,const Extensions & supportedExtensions,const deUint32 queueFamilyIndex,const VkAllocationCallbacks * pAllocator,bool validationEnabled)134 Move<VkDevice> createDeviceWithWsi (const vk::PlatformInterface&	vkp,
135 									vk::VkInstance					instance,
136 									const InstanceInterface&		vki,
137 									VkPhysicalDevice				physicalDevice,
138 									const Extensions&				supportedExtensions,
139 									const deUint32					queueFamilyIndex,
140 									const VkAllocationCallbacks*	pAllocator,
141 									bool							validationEnabled)
142 {
143 	const float						queuePriorities[]	= { 1.0f };
144 	const VkDeviceQueueCreateInfo	queueInfos[]		=
145 	{
146 		{
147 			VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
148 			DE_NULL,
149 			(VkDeviceQueueCreateFlags)0,
150 			queueFamilyIndex,
151 			DE_LENGTH_OF_ARRAY(queuePriorities),
152 			&queuePriorities[0]
153 		}
154 	};
155 	const VkPhysicalDeviceFeatures	features		= getDeviceFeaturesForWsi();
156 	vector<const char*>		extensions;
157 
158 	if (!isExtensionStructSupported(supportedExtensions, RequiredExtension("VK_KHR_swapchain")))
159 		TCU_THROW(NotSupportedError, "VK_KHR_swapchain is not supported");
160 	extensions.push_back("VK_KHR_swapchain");
161 
162 	if (isExtensionStructSupported(supportedExtensions, RequiredExtension("VK_EXT_hdr_metadata")))
163 		extensions.push_back("VK_EXT_hdr_metadata");
164 
165 	VkDeviceCreateInfo		deviceParams	=
166 	{
167 		VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
168 		DE_NULL,
169 		(VkDeviceCreateFlags)0,
170 		DE_LENGTH_OF_ARRAY(queueInfos),
171 		&queueInfos[0],
172 		0u,									// enabledLayerCount
173 		DE_NULL,							// ppEnabledLayerNames
174 		(deUint32)extensions.size(),
175 		extensions.empty() ? DE_NULL : &extensions[0],
176 		&features
177 	};
178 
179 	return createCustomDevice(validationEnabled, vkp, instance, vki, physicalDevice, &deviceParams, pAllocator);
180 }
181 
182 struct InstanceHelper
183 {
184 	const vector<VkExtensionProperties>	supportedExtensions;
185 	const CustomInstance				instance;
186 	const InstanceDriver&				vki;
187 
InstanceHelpervkt::wsi::__anon8de9ffac0111::InstanceHelper188 	InstanceHelper (Context& context, Type wsiType, const VkAllocationCallbacks* pAllocator = DE_NULL)
189 		: supportedExtensions	(enumerateInstanceExtensionProperties(context.getPlatformInterface(),
190 																	  DE_NULL))
191 		, instance				(createInstanceWithWsi(context,
192 													   supportedExtensions,
193 													   wsiType,
194 													   pAllocator))
195 		, vki					(instance.getDriver())
196 	{}
197 };
198 
199 struct DeviceHelper
200 {
201 	const VkPhysicalDevice	physicalDevice;
202 	const deUint32			queueFamilyIndex;
203 	const Unique<VkDevice>	device;
204 	const DeviceDriver		vkd;
205 	const VkQueue			queue;
206 
DeviceHelpervkt::wsi::__anon8de9ffac0111::DeviceHelper207 	DeviceHelper (Context&						context,
208 				  const InstanceInterface&		vki,
209 				  VkInstance					instance,
210 				  VkSurfaceKHR					surface,
211 				  const VkAllocationCallbacks*	pAllocator = DE_NULL)
212 		: physicalDevice	(chooseDevice(vki, instance, context.getTestContext().getCommandLine()))
213 		, queueFamilyIndex	(chooseQueueFamilyIndex(vki, physicalDevice, surface))
214 		, device			(createDeviceWithWsi(context.getPlatformInterface(),
215 												 instance,
216 												 vki,
217 												 physicalDevice,
218 												 enumerateDeviceExtensionProperties(vki, physicalDevice, DE_NULL),
219 												 queueFamilyIndex,
220 												 pAllocator,
221 												 context.getTestContext().getCommandLine().isValidationEnabled()))
222 		, vkd				(context.getPlatformInterface(), instance, *device)
223 		, queue				(getDeviceQueue(vkd, *device, queueFamilyIndex, 0))
224 	{
225 	}
226 };
227 
228 enum TestDimension
229 {
230 	TEST_DIMENSION_MIN_IMAGE_COUNT = 0,	//!< Test all supported image counts
231 	TEST_DIMENSION_IMAGE_FORMAT,		//!< Test all supported formats
232 	TEST_DIMENSION_IMAGE_EXTENT,		//!< Test various (supported) extents
233 	TEST_DIMENSION_IMAGE_ARRAY_LAYERS,
234 	TEST_DIMENSION_IMAGE_USAGE,
235 	TEST_DIMENSION_IMAGE_SHARING_MODE,
236 	TEST_DIMENSION_PRE_TRANSFORM,
237 	TEST_DIMENSION_COMPOSITE_ALPHA,
238 	TEST_DIMENSION_PRESENT_MODE,
239 	TEST_DIMENSION_CLIPPED,
240 
241 	TEST_DIMENSION_LAST
242 };
243 
244 struct TestParameters
245 {
246 	Type			wsiType;
247 	TestDimension	dimension;
248 
TestParametersvkt::wsi::__anon8de9ffac0111::TestParameters249 	TestParameters (Type wsiType_, TestDimension dimension_)
250 		: wsiType	(wsiType_)
251 		, dimension	(dimension_)
252 	{}
253 
TestParametersvkt::wsi::__anon8de9ffac0111::TestParameters254 	TestParameters (void)
255 		: wsiType	(TYPE_LAST)
256 		, dimension	(TEST_DIMENSION_LAST)
257 	{}
258 };
259 
260 struct GroupParameters
261 {
262 	typedef FunctionInstance1<TestParameters>::Function	Function;
263 
264 	Type		wsiType;
265 	Function	function;
266 
GroupParametersvkt::wsi::__anon8de9ffac0111::GroupParameters267 	GroupParameters (Type wsiType_, Function function_)
268 		: wsiType	(wsiType_)
269 		, function	(function_)
270 	{}
271 
GroupParametersvkt::wsi::__anon8de9ffac0111::GroupParameters272 	GroupParameters (void)
273 		: wsiType	(TYPE_LAST)
274 		, function	((Function)DE_NULL)
275 	{}
276 };
277 
getBasicSwapchainParameters(Type wsiType,const InstanceInterface & vki,VkPhysicalDevice physicalDevice,VkSurfaceKHR surface,VkSurfaceFormatKHR surfaceFormat,const tcu::UVec2 & desiredSize,deUint32 desiredImageCount,VkColorSpaceKHR desiredColorspace=VK_COLOR_SPACE_MAX_ENUM_KHR)278 VkSwapchainCreateInfoKHR getBasicSwapchainParameters (Type						wsiType,
279 													  const InstanceInterface&	vki,
280 													  VkPhysicalDevice			physicalDevice,
281 													  VkSurfaceKHR				surface,
282 													  VkSurfaceFormatKHR		surfaceFormat,
283 													  const tcu::UVec2&			desiredSize,
284 													  deUint32					desiredImageCount,
285 													  VkColorSpaceKHR			desiredColorspace = VK_COLOR_SPACE_MAX_ENUM_KHR)
286 {
287 	bool setColorspaceManually = desiredColorspace != VK_COLOR_SPACE_MAX_ENUM_KHR;
288 
289 	const VkSurfaceCapabilitiesKHR		capabilities		= getPhysicalDeviceSurfaceCapabilities(vki,
290 																								   physicalDevice,
291 																								   surface);
292 	const PlatformProperties&			platformProperties	= getPlatformProperties(wsiType);
293 	const VkSurfaceCapabilitiesKHR		surfaceCapabilities	= getPhysicalDeviceSurfaceCapabilities(vki,physicalDevice, surface);
294 
295 	// Check that the device has at least one supported alpha compositing mode
296 	// and pick the first supported mode to be used.
297 	vk::VkCompositeAlphaFlagsKHR		alpha				= 0;
298 	for (deUint32 i = 1u; i <= surfaceCapabilities.supportedCompositeAlpha; i <<= 1u)
299 	{
300 		if ((i & surfaceCapabilities.supportedCompositeAlpha) != 0)
301 		{
302 			alpha = i;
303 			break;
304 		}
305 	}
306 	if (alpha == 0)
307 		TCU_THROW(NotSupportedError, "No supported composite alphas available.");
308 
309 	const VkSurfaceTransformFlagBitsKHR transform			= (capabilities.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) ? VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR : capabilities.currentTransform;
310 	const VkSwapchainCreateInfoKHR		parameters			=
311 	{
312 		VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
313 		DE_NULL,
314 		(VkSwapchainCreateFlagsKHR)0,
315 		surface,
316 		de::clamp(desiredImageCount, capabilities.minImageCount, capabilities.maxImageCount > 0 ? capabilities.maxImageCount : capabilities.minImageCount + desiredImageCount),
317 		surfaceFormat.format,
318 		(setColorspaceManually ? desiredColorspace : surfaceFormat.colorSpace),
319 		(platformProperties.swapchainExtent == PlatformProperties::SWAPCHAIN_EXTENT_MUST_MATCH_WINDOW_SIZE ? capabilities.currentExtent : vk::makeExtent2D(desiredSize.x(), desiredSize.y())),
320 		1u,									// imageArrayLayers
321 		VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT,
322 		VK_SHARING_MODE_EXCLUSIVE,
323 		0u,
324 		(const deUint32*)DE_NULL,
325 		transform,
326 		static_cast<VkCompositeAlphaFlagBitsKHR>(alpha),
327 		VK_PRESENT_MODE_FIFO_KHR,
328 		VK_FALSE,							// clipped
329 		(VkSwapchainKHR)0					// oldSwapchain
330 	};
331 
332 	return parameters;
333 }
334 
335 typedef de::SharedPtr<Unique<VkCommandBuffer> >	CommandBufferSp;
336 typedef de::SharedPtr<Unique<VkFence> >			FenceSp;
337 typedef de::SharedPtr<Unique<VkSemaphore> >		SemaphoreSp;
338 
createFences(const DeviceInterface & vkd,const VkDevice device,size_t numFences)339 vector<FenceSp> createFences (const DeviceInterface&	vkd,
340 							  const VkDevice			device,
341 							  size_t					numFences)
342 {
343 	vector<FenceSp> fences(numFences);
344 
345 	for (size_t ndx = 0; ndx < numFences; ++ndx)
346 		fences[ndx] = FenceSp(new Unique<VkFence>(createFence(vkd, device)));
347 
348 	return fences;
349 }
350 
createSemaphores(const DeviceInterface & vkd,const VkDevice device,size_t numSemaphores)351 vector<SemaphoreSp> createSemaphores (const DeviceInterface&	vkd,
352 									  const VkDevice			device,
353 									  size_t					numSemaphores)
354 {
355 	vector<SemaphoreSp> semaphores(numSemaphores);
356 
357 	for (size_t ndx = 0; ndx < numSemaphores; ++ndx)
358 		semaphores[ndx] = SemaphoreSp(new Unique<VkSemaphore>(createSemaphore(vkd, device)));
359 
360 	return semaphores;
361 }
362 
allocateCommandBuffers(const DeviceInterface & vkd,const VkDevice device,const VkCommandPool commandPool,const VkCommandBufferLevel level,const size_t numCommandBuffers)363 vector<CommandBufferSp> allocateCommandBuffers (const DeviceInterface&		vkd,
364 												const VkDevice				device,
365 												const VkCommandPool			commandPool,
366 												const VkCommandBufferLevel	level,
367 												const size_t				numCommandBuffers)
368 {
369 	vector<CommandBufferSp>				buffers		(numCommandBuffers);
370 
371 	for (size_t ndx = 0; ndx < numCommandBuffers; ++ndx)
372 		buffers[ndx] = CommandBufferSp(new Unique<VkCommandBuffer>(allocateCommandBuffer(vkd, device, commandPool, level)));
373 
374 	return buffers;
375 }
376 
getPixel(const DeviceInterface & vkd,const VkDevice device,const VkQueue queue,const VkCommandPool & commandPool,Allocator & allocator,const tcu::UVec2 size,const tcu::TextureFormat textureFormat,const VkImage * image)377 tcu::Vec4 getPixel (const DeviceInterface&		vkd,
378 					const VkDevice				device,
379 					const VkQueue				queue,
380 					const VkCommandPool&		commandPool,
381 					Allocator&					allocator,
382 					const tcu::UVec2			size,
383 					const tcu::TextureFormat	textureFormat,
384 					const VkImage*				image)
385 {
386 	Move<VkCommandBuffer>		commandBuffer;
387 	Move<VkBuffer>				resultBuffer;
388 	de::MovePtr<Allocation>		resultBufferMemory;
389 
390 	commandBuffer = allocateCommandBuffer(vkd, device, commandPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
391 
392 	// Result Buffer
393 	{
394 		const VkDeviceSize			bufferSize = textureFormat.getPixelSize() * size.x() * size.y();
395 		const VkBufferCreateInfo	createInfo = makeBufferCreateInfo(bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT);
396 
397 		resultBuffer				= createBuffer(vkd, device, &createInfo);
398 		resultBufferMemory			= allocator.allocate(getBufferMemoryRequirements(vkd, device, *resultBuffer), MemoryRequirement::HostVisible);
399 
400 		VK_CHECK(vkd.bindBufferMemory(device, *resultBuffer, resultBufferMemory->getMemory(), resultBufferMemory->getOffset()));
401 	}
402 
403 	beginCommandBuffer(vkd, *commandBuffer, 0u);
404 	{
405 		copyImageToBuffer(vkd, *commandBuffer, *image, *resultBuffer, tcu::IVec2(size.x(), size.y()), VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
406 	}
407 	endCommandBuffer(vkd, *commandBuffer);
408 	submitCommandsAndWait(vkd, device, queue, commandBuffer.get());
409 
410 	tcu::ConstPixelBufferAccess	resultAccess(textureFormat,
411 											 tcu::IVec3(size.x(), size.y(), 1),
412 											 resultBufferMemory->getHostPtr());
413 
414 	return (resultAccess.getPixel(128, 128));
415 }
416 
basicExtensionTest(Context & context,Type wsiType)417 tcu::TestStatus basicExtensionTest (Context& context, Type wsiType)
418 {
419 	const tcu::UVec2				desiredSize		(256, 256);
420 	const InstanceHelper			instHelper		(context, wsiType);
421 	const NativeObjects				native			(context, instHelper.supportedExtensions, wsiType, 1u, tcu::just(desiredSize));
422 	const Unique<VkSurfaceKHR>		surface			(createSurface(instHelper.vki, instHelper.instance, wsiType, native.getDisplay(), native.getWindow(), context.getTestContext().getCommandLine()));
423 	const DeviceHelper				devHelper		(context, instHelper.vki, instHelper.instance, *surface);
424 
425 	if (!de::contains(context.getInstanceExtensions().begin(), context.getInstanceExtensions().end(), "VK_EXT_swapchain_colorspace"))
426 		TCU_THROW(NotSupportedError, "Extension VK_EXT_swapchain_colorspace not supported");
427 
428 	const vector<VkSurfaceFormatKHR>	formats			= getPhysicalDeviceSurfaceFormats(instHelper.vki,
429 																						  devHelper.physicalDevice,
430 																						  *surface);
431 
432 	bool found = false;
433 	for (vector<VkSurfaceFormatKHR>::const_iterator curFmt = formats.begin(); curFmt != formats.end(); ++curFmt)
434 	{
435 		if (curFmt->colorSpace != VK_COLOR_SPACE_SRGB_NONLINEAR_KHR)
436 		{
437 			found = true;
438 			break;
439 		}
440 	}
441 	if (!found)
442 	{
443 		TCU_THROW(NotSupportedError, "VK_EXT_swapchain_colorspace supported, but no non-SRGB_NONLINEAR_KHR surface formats found.");
444 	}
445 	return tcu::TestStatus::pass("Extension tests succeeded");
446 }
447 
448 struct TestParams
449 {
450 	Type		wsiType;
451 	VkFormat	format;
452 };
453 
454 // Create swapchain with multiple images on different colorspaces and compare pixels on those images.
colorspaceCompareTest(Context & context,TestParams params)455 tcu::TestStatus colorspaceCompareTest (Context& context, TestParams params)
456 {
457 	if (!context.isInstanceFunctionalitySupported("VK_EXT_swapchain_colorspace"))
458 		TCU_THROW(NotSupportedError, "Extension VK_EXT_swapchain_colorspace not supported");
459 
460 	const tcu::UVec2					desiredSize				(256, 256);
461 	const InstanceHelper				instHelper				(context, params.wsiType);
462 	const NativeObjects					native					(context, instHelper.supportedExtensions, params.wsiType, tcu::just(desiredSize));
463 	const Unique<VkSurfaceKHR>			surface					(createSurface(instHelper.vki, instHelper.instance, params.wsiType, native.getDisplay(), native.getWindow(), context.getTestContext().getCommandLine()));
464 	const DeviceHelper					devHelper				(context, instHelper.vki, instHelper.instance, *surface);
465 
466 	const vector<VkSurfaceFormatKHR>	queriedFormats		=	getPhysicalDeviceSurfaceFormats(instHelper.vki,
467 																								devHelper.physicalDevice,
468 																								*surface);
469 
470 	vector<vk::VkColorSpaceKHR> supportedColorSpaces;
471 	for (const auto& queriedFormat : queriedFormats)
472 	{
473 		if (queriedFormat.format == params.format)
474 		{
475 			supportedColorSpaces.push_back(queriedFormat.colorSpace);
476 		}
477 	}
478 
479 	// Not supported if there's no color spaces for the format.
480 	if(supportedColorSpaces.size() < 2)
481 		TCU_THROW(NotSupportedError, "Format not supported");
482 
483 	// Surface format is used to create the swapchain.
484 	VkSurfaceFormatKHR surfaceFormat =
485 	{
486 		params.format,				// format
487 		supportedColorSpaces.at(0)	// colorSpace
488 	};
489 
490 	tcu::Vec4						 referenceColorspacePixel;
491 	const tcu::TextureFormat		 textureFormat				= vk::mapVkFormat(surfaceFormat.format);
492 	const DeviceInterface&			 vkd						= devHelper.vkd;
493 	const VkDevice					 device						= *devHelper.device;
494 	SimpleAllocator					 allocator					(vkd,
495 																 device,
496 																 getPhysicalDeviceMemoryProperties(instHelper.vki,
497 																 context.getPhysicalDevice()));
498 
499 	for (size_t colorspaceNdx = 0; colorspaceNdx < supportedColorSpaces.size(); ++colorspaceNdx)
500 	{
501 		const VkSwapchainCreateInfoKHR swapchainInfo = getBasicSwapchainParameters(params.wsiType,
502 																				   instHelper.vki,
503 																				   devHelper.physicalDevice,
504 																				   *surface,
505 																				   surfaceFormat,
506 																				   desiredSize,
507 																				   2,
508 																				   supportedColorSpaces[colorspaceNdx]);
509 		const Unique<VkSwapchainKHR>		swapchain			(createSwapchainKHR(vkd, device, &swapchainInfo));
510 		const vector<VkImage>				swapchainImages		= getSwapchainImages(vkd, device, *swapchain);
511 		const vector<VkExtensionProperties>	deviceExtensions	(enumerateDeviceExtensionProperties(instHelper.vki, devHelper.physicalDevice, DE_NULL));
512 
513 		const WsiTriangleRenderer renderer(vkd,
514 										   device,
515 										   allocator,
516 										   context.getBinaryCollection(),
517 										   true,
518 										   swapchainImages,
519 										   swapchainImages,
520 										   swapchainInfo.imageFormat,
521 										   tcu::UVec2(swapchainInfo.imageExtent.width, swapchainInfo.imageExtent.height));
522 
523 		const Move<VkCommandPool>	commandPool					(createCommandPool(vkd,
524 																				   device,
525 																				   VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,
526 																				   devHelper.queueFamilyIndex));
527 		const Move<VkSemaphore>		imageReadySemaphore			= createSemaphore(vkd, device);
528 		const Move<VkSemaphore>		renderingCompleteSemaphore	= createSemaphore(vkd, device);
529 		const Move<VkCommandBuffer>	commandBuffer				= allocateCommandBuffer(vkd,
530 																						device,
531 																						*commandPool,
532 																						VK_COMMAND_BUFFER_LEVEL_PRIMARY);
533 
534 		try
535 		{
536 			deUint32 imageNdx = ~0u;
537 
538 			{
539 				const VkResult acquireResult = vkd.acquireNextImageKHR(device,
540 																	   *swapchain,
541 																	   std::numeric_limits<deUint64>::max(),
542 																	   imageReadySemaphore.get(),
543 																	   DE_NULL,
544 																	   &imageNdx);
545 
546 				if (acquireResult == VK_SUBOPTIMAL_KHR)
547 				{
548 					context.getTestContext().getLog() << TestLog::Message << "Got " << acquireResult
549 													  << TestLog::EndMessage;
550 				}
551 				else
552 				{
553 					VK_CHECK(acquireResult);
554 				}
555 			}
556 
557 			TCU_CHECK((size_t) imageNdx < swapchainImages.size());
558 
559 			{
560 				const VkPipelineStageFlags waitDstStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
561 				const VkSubmitInfo submitInfo =
562 				{
563 					VK_STRUCTURE_TYPE_SUBMIT_INFO,
564 					DE_NULL,
565 					0u,
566 					&imageReadySemaphore.get(),
567 					&waitDstStage,
568 					1u,
569 					&commandBuffer.get(),
570 					1u,
571 					&renderingCompleteSemaphore.get()
572 				};
573 				const VkPresentInfoKHR presentInfo =
574 				{
575 					VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
576 					DE_NULL,
577 					1u,
578 					&renderingCompleteSemaphore.get(),
579 					1u,
580 					&swapchain.get(),
581 					&imageNdx,
582 					(VkResult *) DE_NULL
583 				};
584 
585 				renderer.recordFrame(commandBuffer.get(), imageNdx, 0);
586 				VK_CHECK(vkd.queueSubmit(devHelper.queue, 1u, &submitInfo, DE_NULL));
587 				VK_CHECK_WSI(vkd.queuePresentKHR(devHelper.queue, &presentInfo));
588 			}
589 
590 			// Set reference pixelBufferAccess for comparison.
591 			if (colorspaceNdx == 0)
592 			{
593 				referenceColorspacePixel = getPixel(vkd, device, devHelper.queue, commandPool.get(),
594 													allocator, desiredSize, textureFormat,
595 													&swapchainImages[imageNdx]);
596 				continue;
597 			}
598 
599 			// Compare pixels from images to make sure the colorspace makes no difference.
600 			if (referenceColorspacePixel == getPixel(vkd, device, devHelper.queue, commandPool.get(),
601 													 allocator, desiredSize, textureFormat,
602 													 &swapchainImages[imageNdx]))
603 				continue;
604 			else
605 			{
606 				VK_CHECK(vkd.deviceWaitIdle(device));
607 				return tcu::TestStatus::fail("Colorspace comparison test failed");
608 			}
609 		}
610 		catch (...)
611 		{
612 			// Make sure device is idle before destroying resources
613 			vkd.deviceWaitIdle(device);
614 			throw;
615 		}
616 	}
617 
618 	VK_CHECK(vkd.deviceWaitIdle(device));
619 	return tcu::TestStatus::pass("Colorspace comparison test succeeded");
620 }
621 
surfaceFormatRenderTest(Context & context,Type wsiType,const InstanceHelper & instHelper,const DeviceHelper & devHelper,VkSurfaceKHR surface,VkSurfaceFormatKHR curFmt,deBool checkHdr=false)622 tcu::TestStatus surfaceFormatRenderTest (Context& context,
623 										 Type wsiType,
624 										 const InstanceHelper& instHelper,
625 										 const DeviceHelper& devHelper,
626 										 VkSurfaceKHR surface,
627 										 VkSurfaceFormatKHR curFmt,
628 										 deBool checkHdr = false)
629 {
630 	const tcu::UVec2					desiredSize		(256, 256);
631 	const DeviceInterface&				vkd				= devHelper.vkd;
632 	const VkDevice						device			= *devHelper.device;
633 	SimpleAllocator						allocator		(vkd, device, getPhysicalDeviceMemoryProperties(instHelper.vki, devHelper.physicalDevice));
634 
635 	const VkSwapchainCreateInfoKHR		swapchainInfo			= getBasicSwapchainParameters(wsiType, instHelper.vki, devHelper.physicalDevice, surface, curFmt, desiredSize, 2);
636 	const Unique<VkSwapchainKHR>		swapchain				(createSwapchainKHR(vkd, device, &swapchainInfo));
637 	const vector<VkImage>				swapchainImages			= getSwapchainImages(vkd, device, *swapchain);
638 	const vector<VkExtensionProperties>	deviceExtensions		(enumerateDeviceExtensionProperties(instHelper.vki, devHelper.physicalDevice, DE_NULL));
639 
640 	if (checkHdr && !isExtensionStructSupported(deviceExtensions, RequiredExtension("VK_EXT_hdr_metadata")))
641 		TCU_THROW(NotSupportedError, "Extension VK_EXT_hdr_metadata not supported");
642 
643 	const WsiTriangleRenderer		renderer					(vkd,
644 																 device,
645 																 allocator,
646 																 context.getBinaryCollection(),
647 																 true,
648 																 swapchainImages,
649 																 swapchainImages,
650 																 swapchainInfo.imageFormat,
651 																 tcu::UVec2(swapchainInfo.imageExtent.width, swapchainInfo.imageExtent.height));
652 
653 	const Unique<VkCommandPool>		commandPool					(createCommandPool(vkd, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, devHelper.queueFamilyIndex));
654 
655 	const size_t					maxQueuedFrames				= swapchainImages.size()*2;
656 
657 	// We need to keep hold of fences from vkAcquireNextImageKHR to actually
658 	// limit number of frames we allow to be queued.
659 	const vector<FenceSp>			imageReadyFences			(createFences(vkd, device, maxQueuedFrames));
660 
661 	// We need maxQueuedFrames+1 for imageReadySemaphores pool as we need to pass
662 	// the semaphore in same time as the fence we use to meter rendering.
663 	const vector<SemaphoreSp>		imageReadySemaphores		(createSemaphores(vkd, device, maxQueuedFrames+1));
664 
665 	// For rest we simply need maxQueuedFrames as we will wait for image
666 	// from frameNdx-maxQueuedFrames to become available to us, guaranteeing that
667 	// previous uses must have completed.
668 	const vector<SemaphoreSp>		renderingCompleteSemaphores	(createSemaphores(vkd, device, maxQueuedFrames));
669 	const vector<CommandBufferSp>	commandBuffers				(allocateCommandBuffers(vkd, device, *commandPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY, maxQueuedFrames));
670 
671 	try
672 	{
673 		const deUint32	numFramesToRender	= 60;
674 
675 		for (deUint32 frameNdx = 0; frameNdx < numFramesToRender; ++frameNdx)
676 		{
677 			const VkFence		imageReadyFence		= **imageReadyFences[frameNdx%imageReadyFences.size()];
678 			const VkSemaphore	imageReadySemaphore	= **imageReadySemaphores[frameNdx%imageReadySemaphores.size()];
679 			deUint32			imageNdx			= ~0u;
680 
681 			if (frameNdx >= maxQueuedFrames)
682 				VK_CHECK(vkd.waitForFences(device, 1u, &imageReadyFence, VK_TRUE, std::numeric_limits<deUint64>::max()));
683 
684 			VK_CHECK(vkd.resetFences(device, 1, &imageReadyFence));
685 
686 			{
687 				const VkResult	acquireResult	= vkd.acquireNextImageKHR(device,
688 																		  *swapchain,
689 																		  std::numeric_limits<deUint64>::max(),
690 																		  imageReadySemaphore,
691 																		  (vk::VkFence)0,
692 																		  &imageNdx);
693 
694 				if (acquireResult == VK_SUBOPTIMAL_KHR)
695 					context.getTestContext().getLog() << TestLog::Message << "Got " << acquireResult << " at frame " << frameNdx << TestLog::EndMessage;
696 				else
697 					VK_CHECK(acquireResult);
698 			}
699 
700 			TCU_CHECK((size_t)imageNdx < swapchainImages.size());
701 
702 			{
703 				const VkSemaphore			renderingCompleteSemaphore	= **renderingCompleteSemaphores[frameNdx%renderingCompleteSemaphores.size()];
704 				const VkCommandBuffer		commandBuffer				= **commandBuffers[frameNdx%commandBuffers.size()];
705 				const VkPipelineStageFlags	waitDstStage				= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
706 				const VkSubmitInfo			submitInfo					=
707 				{
708 					VK_STRUCTURE_TYPE_SUBMIT_INFO,
709 					DE_NULL,
710 					1u,
711 					&imageReadySemaphore,
712 					&waitDstStage,
713 					1u,
714 					&commandBuffer,
715 					1u,
716 					&renderingCompleteSemaphore
717 				};
718 				const VkPresentInfoKHR		presentInfo					=
719 				{
720 					VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
721 					DE_NULL,
722 					1u,
723 					&renderingCompleteSemaphore,
724 					1u,
725 					&*swapchain,
726 					&imageNdx,
727 					(VkResult*)DE_NULL
728 				};
729 
730 				if (checkHdr) {
731 					const VkHdrMetadataEXT hdrData = {
732 							VK_STRUCTURE_TYPE_HDR_METADATA_EXT,
733 							DE_NULL,
734 							makeXYColorEXT(0.680f, 0.320f),
735 							makeXYColorEXT(0.265f, 0.690f),
736 							makeXYColorEXT(0.150f, 0.060f),
737 							makeXYColorEXT(0.3127f, 0.3290f),
738 							1000.0,
739 							0.0,
740 							1000.0,
741 							70.0
742 					};
743 					vector<VkSwapchainKHR> swapchainArray;
744 
745 					swapchainArray.push_back(*swapchain);
746 					vkd.setHdrMetadataEXT(device, (deUint32)swapchainArray.size(), swapchainArray.data(), &hdrData);
747 				}
748 
749 				renderer.recordFrame(commandBuffer, imageNdx, frameNdx);
750 				VK_CHECK(vkd.queueSubmit(devHelper.queue, 1u, &submitInfo, imageReadyFence));
751 				VK_CHECK_WSI(vkd.queuePresentKHR(devHelper.queue, &presentInfo));
752 			}
753 		}
754 
755 		VK_CHECK(vkd.deviceWaitIdle(device));
756 	}
757 	catch (...)
758 	{
759 		// Make sure device is idle before destroying resources
760 		vkd.deviceWaitIdle(device);
761 		throw;
762 	}
763 
764 	return tcu::TestStatus::pass("Rendering test succeeded");
765 }
766 
surfaceFormatRenderTests(Context & context,Type wsiType)767 tcu::TestStatus surfaceFormatRenderTests (Context& context, Type wsiType)
768 {
769 	const tcu::UVec2					desiredSize		(256, 256);
770 	const InstanceHelper				instHelper		(context, wsiType);
771 	const NativeObjects					native			(context, instHelper.supportedExtensions, wsiType, 1u, tcu::just(desiredSize));
772 	const Unique<VkSurfaceKHR>			surface			(createSurface(instHelper.vki, instHelper.instance, wsiType, native.getDisplay(), native.getWindow(), context.getTestContext().getCommandLine()));
773 	const DeviceHelper					devHelper		(context, instHelper.vki, instHelper.instance, *surface);
774 
775 	if (!de::contains(context.getInstanceExtensions().begin(), context.getInstanceExtensions().end(), "VK_EXT_swapchain_colorspace"))
776 		TCU_THROW(NotSupportedError, "Extension VK_EXT_swapchain_colorspace not supported");
777 
778 	const vector<VkSurfaceFormatKHR>	formats			= getPhysicalDeviceSurfaceFormats(instHelper.vki,
779 																							 devHelper.physicalDevice,
780 																							 *surface);
781 	for (vector<VkSurfaceFormatKHR>::const_iterator curFmt = formats.begin(); curFmt != formats.end(); ++curFmt)
782 	{
783 		surfaceFormatRenderTest(context, wsiType, instHelper, devHelper, *surface, *curFmt);
784 		context.getTestContext().touchWatchdog();
785 	}
786 	return tcu::TestStatus::pass("Rendering tests succeeded");
787 }
788 
surfaceFormatRenderWithHdrTests(Context & context,Type wsiType)789 tcu::TestStatus surfaceFormatRenderWithHdrTests (Context& context, Type wsiType)
790 {
791 	const tcu::UVec2					desiredSize		(256, 256);
792 	const InstanceHelper				instHelper		(context, wsiType);
793 	const NativeObjects					native			(context, instHelper.supportedExtensions, wsiType, 1u, tcu::just(desiredSize));
794 	const Unique<VkSurfaceKHR>			surface			(createSurface(instHelper.vki, instHelper.instance, wsiType, native.getDisplay(), native.getWindow(), context.getTestContext().getCommandLine()));
795 	const DeviceHelper					devHelper		(context, instHelper.vki, instHelper.instance, *surface);
796 
797 	if (!de::contains(context.getInstanceExtensions().begin(), context.getInstanceExtensions().end(), "VK_EXT_swapchain_colorspace"))
798 		TCU_THROW(NotSupportedError, "Extension VK_EXT_swapchain_colorspace not supported");
799 
800 	const vector<VkSurfaceFormatKHR>	formats			= getPhysicalDeviceSurfaceFormats(instHelper.vki,
801 																						  devHelper.physicalDevice,
802 																						  *surface);
803 	for (vector<VkSurfaceFormatKHR>::const_iterator curFmt = formats.begin(); curFmt != formats.end(); ++curFmt)
804 	{
805 		surfaceFormatRenderTest(context, wsiType, instHelper, devHelper, *surface, *curFmt, true);
806 		context.getTestContext().touchWatchdog();
807 	}
808 	return tcu::TestStatus::pass("Rendering tests succeeded");
809 }
810 
811 // We need different versions of this function in order to invoke
812 // different overloaded versions of addFunctionCaseWithPrograms.
getBasicRenderPrograms2(SourceCollections & dst,TestParams)813 void getBasicRenderPrograms2 (SourceCollections& dst, TestParams)
814 {
815 	WsiTriangleRenderer::getPrograms(dst);
816 }
817 
getBasicRenderPrograms(SourceCollections & dst,Type)818 void getBasicRenderPrograms (SourceCollections& dst, Type)
819 {
820 	WsiTriangleRenderer::getPrograms(dst);
821 }
822 } // anonymous
823 
createColorSpaceTests(tcu::TestCaseGroup * testGroup,vk::wsi::Type wsiType)824 void createColorSpaceTests (tcu::TestCaseGroup* testGroup, vk::wsi::Type wsiType)
825 {
826 	addFunctionCase(testGroup, "extensions", "Verify Colorspace Extensions", basicExtensionTest, wsiType);
827 	addFunctionCaseWithPrograms(testGroup, "basic", "Basic Rendering Tests", getBasicRenderPrograms, surfaceFormatRenderTests, wsiType);
828 	addFunctionCaseWithPrograms(testGroup, "hdr", "Basic Rendering Tests with HDR", getBasicRenderPrograms, surfaceFormatRenderWithHdrTests, wsiType);
829 }
830 
createColorspaceCompareTests(tcu::TestCaseGroup * testGroup,vk::wsi::Type wsiType)831 void createColorspaceCompareTests (tcu::TestCaseGroup* testGroup, vk::wsi::Type wsiType)
832 {
833 	const VkFormat formatList[] = {
834 									VK_FORMAT_B8G8R8A8_UNORM,
835 									VK_FORMAT_R8G8B8A8_UNORM,
836 									VK_FORMAT_R8G8B8A8_SRGB,
837 									VK_FORMAT_R5G6B5_UNORM_PACK16,
838 									VK_FORMAT_A2B10G10R10_UNORM_PACK32,
839 									VK_FORMAT_R16G16B16A16_SFLOAT
840 									};
841 
842 	// Create test for every format.
843 	for (const VkFormat& format : formatList)
844 	{
845 		const char* const	enumName	= getFormatName(format);
846 		const string		caseName	= de::toLower(string(enumName).substr(10));
847 		const TestParams params =
848 		{
849 			wsiType,
850 			format
851 		};
852 		addFunctionCaseWithPrograms(testGroup, caseName, "", getBasicRenderPrograms2, colorspaceCompareTest, params);
853 	}
854 }
855 
856 } // wsi
857 } // vkt
858