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