1 /*-------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2016 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 VkSurface Tests
22  *//*--------------------------------------------------------------------*/
23 
24 #include "vktWsiSurfaceTests.hpp"
25 
26 #include "vktTestCaseUtil.hpp"
27 #include "vktTestGroupUtil.hpp"
28 
29 #include "vkDefs.hpp"
30 #include "vkPlatform.hpp"
31 #include "vkStrUtil.hpp"
32 #include "vkRef.hpp"
33 #include "vkRefUtil.hpp"
34 #include "vkQueryUtil.hpp"
35 #include "vkMemUtil.hpp"
36 #include "vkDeviceUtil.hpp"
37 #include "vkPrograms.hpp"
38 #include "vkTypeUtil.hpp"
39 #include "vkWsiPlatform.hpp"
40 #include "vkWsiUtil.hpp"
41 #include "vkAllocationCallbackUtil.hpp"
42 #include "vkQueryUtil.hpp"
43 
44 #include "tcuTestLog.hpp"
45 #include "tcuFormatUtil.hpp"
46 #include "tcuPlatform.hpp"
47 #include "tcuResultCollector.hpp"
48 #include "tcuCommandLine.hpp"
49 
50 #include "deUniquePtr.hpp"
51 #include "deStringUtil.hpp"
52 #include "deMemory.h"
53 
54 namespace vk
55 {
56 
operator !=(const VkSurfaceFormatKHR & a,const VkSurfaceFormatKHR & b)57 inline bool operator!= (const VkSurfaceFormatKHR& a, const VkSurfaceFormatKHR& b)
58 {
59 	return (a.format != b.format) || (a.colorSpace != b.colorSpace);
60 }
61 
operator ==(const VkSurfaceFormatKHR & a,const VkSurfaceFormatKHR & b)62 inline bool operator== (const VkSurfaceFormatKHR& a, const VkSurfaceFormatKHR& b)
63 {
64 	return !(a != b);
65 }
66 
operator !=(const VkExtent2D & a,const VkExtent2D & b)67 inline bool operator!= (const VkExtent2D& a, const VkExtent2D& b)
68 {
69 	return (a.width != b.width) || (a.height != b.height);
70 }
71 
operator !=(const VkSurfaceCapabilitiesKHR & a,const VkSurfaceCapabilitiesKHR & b)72 inline bool operator!= (const VkSurfaceCapabilitiesKHR& a, const VkSurfaceCapabilitiesKHR& b)
73 {
74 	return (a.minImageCount				!= b.minImageCount)				||
75 		   (a.maxImageCount				!= b.maxImageCount)				||
76 		   (a.currentExtent				!= b.currentExtent)				||
77 		   (a.minImageExtent			!= b.minImageExtent)			||
78 		   (a.maxImageExtent			!= b.maxImageExtent)			||
79 		   (a.maxImageArrayLayers		!= b.maxImageArrayLayers)		||
80 		   (a.supportedTransforms		!= b.supportedTransforms)		||
81 		   (a.currentTransform			!= b.currentTransform)			||
82 		   (a.supportedCompositeAlpha	!= b.supportedCompositeAlpha)	||
83 		   (a.supportedUsageFlags		!= b.supportedUsageFlags);
84 }
85 
86 } // vk
87 
88 namespace vkt
89 {
90 namespace wsi
91 {
92 
93 namespace
94 {
95 
96 using namespace vk;
97 using namespace vk::wsi;
98 
99 using tcu::TestLog;
100 using tcu::Maybe;
101 using tcu::UVec2;
102 
103 using de::MovePtr;
104 using de::UniquePtr;
105 
106 using std::string;
107 using std::vector;
108 
109 enum
110 {
111 	SURFACE_EXTENT_DETERMINED_BY_SWAPCHAIN_MAGIC	= 0xffffffff
112 };
113 
114 enum
115 {
116 	GUARD_SIZE										= 0x20,			//!< Number of bytes to check
117 	GUARD_VALUE										= 0xcd,			//!< Data pattern
118 };
119 
120 template<typename T>
121 class CheckIncompleteResult
122 {
123 public:
~CheckIncompleteResult(void)124 	virtual			~CheckIncompleteResult	(void) {}
125 	virtual void	getResult				(const InstanceInterface& vki, const VkPhysicalDevice physDevice, const VkSurfaceKHR surface, T* data) = 0;
126 
operator ()(tcu::ResultCollector & results,const InstanceInterface & vki,const VkPhysicalDevice physDevice,const VkSurfaceKHR surface,const std::size_t expectedCompleteSize)127 	void operator() (tcu::ResultCollector&		results,
128 					 const InstanceInterface&	vki,
129 					 const VkPhysicalDevice		physDevice,
130 					 const VkSurfaceKHR			surface,
131 					 const std::size_t			expectedCompleteSize)
132 	{
133 		if (expectedCompleteSize == 0)
134 			return;
135 
136 		vector<T>		outputData	(expectedCompleteSize);
137 		const deUint32	usedSize	= static_cast<deUint32>(expectedCompleteSize / 3);
138 
139 		ValidateQueryBits::fillBits(outputData.begin(), outputData.end());	// unused entries should have this pattern intact
140 		m_count		= usedSize;
141 		m_result	= VK_SUCCESS;
142 
143 		getResult(vki, physDevice, surface, &outputData[0]);				// update m_count and m_result
144 
145 		if (m_count != usedSize || m_result != VK_INCOMPLETE || !ValidateQueryBits::checkBits(outputData.begin() + m_count, outputData.end()))
146 			results.fail("Query didn't return VK_INCOMPLETE");
147 	}
148 
149 protected:
150 	deUint32	m_count;
151 	VkResult	m_result;
152 };
153 
154 struct CheckPhysicalDeviceSurfaceFormatsIncompleteResult : public CheckIncompleteResult<VkSurfaceFormatKHR>
155 {
getResultvkt::wsi::__anon1d6584650111::CheckPhysicalDeviceSurfaceFormatsIncompleteResult156 	void getResult (const InstanceInterface& vki, const VkPhysicalDevice physDevice, const VkSurfaceKHR surface, VkSurfaceFormatKHR* data)
157 	{
158 		m_result = vki.getPhysicalDeviceSurfaceFormatsKHR(physDevice, surface, &m_count, data);
159 	}
160 };
161 
162 struct CheckPhysicalDeviceSurfacePresentModesIncompleteResult : public CheckIncompleteResult<VkPresentModeKHR>
163 {
getResultvkt::wsi::__anon1d6584650111::CheckPhysicalDeviceSurfacePresentModesIncompleteResult164 	void getResult (const InstanceInterface& vki, const VkPhysicalDevice physDevice, const VkSurfaceKHR surface, VkPresentModeKHR* data)
165 	{
166 		m_result = vki.getPhysicalDeviceSurfacePresentModesKHR(physDevice, surface, &m_count, data);
167 	}
168 };
169 
170 typedef vector<VkExtensionProperties> Extensions;
171 
createInstanceWithWsi(const PlatformInterface & vkp,deUint32 version,const Extensions & supportedExtensions,Type wsiType,const vector<string> extraExtensions,const VkAllocationCallbacks * pAllocator=DE_NULL)172 Move<VkInstance> createInstanceWithWsi (const PlatformInterface&		vkp,
173 										deUint32						version,
174 										const Extensions&				supportedExtensions,
175 										Type							wsiType,
176 										const vector<string>			extraExtensions,
177 										const VkAllocationCallbacks*	pAllocator	= DE_NULL)
178 {
179 	vector<string>	extensions = extraExtensions;
180 
181 	extensions.push_back("VK_KHR_surface");
182 	extensions.push_back(getExtensionName(wsiType));
183 
184 	vector<string>	instanceExtensions;
185 
186 	for (vector<string>::const_iterator extensionName = extensions.begin();
187 		 extensionName != extensions.end();
188 		 ++extensionName)
189 	{
190 		if (!isInstanceExtensionSupported(version, supportedExtensions, RequiredExtension(*extensionName)))
191 			TCU_THROW(NotSupportedError, (*extensionName + " is not supported").c_str());
192 
193 		if (!isCoreInstanceExtension(version, *extensionName))
194 			instanceExtensions.push_back(*extensionName);
195 	}
196 
197 	return vk::createDefaultInstance(vkp, version, vector<string>(), instanceExtensions, pAllocator);
198 }
199 
200 struct InstanceHelper
201 {
202 	const vector<VkExtensionProperties>	supportedExtensions;
203 	Unique<VkInstance>					instance;
204 	const InstanceDriver				vki;
205 
InstanceHelpervkt::wsi::__anon1d6584650111::InstanceHelper206 	InstanceHelper (Context& context, Type wsiType, const VkAllocationCallbacks* pAllocator = DE_NULL)
207 		: supportedExtensions	(enumerateInstanceExtensionProperties(context.getPlatformInterface(),
208 																	  DE_NULL))
209 		, instance				(createInstanceWithWsi(context.getPlatformInterface(),
210 													   context.getUsedApiVersion(),
211 													   supportedExtensions,
212 													   wsiType,
213 													   vector<string>(),
214 													   pAllocator))
215 		, vki					(context.getPlatformInterface(), *instance)
216 	{}
217 
InstanceHelpervkt::wsi::__anon1d6584650111::InstanceHelper218 	InstanceHelper (Context& context, Type wsiType, const vector<string>& extensions, const VkAllocationCallbacks* pAllocator = DE_NULL)
219 		: supportedExtensions	(enumerateInstanceExtensionProperties(context.getPlatformInterface(),
220 																	  DE_NULL))
221 		, instance				(createInstanceWithWsi(context.getPlatformInterface(),
222 													   context.getUsedApiVersion(),
223 													   supportedExtensions,
224 													   wsiType,
225 													   extensions,
226 													   pAllocator))
227 		, vki					(context.getPlatformInterface(), *instance)
228 	{}
229 };
230 
createDisplay(const vk::Platform & platform,const Extensions & supportedExtensions,Type wsiType)231 MovePtr<Display> createDisplay (const vk::Platform&	platform,
232 								const Extensions&	supportedExtensions,
233 								Type				wsiType)
234 {
235 	try
236 	{
237 		return MovePtr<Display>(platform.createWsiDisplay(wsiType));
238 	}
239 	catch (const tcu::NotSupportedError& e)
240 	{
241 		if (isExtensionSupported(supportedExtensions, RequiredExtension(getExtensionName(wsiType))) &&
242 		    platform.hasDisplay(wsiType))
243 		{
244 			// If VK_KHR_{platform}_surface was supported, vk::Platform implementation
245 			// must support creating native display & window for that WSI type.
246 			throw tcu::TestError(e.getMessage());
247 		}
248 		else
249 			throw;
250 	}
251 }
252 
createWindow(const Display & display,const Maybe<UVec2> & initialSize)253 MovePtr<Window> createWindow (const Display& display, const Maybe<UVec2>& initialSize)
254 {
255 	try
256 	{
257 		return MovePtr<Window>(display.createWindow(initialSize));
258 	}
259 	catch (const tcu::NotSupportedError& e)
260 	{
261 		// See createDisplay - assuming that wsi::Display was supported platform port
262 		// should also support creating a window.
263 		throw tcu::TestError(e.getMessage());
264 	}
265 }
266 
267 struct NativeObjects
268 {
269 	const UniquePtr<Display>	display;
270 	const UniquePtr<Window>		window;
271 
NativeObjectsvkt::wsi::__anon1d6584650111::NativeObjects272 	NativeObjects (Context&				context,
273 				   const Extensions&	supportedExtensions,
274 				   Type					wsiType,
275 				   const Maybe<UVec2>&	initialWindowSize = tcu::nothing<UVec2>())
276 		: display	(createDisplay(context.getTestContext().getPlatform().getVulkanPlatform(), supportedExtensions, wsiType))
277 		, window	(createWindow(*display, initialWindowSize))
278 	{}
279 };
280 
createSurfaceTest(Context & context,Type wsiType)281 tcu::TestStatus createSurfaceTest (Context& context, Type wsiType)
282 {
283 	const InstanceHelper		instHelper	(context, wsiType);
284 	const NativeObjects			native		(context, instHelper.supportedExtensions, wsiType);
285 	const Unique<VkSurfaceKHR>	surface		(createSurface(instHelper.vki, *instHelper.instance, wsiType, *native.display, *native.window));
286 
287 	return tcu::TestStatus::pass("Creating surface succeeded");
288 }
289 
createSurfaceCustomAllocatorTest(Context & context,Type wsiType)290 tcu::TestStatus createSurfaceCustomAllocatorTest (Context& context, Type wsiType)
291 {
292 	AllocationCallbackRecorder	allocationRecorder	(getSystemAllocator());
293 	tcu::TestLog&				log					= context.getTestContext().getLog();
294 
295 	{
296 		const InstanceHelper		instHelper	(context, wsiType, allocationRecorder.getCallbacks());
297 		const NativeObjects			native		(context, instHelper.supportedExtensions, wsiType);
298 		const Unique<VkSurfaceKHR>	surface		(createSurface(instHelper.vki,
299 															   *instHelper.instance,
300 															   wsiType,
301 															   *native.display,
302 															   *native.window,
303 															   allocationRecorder.getCallbacks()));
304 
305 		if (!validateAndLog(log,
306 							allocationRecorder,
307 							(1u<<VK_SYSTEM_ALLOCATION_SCOPE_OBJECT)		|
308 							(1u<<VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE)))
309 			return tcu::TestStatus::fail("Detected invalid system allocation callback");
310 	}
311 
312 	if (!validateAndLog(log, allocationRecorder, 0u))
313 		return tcu::TestStatus::fail("Detected invalid system allocation callback");
314 
315 	if (allocationRecorder.getRecordsBegin() == allocationRecorder.getRecordsEnd())
316 		return tcu::TestStatus(QP_TEST_RESULT_QUALITY_WARNING, "Allocation callbacks were not used");
317 	else
318 		return tcu::TestStatus::pass("Creating surface succeeded using custom allocator");
319 }
320 
createSurfaceSimulateOOMTest(Context & context,Type wsiType)321 tcu::TestStatus createSurfaceSimulateOOMTest (Context& context, Type wsiType)
322 {
323 	tcu::TestLog&	log	= context.getTestContext().getLog();
324 
325 	for (deUint32 numPassingAllocs = 0; numPassingAllocs <= 1024u; ++numPassingAllocs)
326 	{
327 		AllocationCallbackRecorder	allocationRecorder	(getSystemAllocator());
328 		DeterministicFailAllocator	failingAllocator	(allocationRecorder.getCallbacks(),
329 														 DeterministicFailAllocator::MODE_DO_NOT_COUNT,
330 														 0);
331 		bool						gotOOM				= false;
332 
333 		log << TestLog::Message << "Testing with " << numPassingAllocs << " first allocations succeeding" << TestLog::EndMessage;
334 
335 		try
336 		{
337 			const InstanceHelper		instHelper	(context, wsiType, failingAllocator.getCallbacks());
338 
339 			// OOM is not simulated for VkInstance as we don't want to spend time
340 			// testing OOM paths inside instance creation.
341 			failingAllocator.reset(DeterministicFailAllocator::MODE_COUNT_AND_FAIL, numPassingAllocs);
342 
343 			const NativeObjects			native		(context, instHelper.supportedExtensions, wsiType);
344 			const Unique<VkSurfaceKHR>	surface		(createSurface(instHelper.vki,
345 																   *instHelper.instance,
346 																   wsiType,
347 																   *native.display,
348 																   *native.window,
349 																   failingAllocator.getCallbacks()));
350 
351 			if (!validateAndLog(log,
352 								allocationRecorder,
353 								(1u<<VK_SYSTEM_ALLOCATION_SCOPE_OBJECT)		|
354 								(1u<<VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE)))
355 				return tcu::TestStatus::fail("Detected invalid system allocation callback");
356 		}
357 		catch (const OutOfMemoryError& e)
358 		{
359 			log << TestLog::Message << "Got " << e.getError() << TestLog::EndMessage;
360 			gotOOM = true;
361 		}
362 
363 		if (!validateAndLog(log, allocationRecorder, 0u))
364 			return tcu::TestStatus::fail("Detected invalid system allocation callback");
365 
366 		if (!gotOOM)
367 		{
368 			log << TestLog::Message << "Creating surface succeeded!" << TestLog::EndMessage;
369 
370 			if (numPassingAllocs == 0)
371 				return tcu::TestStatus(QP_TEST_RESULT_QUALITY_WARNING, "Allocation callbacks were not used");
372 			else
373 				return tcu::TestStatus::pass("OOM simulation completed");
374 		}
375 	}
376 
377 	return tcu::TestStatus(QP_TEST_RESULT_QUALITY_WARNING, "Creating surface did not succeed, callback limit exceeded");
378 }
379 
getNumQueueFamilies(const InstanceInterface & vki,VkPhysicalDevice physicalDevice)380 deUint32 getNumQueueFamilies (const InstanceInterface& vki, VkPhysicalDevice physicalDevice)
381 {
382 	deUint32	numFamilies		= 0;
383 
384 	vki.getPhysicalDeviceQueueFamilyProperties(physicalDevice, &numFamilies, DE_NULL);
385 
386 	return numFamilies;
387 }
388 
querySurfaceSupportTest(Context & context,Type wsiType)389 tcu::TestStatus querySurfaceSupportTest (Context& context, Type wsiType)
390 {
391 	tcu::TestLog&					log						= context.getTestContext().getLog();
392 	tcu::ResultCollector			results					(log);
393 
394 	const InstanceHelper			instHelper				(context, wsiType);
395 	const NativeObjects				native					(context, instHelper.supportedExtensions, wsiType);
396 	const Unique<VkSurfaceKHR>		surface					(createSurface(instHelper.vki, *instHelper.instance, wsiType, *native.display, *native.window));
397 	const vector<VkPhysicalDevice>	physicalDevices			= enumeratePhysicalDevices(instHelper.vki, *instHelper.instance);
398 
399 	// On Android surface must be supported by all devices and queue families
400 	const bool						expectSupportedOnAll	= wsiType == TYPE_ANDROID;
401 
402 	for (size_t deviceNdx = 0; deviceNdx < physicalDevices.size(); ++deviceNdx)
403 	{
404 		const VkPhysicalDevice		physicalDevice		= physicalDevices[deviceNdx];
405 		const deUint32				numQueueFamilies	= getNumQueueFamilies(instHelper.vki, physicalDevice);
406 
407 		for (deUint32 queueFamilyNdx = 0; queueFamilyNdx < numQueueFamilies; ++queueFamilyNdx)
408 		{
409 			const VkBool32	isSupported		= getPhysicalDeviceSurfaceSupport(instHelper.vki, physicalDevice, queueFamilyNdx, *surface);
410 
411 			log << TestLog::Message << "Device " << deviceNdx << ", queue family " << queueFamilyNdx << ": "
412 									<< (isSupported == VK_FALSE ? "NOT " : "") << "supported"
413 				<< TestLog::EndMessage;
414 
415 			if (expectSupportedOnAll && !isSupported)
416 				results.fail("Surface must be supported by all devices and queue families");
417 		}
418 	}
419 
420 	return tcu::TestStatus(results.getResult(), results.getMessage());
421 }
422 
isSupportedByAnyQueue(const InstanceInterface & vki,VkPhysicalDevice physicalDevice,VkSurfaceKHR surface)423 bool isSupportedByAnyQueue (const InstanceInterface& vki, VkPhysicalDevice physicalDevice, VkSurfaceKHR surface)
424 {
425 	const deUint32	numQueueFamilies	= getNumQueueFamilies(vki, physicalDevice);
426 
427 	for (deUint32 queueFamilyNdx = 0; queueFamilyNdx < numQueueFamilies; ++queueFamilyNdx)
428 	{
429 		if (getPhysicalDeviceSurfaceSupport(vki, physicalDevice, queueFamilyNdx, surface) != VK_FALSE)
430 			return true;
431 	}
432 
433 	return false;
434 }
435 
validateSurfaceCapabilities(tcu::ResultCollector & results,const VkSurfaceCapabilitiesKHR & capabilities)436 void validateSurfaceCapabilities (tcu::ResultCollector& results, const VkSurfaceCapabilitiesKHR& capabilities)
437 {
438 	results.check(capabilities.minImageCount > 0,
439 				  "minImageCount must be larger than 0");
440 
441 	results.check(capabilities.minImageExtent.width > 0 &&
442 				  capabilities.minImageExtent.height > 0,
443 				  "minImageExtent dimensions must be larger than 0");
444 
445 	results.check(capabilities.maxImageExtent.width > 0 &&
446 				  capabilities.maxImageExtent.height > 0,
447 				  "maxImageExtent dimensions must be larger than 0");
448 
449 	results.check(capabilities.minImageExtent.width <= capabilities.maxImageExtent.width &&
450 				  capabilities.minImageExtent.height <= capabilities.maxImageExtent.height,
451 				  "maxImageExtent must be larger or equal to minImageExtent");
452 
453 	if (capabilities.currentExtent.width != SURFACE_EXTENT_DETERMINED_BY_SWAPCHAIN_MAGIC ||
454 		capabilities.currentExtent.height != SURFACE_EXTENT_DETERMINED_BY_SWAPCHAIN_MAGIC)
455 	{
456 		results.check(capabilities.currentExtent.width > 0 &&
457 					  capabilities.currentExtent.height > 0,
458 					  "currentExtent dimensions must be larger than 0");
459 
460 		results.check(de::inRange(capabilities.currentExtent.width, capabilities.minImageExtent.width, capabilities.maxImageExtent.width) &&
461 					  de::inRange(capabilities.currentExtent.height, capabilities.minImageExtent.height, capabilities.maxImageExtent.height),
462 					  "currentExtent is not in supported extent limits");
463 	}
464 
465 	results.check(capabilities.maxImageArrayLayers > 0,
466 				  "maxImageArrayLayers must be larger than 0");
467 
468 	results.check((capabilities.supportedUsageFlags & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) != 0,
469 				  "VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT must be set in supportedUsageFlags");
470 
471 	results.check(capabilities.supportedTransforms != 0,
472 				  "At least one transform must be supported");
473 
474 	results.check(dePop32(capabilities.currentTransform) != 0,
475 				  "Invalid currentTransform");
476 
477 	results.check((capabilities.supportedTransforms & capabilities.currentTransform) != 0,
478 				  "currentTransform is not supported by surface");
479 
480 	results.check(capabilities.supportedCompositeAlpha != 0,
481 				  "At least one alpha mode must be supported");
482 }
483 
querySurfaceCapabilitiesTest(Context & context,Type wsiType)484 tcu::TestStatus querySurfaceCapabilitiesTest (Context& context, Type wsiType)
485 {
486 	tcu::TestLog&					log						= context.getTestContext().getLog();
487 	tcu::ResultCollector			results					(log);
488 
489 	const InstanceHelper			instHelper				(context, wsiType);
490 	const NativeObjects				native					(context, instHelper.supportedExtensions, wsiType);
491 	const Unique<VkSurfaceKHR>		surface					(createSurface(instHelper.vki, *instHelper.instance, wsiType, *native.display, *native.window));
492 	const vector<VkPhysicalDevice>	physicalDevices			= enumeratePhysicalDevices(instHelper.vki, *instHelper.instance);
493 
494 	for (size_t deviceNdx = 0; deviceNdx < physicalDevices.size(); ++deviceNdx)
495 	{
496 		if (isSupportedByAnyQueue(instHelper.vki, physicalDevices[deviceNdx], *surface))
497 		{
498 			const VkSurfaceCapabilitiesKHR	capabilities	= getPhysicalDeviceSurfaceCapabilities(instHelper.vki,
499 																								   physicalDevices[deviceNdx],
500 																								   *surface);
501 
502 			log << TestLog::Message << "Device " << deviceNdx << ": " << capabilities << TestLog::EndMessage;
503 
504 			validateSurfaceCapabilities(results, capabilities);
505 		}
506 		// else skip query as surface is not supported by the device
507 	}
508 
509 	return tcu::TestStatus(results.getResult(), results.getMessage());
510 }
511 
querySurfaceCapabilities2Test(Context & context,Type wsiType)512 tcu::TestStatus querySurfaceCapabilities2Test (Context& context, Type wsiType)
513 {
514 	tcu::TestLog&					log						= context.getTestContext().getLog();
515 	tcu::ResultCollector			results					(log);
516 
517 	const InstanceHelper			instHelper				(context, wsiType, vector<string>(1, string("VK_KHR_get_surface_capabilities2")));
518 	const NativeObjects				native					(context, instHelper.supportedExtensions, wsiType);
519 	const Unique<VkSurfaceKHR>		surface					(createSurface(instHelper.vki, *instHelper.instance, wsiType, *native.display, *native.window));
520 	const vector<VkPhysicalDevice>	physicalDevices			= enumeratePhysicalDevices(instHelper.vki, *instHelper.instance);
521 
522 	for (size_t deviceNdx = 0; deviceNdx < physicalDevices.size(); ++deviceNdx)
523 	{
524 		if (isSupportedByAnyQueue(instHelper.vki, physicalDevices[deviceNdx], *surface))
525 		{
526 			const VkSurfaceCapabilitiesKHR	refCapabilities	= getPhysicalDeviceSurfaceCapabilities(instHelper.vki,
527 																								   physicalDevices[deviceNdx],
528 																								   *surface);
529 			VkSurfaceCapabilities2KHR		extCapabilities;
530 
531 			deMemset(&extCapabilities, 0xcd, sizeof(VkSurfaceCapabilities2KHR));
532 			extCapabilities.sType	= VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR;
533 			extCapabilities.pNext	= DE_NULL;
534 
535 			{
536 				const VkPhysicalDeviceSurfaceInfo2KHR	surfaceInfo	=
537 				{
538 					VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SURFACE_INFO_2_KHR,
539 					DE_NULL,
540 					*surface
541 				};
542 				VkPhysicalDeviceSurfaceInfo2KHR			infoCopy;
543 
544 				deMemcpy(&infoCopy, &surfaceInfo, sizeof(VkPhysicalDeviceSurfaceInfo2KHR));
545 
546 				VK_CHECK(instHelper.vki.getPhysicalDeviceSurfaceCapabilities2KHR(physicalDevices[deviceNdx], &surfaceInfo, &extCapabilities));
547 
548 				results.check(deMemoryEqual(&surfaceInfo, &infoCopy, sizeof(VkPhysicalDeviceSurfaceInfo2KHR)) == DE_TRUE, "Driver wrote into input struct");
549 			}
550 
551 			results.check(extCapabilities.sType == VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR &&
552 						  extCapabilities.pNext == DE_NULL,
553 						  "sType/pNext modified");
554 
555 			if (refCapabilities != extCapabilities.surfaceCapabilities)
556 			{
557 				log << TestLog::Message
558 					<< "Device " << deviceNdx
559 					<< ": expected " << refCapabilities
560 					<< ", got " << extCapabilities.surfaceCapabilities
561 					<< TestLog::EndMessage;
562 				results.fail("Mismatch between VK_KHR_surface and VK_KHR_surface2 query results");
563 			}
564 		}
565 	}
566 
567 	return tcu::TestStatus(results.getResult(), results.getMessage());
568 }
569 
querySurfaceProtectedCapabilitiesTest(Context & context,Type wsiType)570 tcu::TestStatus querySurfaceProtectedCapabilitiesTest (Context& context, Type wsiType)
571 {
572 	tcu::TestLog&			log			= context.getTestContext().getLog();
573 	tcu::ResultCollector		results			(log);
574 
575 	vector<string>			requiredExtensions;
576 	requiredExtensions.push_back("VK_KHR_get_surface_capabilities2");
577 	requiredExtensions.push_back("VK_KHR_surface_protected_capabilities");
578 	const InstanceHelper		instHelper		(context, wsiType, requiredExtensions);
579 	const NativeObjects		native			(context, instHelper.supportedExtensions, wsiType);
580 	const Unique<VkSurfaceKHR>	surface			(createSurface(instHelper.vki, *instHelper.instance, wsiType, *native.display, *native.window));
581 	const vector<VkPhysicalDevice>	physicalDevices		= enumeratePhysicalDevices(instHelper.vki, *instHelper.instance);
582 
583 	for (size_t deviceNdx = 0; deviceNdx < physicalDevices.size(); ++deviceNdx)
584 	{
585 		if (isSupportedByAnyQueue(instHelper.vki, physicalDevices[deviceNdx], *surface))
586 		{
587 			VkSurfaceCapabilities2KHR		extCapabilities;
588 			VkSurfaceProtectedCapabilitiesKHR	extProtectedCapabilities;
589 
590 			deMemset(&extProtectedCapabilities, 0xcd, sizeof(VkSurfaceProtectedCapabilitiesKHR));
591 			extProtectedCapabilities.sType		= VK_STRUCTURE_TYPE_SURFACE_PROTECTED_CAPABILITIES_KHR;
592 			extProtectedCapabilities.pNext		= DE_NULL;
593 
594 			deMemset(&extCapabilities, 0xcd, sizeof(VkSurfaceCapabilities2KHR));
595 			extCapabilities.sType	= VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR;
596 			extCapabilities.pNext	= &extProtectedCapabilities;
597 
598 			{
599 				VkPhysicalDeviceSurfaceInfo2KHR		infoCopy;
600 				const VkPhysicalDeviceSurfaceInfo2KHR	surfaceInfo =
601 				{
602 					VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SURFACE_INFO_2_KHR,
603 					DE_NULL,
604 					*surface
605 				};
606 
607 
608 				deMemcpy(&infoCopy, &surfaceInfo, sizeof(VkPhysicalDeviceSurfaceInfo2KHR));
609 
610 				VK_CHECK(instHelper.vki.getPhysicalDeviceSurfaceCapabilities2KHR(physicalDevices[deviceNdx], &surfaceInfo, &extCapabilities));
611 
612 				results.check(deMemoryEqual(&surfaceInfo, &infoCopy, sizeof(VkPhysicalDeviceSurfaceInfo2KHR)) == DE_TRUE, "Driver wrote into input struct");
613 			}
614 
615 			results.check(extCapabilities.sType == VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR &&
616 					extCapabilities.pNext == &extProtectedCapabilities,
617 					"sType/pNext modified");
618 
619 			results.check(extProtectedCapabilities.sType == VK_STRUCTURE_TYPE_SURFACE_PROTECTED_CAPABILITIES_KHR &&
620 					extProtectedCapabilities.pNext == DE_NULL,
621 					"sType/pNext modified");
622 
623 			results.check(extProtectedCapabilities.supportsProtected == 0 ||
624 					extProtectedCapabilities.supportsProtected == 1,
625 					"supportsProtected ");
626 		}
627 	}
628 
629 	return tcu::TestStatus(results.getResult(), results.getMessage());
630 }
631 
validateSurfaceFormats(tcu::ResultCollector & results,Type wsiType,const vector<VkSurfaceFormatKHR> & formats)632 void validateSurfaceFormats (tcu::ResultCollector& results, Type wsiType, const vector<VkSurfaceFormatKHR>& formats)
633 {
634 	const VkSurfaceFormatKHR*	requiredFormats		= DE_NULL;
635 	size_t						numRequiredFormats	= 0;
636 
637 	if (wsiType == TYPE_ANDROID)
638 	{
639 		static const VkSurfaceFormatKHR s_androidFormats[] =
640 		{
641 			{ VK_FORMAT_R8G8B8A8_UNORM,			VK_COLOR_SPACE_SRGB_NONLINEAR_KHR	},
642 			{ VK_FORMAT_R8G8B8A8_SRGB,			VK_COLOR_SPACE_SRGB_NONLINEAR_KHR	},
643 			{ VK_FORMAT_R5G6B5_UNORM_PACK16,	VK_COLOR_SPACE_SRGB_NONLINEAR_KHR	}
644 		};
645 
646 		requiredFormats		= &s_androidFormats[0];
647 		numRequiredFormats	= DE_LENGTH_OF_ARRAY(s_androidFormats);
648 	}
649 
650 	for (size_t ndx = 0; ndx < numRequiredFormats; ++ndx)
651 	{
652 		const VkSurfaceFormatKHR&	requiredFormat	= requiredFormats[ndx];
653 
654 		if (!de::contains(formats.begin(), formats.end(), requiredFormat))
655 			results.fail(de::toString(requiredFormat) + " not supported");
656 	}
657 
658 	// Check that there are no duplicates
659 	for (size_t ndx = 1; ndx < formats.size(); ++ndx)
660 	{
661 		if (de::contains(formats.begin(), formats.begin() + ndx, formats[ndx]))
662 			results.fail("Found duplicate entry " + de::toString(formats[ndx]));
663 	}
664 }
665 
querySurfaceFormatsTest(Context & context,Type wsiType)666 tcu::TestStatus querySurfaceFormatsTest (Context& context, Type wsiType)
667 {
668 	tcu::TestLog&					log				= context.getTestContext().getLog();
669 	tcu::ResultCollector			results			(log);
670 
671 	const InstanceHelper			instHelper		(context, wsiType);
672 	const NativeObjects				native			(context, instHelper.supportedExtensions, wsiType);
673 	const Unique<VkSurfaceKHR>		surface			(createSurface(instHelper.vki, *instHelper.instance, wsiType, *native.display, *native.window));
674 	const vector<VkPhysicalDevice>	physicalDevices	= enumeratePhysicalDevices(instHelper.vki, *instHelper.instance);
675 
676 	for (size_t deviceNdx = 0; deviceNdx < physicalDevices.size(); ++deviceNdx)
677 	{
678 		if (isSupportedByAnyQueue(instHelper.vki, physicalDevices[deviceNdx], *surface))
679 		{
680 			deUint32	numFormats = 0;
681 
682 			VK_CHECK(instHelper.vki.getPhysicalDeviceSurfaceFormatsKHR(physicalDevices[deviceNdx], *surface, &numFormats, DE_NULL));
683 
684 			std::vector<VkSurfaceFormatKHR>	formats	(numFormats + 1);
685 
686 			if (numFormats > 0)
687 			{
688 				const deUint32 numFormatsOrig = numFormats;
689 
690 				// check if below call properly overwrites formats count
691 				numFormats++;
692 
693 				VK_CHECK(instHelper.vki.getPhysicalDeviceSurfaceFormatsKHR(physicalDevices[deviceNdx], *surface, &numFormats, &formats[0]));
694 
695 				if (numFormats != numFormatsOrig)
696 					results.fail("Format count changed between calls");
697 			}
698 
699 			formats.pop_back();
700 
701 			log << TestLog::Message << "Device " << deviceNdx << ": " << tcu::formatArray(formats.begin(), formats.end()) << TestLog::EndMessage;
702 
703 			validateSurfaceFormats(results, wsiType, formats);
704 			CheckPhysicalDeviceSurfaceFormatsIncompleteResult()(results, instHelper.vki, physicalDevices[deviceNdx], *surface, formats.size());
705 		}
706 		// else skip query as surface is not supported by the device
707 	}
708 
709 	return tcu::TestStatus(results.getResult(), results.getMessage());
710 }
711 
querySurfaceFormats2Test(Context & context,Type wsiType)712 tcu::TestStatus querySurfaceFormats2Test (Context& context, Type wsiType)
713 {
714 	tcu::TestLog&					log				= context.getTestContext().getLog();
715 	tcu::ResultCollector			results			(log);
716 
717 	const InstanceHelper			instHelper		(context, wsiType, vector<string>(1, string("VK_KHR_get_surface_capabilities2")));
718 	const NativeObjects				native			(context, instHelper.supportedExtensions, wsiType);
719 	const Unique<VkSurfaceKHR>		surface			(createSurface(instHelper.vki, *instHelper.instance, wsiType, *native.display, *native.window));
720 	const vector<VkPhysicalDevice>	physicalDevices	= enumeratePhysicalDevices(instHelper.vki, *instHelper.instance);
721 
722 	for (size_t deviceNdx = 0; deviceNdx < physicalDevices.size(); ++deviceNdx)
723 	{
724 		if (isSupportedByAnyQueue(instHelper.vki, physicalDevices[deviceNdx], *surface))
725 		{
726 			const vector<VkSurfaceFormatKHR>		refFormats	= getPhysicalDeviceSurfaceFormats(instHelper.vki,
727 																								  physicalDevices[deviceNdx],
728 																								  *surface);
729 			const VkPhysicalDeviceSurfaceInfo2KHR	surfaceInfo	=
730 			{
731 				VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SURFACE_INFO_2_KHR,
732 				DE_NULL,
733 				*surface
734 			};
735 			deUint32								numFormats	= 0;
736 
737 			VK_CHECK(instHelper.vki.getPhysicalDeviceSurfaceFormats2KHR(physicalDevices[deviceNdx], &surfaceInfo, &numFormats, DE_NULL));
738 
739 			if ((size_t)numFormats != refFormats.size())
740 				results.fail("vkGetPhysicalDeviceSurfaceFormats2KHR() returned different number of formats");
741 
742 			if (numFormats > 0)
743 			{
744 				vector<VkSurfaceFormat2KHR>	formats	(numFormats + 1);
745 
746 				for (size_t ndx = 0; ndx < formats.size(); ++ndx)
747 				{
748 					formats[ndx].sType = VK_STRUCTURE_TYPE_SURFACE_FORMAT_2_KHR;
749 					formats[ndx].pNext = DE_NULL;
750 				}
751 
752 				const deUint32 numFormatsOrig = numFormats;
753 
754 				// check if below call properly overwrites formats count
755 				numFormats++;
756 
757 				VK_CHECK(instHelper.vki.getPhysicalDeviceSurfaceFormats2KHR(physicalDevices[deviceNdx], &surfaceInfo, &numFormats, &formats[0]));
758 
759 				if ((size_t)numFormats != numFormatsOrig)
760 					results.fail("Format count changed between calls");
761 
762 				formats.pop_back();
763 
764 				{
765 					vector<VkSurfaceFormatKHR>	extFormats	(formats.size());
766 
767 					for (size_t ndx = 0; ndx < formats.size(); ++ndx)
768 					{
769 						results.check(formats[ndx].sType == VK_STRUCTURE_TYPE_SURFACE_FORMAT_2_KHR &&
770 									  formats[ndx].pNext == DE_NULL,
771 									  "sType/pNext modified");
772 						extFormats[ndx] = formats[ndx].surfaceFormat;
773 					}
774 
775 					for (size_t ndx = 0; ndx < refFormats.size(); ++ndx)
776 					{
777 						if (!de::contains(extFormats.begin(), extFormats.end(), refFormats[ndx]))
778 							results.fail(de::toString(refFormats[ndx]) + " missing from extended query");
779 					}
780 				}
781 
782 				// Check VK_INCOMPLETE
783 				{
784 					vector<VkSurfaceFormat2KHR>	formatsClone	(formats);
785 					deUint32					numToSupply		= numFormats/2;
786 					VkResult					queryResult;
787 
788 					ValidateQueryBits::fillBits(formatsClone.begin() + numToSupply, formatsClone.end());
789 
790 					queryResult = instHelper.vki.getPhysicalDeviceSurfaceFormats2KHR(physicalDevices[deviceNdx], &surfaceInfo, &numToSupply, &formatsClone[0]);
791 
792 					results.check(queryResult == VK_INCOMPLETE, "Expected VK_INCOMPLETE");
793 					results.check(ValidateQueryBits::checkBits(formatsClone.begin() + numToSupply, formatsClone.end()),
794 								  "Driver wrote past last element");
795 
796 					for (size_t ndx = 0; ndx < (size_t)numToSupply; ++ndx)
797 					{
798 						results.check(formatsClone[ndx].sType == VK_STRUCTURE_TYPE_SURFACE_FORMAT_2_KHR &&
799 									  formatsClone[ndx].pNext == DE_NULL &&
800 									  formatsClone[ndx].surfaceFormat == formats[ndx].surfaceFormat,
801 									  "Returned element " + de::toString(ndx) + " is different");
802 					}
803 				}
804 			}
805 		}
806 		// else skip query as surface is not supported by the device
807 	}
808 
809 	return tcu::TestStatus(results.getResult(), results.getMessage());
810 }
811 
validateSurfacePresentModes(tcu::ResultCollector & results,Type wsiType,const vector<VkPresentModeKHR> & modes)812 void validateSurfacePresentModes (tcu::ResultCollector& results, Type wsiType, const vector<VkPresentModeKHR>& modes)
813 {
814 	results.check(de::contains(modes.begin(), modes.end(), VK_PRESENT_MODE_FIFO_KHR),
815 				  "VK_PRESENT_MODE_FIFO_KHR is not supported");
816 
817 	if (wsiType == TYPE_ANDROID)
818 		results.check(de::contains(modes.begin(), modes.end(), VK_PRESENT_MODE_MAILBOX_KHR),
819 					  "VK_PRESENT_MODE_MAILBOX_KHR is not supported");
820 }
821 
querySurfacePresentModesTest(Context & context,Type wsiType)822 tcu::TestStatus querySurfacePresentModesTest (Context& context, Type wsiType)
823 {
824 	tcu::TestLog&					log				= context.getTestContext().getLog();
825 	tcu::ResultCollector			results			(log);
826 
827 	const InstanceHelper			instHelper		(context, wsiType);
828 	const NativeObjects				native			(context, instHelper.supportedExtensions, wsiType);
829 	const Unique<VkSurfaceKHR>		surface			(createSurface(instHelper.vki, *instHelper.instance, wsiType, *native.display, *native.window));
830 	const vector<VkPhysicalDevice>	physicalDevices	= enumeratePhysicalDevices(instHelper.vki, *instHelper.instance);
831 
832 	for (size_t deviceNdx = 0; deviceNdx < physicalDevices.size(); ++deviceNdx)
833 	{
834 		if (isSupportedByAnyQueue(instHelper.vki, physicalDevices[deviceNdx], *surface))
835 		{
836 			deUint32	numModes = 0;
837 
838 			VK_CHECK(instHelper.vki.getPhysicalDeviceSurfacePresentModesKHR(physicalDevices[deviceNdx], *surface, &numModes, DE_NULL));
839 
840 			vector<VkPresentModeKHR>	modes	(numModes + 1);
841 
842 			if (numModes > 0)
843 			{
844 				const deUint32 numModesOrig = numModes;
845 
846 				// check if below call properly overwrites mode count
847 				numModes++;
848 
849 				VK_CHECK(instHelper.vki.getPhysicalDeviceSurfacePresentModesKHR(physicalDevices[deviceNdx], *surface, &numModes, &modes[0]));
850 
851 				if ((size_t)numModes != numModesOrig)
852 					TCU_FAIL("Mode count changed between calls");
853 			}
854 
855 			modes.pop_back();
856 
857 			log << TestLog::Message << "Device " << deviceNdx << ": " << tcu::formatArray(modes.begin(), modes.end()) << TestLog::EndMessage;
858 
859 			validateSurfacePresentModes(results, wsiType, modes);
860 			CheckPhysicalDeviceSurfacePresentModesIncompleteResult()(results, instHelper.vki, physicalDevices[deviceNdx], *surface, modes.size());
861 		}
862 		// else skip query as surface is not supported by the device
863 	}
864 
865 	return tcu::TestStatus(results.getResult(), results.getMessage());
866 }
867 
queryDevGroupSurfacePresentCapabilitiesTest(Context & context,Type wsiType)868 tcu::TestStatus queryDevGroupSurfacePresentCapabilitiesTest (Context& context, Type wsiType)
869 {
870 	tcu::TestLog&									log						= context.getTestContext().getLog();
871 	const InstanceHelper							instHelper				(context, wsiType, vector<string>(1, string("VK_KHR_device_group_creation")));
872 	const float										queuePriority			= 1.0f;
873 	const tcu::CommandLine&							cmdLine					= context.getTestContext().getCommandLine();
874 	const deUint32									devGroupIdx				= cmdLine.getVKDeviceGroupId() - 1;
875 	const deUint32									deviceIdx				= context.getTestContext().getCommandLine().getVKDeviceId() - 1u;
876 	const VkDeviceGroupPresentModeFlagsKHR			requiredFlag			= VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_BIT_KHR;
877 	const VkDeviceGroupPresentModeFlagsKHR			maxValidFlag			= VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_BIT_KHR|VK_DEVICE_GROUP_PRESENT_MODE_REMOTE_BIT_KHR |
878 																				VK_DEVICE_GROUP_PRESENT_MODE_SUM_BIT_KHR|VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_MULTI_DEVICE_BIT_KHR;
879 	deUint8											buffer					[sizeof(VkDeviceGroupPresentCapabilitiesKHR) + GUARD_SIZE];
880 	deUint32										queueFamilyIndex		= 0;
881 	VkDeviceGroupPresentCapabilitiesKHR*			presentCapabilities;
882 	VkPhysicalDevice								physicalDevice			= chooseDevice(instHelper.vki, *instHelper.instance, cmdLine);
883 	const Extensions&								supportedExtensions		= enumerateDeviceExtensionProperties(instHelper.vki, physicalDevice, DE_NULL);
884 	std::vector<const char*>						deviceExtensions;
885 
886 	if (!isCoreDeviceExtension(context.getUsedApiVersion(), "VK_KHR_device_group"))
887 		deviceExtensions.push_back("VK_KHR_device_group");
888 	deviceExtensions.push_back("VK_KHR_swapchain");
889 
890 	for (int ndx = 0; ndx < int(deviceExtensions.size()); ++ndx)
891 	{
892 		if (!isExtensionSupported(supportedExtensions, RequiredExtension(deviceExtensions[ndx])))
893 			TCU_THROW(NotSupportedError, (string(deviceExtensions[ndx]) + " is not supported").c_str());
894 	}
895 
896 	const vector<VkPhysicalDeviceGroupProperties>	deviceGroupProps		= enumeratePhysicalDeviceGroups(instHelper.vki, *instHelper.instance);
897 
898 	const std::vector<VkQueueFamilyProperties>		queueProps				= getPhysicalDeviceQueueFamilyProperties(instHelper.vki, deviceGroupProps[devGroupIdx].physicalDevices[deviceIdx]);
899 	for (size_t queueNdx = 0; queueNdx < queueProps.size(); queueNdx++)
900 	{
901 		if (queueProps[queueNdx].queueFlags & VK_QUEUE_GRAPHICS_BIT)
902 			queueFamilyIndex = (deUint32)queueNdx;
903 	}
904 	const VkDeviceQueueCreateInfo					deviceQueueCreateInfo	=
905 	{
906 		VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,				//type
907 		DE_NULL,												//pNext
908 		(VkDeviceQueueCreateFlags)0u,							//flags
909 		queueFamilyIndex,										//queueFamilyIndex;
910 		1u,														//queueCount;
911 		&queuePriority,											//pQueuePriorities;
912 	};
913 	const VkDeviceGroupDeviceCreateInfo				deviceGroupInfo			=
914 	{
915 		VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO_KHR,	//stype
916 		DE_NULL,												//pNext
917 		deviceGroupProps[devGroupIdx].physicalDeviceCount,		//physicalDeviceCount
918 		deviceGroupProps[devGroupIdx].physicalDevices			//physicalDevices
919 	};
920 	const VkDeviceCreateInfo						deviceCreateInfo		=
921 	{
922 		VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,							//sType;
923 		&deviceGroupInfo,												//pNext;
924 		(VkDeviceCreateFlags)0u,										//flags
925 		1,																//queueRecordCount;
926 		&deviceQueueCreateInfo,											//pRequestedQueues;
927 		0,																//layerCount;
928 		DE_NULL,														//ppEnabledLayerNames;
929 		deUint32(deviceExtensions.size()),								//enabledExtensionCount;
930 		(deviceExtensions.empty() ? DE_NULL : &deviceExtensions[0]),	//ppEnabledExtensionNames;
931 		DE_NULL,														//pEnabledFeatures;
932 	};
933 	Move<VkDevice>		deviceGroup = createDevice(context.getPlatformInterface(), *instHelper.instance, instHelper.vki, deviceGroupProps[devGroupIdx].physicalDevices[deviceIdx], &deviceCreateInfo);
934 	const DeviceDriver	vk	(context.getPlatformInterface(), *instHelper.instance, *deviceGroup);
935 
936 
937 	presentCapabilities = reinterpret_cast<VkDeviceGroupPresentCapabilitiesKHR*>(buffer);
938 	deMemset(buffer, GUARD_VALUE, sizeof(buffer));
939 	presentCapabilities->sType = VK_STRUCTURE_TYPE_DEVICE_GROUP_PRESENT_CAPABILITIES_KHR;
940 	presentCapabilities->pNext = DE_NULL;
941 	VK_CHECK(vk.getDeviceGroupPresentCapabilitiesKHR(deviceGroup.get(), presentCapabilities));
942 
943 	// Guard check
944 	for (deInt32 ndx = 0; ndx < GUARD_SIZE; ndx++)
945 	{
946 		if (buffer[ndx + sizeof(VkDeviceGroupPresentCapabilitiesKHR)] != GUARD_VALUE)
947 		{
948 			log << TestLog::Message << "deviceGroupPresentCapabilities - Guard offset " << ndx << " not valid" << TestLog::EndMessage;
949 			return tcu::TestStatus::fail("deviceGroupPresentCapabilities buffer overflow");
950 		}
951 	}
952 
953 	// Check each physical device can present on itself
954 	for (size_t physDevIdx = 0; physDevIdx < VK_MAX_DEVICE_GROUP_SIZE_KHR; physDevIdx++)
955 	{
956 		if (presentCapabilities->presentMask[physDevIdx])
957 			if (!((1 << physDevIdx) & (presentCapabilities->presentMask[physDevIdx])))
958 				return tcu::TestStatus::fail("deviceGroupPresentCapabilities, device can not present on itself, invalid present mask");
959 	}
960 
961 	// Check if flags are valid
962 	if ((!(presentCapabilities->modes & requiredFlag)) ||
963 		presentCapabilities->modes > maxValidFlag)
964 		return tcu::TestStatus::fail("deviceGroupPresentCapabilities flag not valid");
965 
966 	return tcu::TestStatus::pass("Querying deviceGroup present capabilities succeeded");
967 }
968 
queryDevGroupSurfacePresentModesTest(Context & context,Type wsiType)969 tcu::TestStatus queryDevGroupSurfacePresentModesTest (Context& context, Type wsiType)
970 {
971 	tcu::TestLog&							log					= context.getTestContext().getLog();
972 	tcu::ResultCollector					results				(log);
973 	const InstanceHelper					instHelper			(context, wsiType, vector<string>(1, string("VK_KHR_device_group_creation")));
974 	const NativeObjects						native				(context, instHelper.supportedExtensions, wsiType);
975 	const Unique<VkSurfaceKHR>				surface				(createSurface(instHelper.vki, *instHelper.instance, wsiType, *native.display, *native.window));
976 	const float								queuePriority		= 1.0f;
977 	const tcu::CommandLine&					cmdLine				= context.getTestContext().getCommandLine();
978 	const deUint32							devGroupIdx			= cmdLine.getVKDeviceGroupId() - 1;
979 	const deUint32							deviceIdx			= context.getTestContext().getCommandLine().getVKDeviceId() - 1u;
980 	const VkDeviceGroupPresentModeFlagsKHR	requiredFlag		= VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_BIT_KHR;
981 	const VkDeviceGroupPresentModeFlagsKHR	maxValidFlag		= VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_BIT_KHR|VK_DEVICE_GROUP_PRESENT_MODE_REMOTE_BIT_KHR |
982 																	VK_DEVICE_GROUP_PRESENT_MODE_SUM_BIT_KHR|VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_MULTI_DEVICE_BIT_KHR;
983 	VkResult								result				= VK_SUCCESS;
984 	deUint8									buffer				[sizeof(VkDeviceGroupPresentModeFlagsKHR) + GUARD_SIZE];
985 	deUint32								rectCount			= 0;
986 	deUint32								incompleteRectCount	= 0;
987 	deUint32								queueFamilyIndex	= 0;
988 	VkRect2D*								presentRectangles;
989 	VkDeviceGroupPresentModeFlagsKHR*		presentModeFlags;
990 	vector<deUint8>							rectanglesBuffer;
991 	VkPhysicalDevice						physicalDevice		= chooseDevice(instHelper.vki, *instHelper.instance, cmdLine);
992 	const Extensions&						supportedExtensions	= enumerateDeviceExtensionProperties(instHelper.vki, physicalDevice, DE_NULL);
993 	std::vector<const char*>				deviceExtensions;
994 
995 	if (!isCoreDeviceExtension(context.getUsedApiVersion(), "VK_KHR_device_group"))
996 		deviceExtensions.push_back("VK_KHR_device_group");
997 	deviceExtensions.push_back("VK_KHR_swapchain");
998 
999 	for (int ndx = 0; ndx < int(deviceExtensions.size()); ++ndx)
1000 	{
1001 		if (!isExtensionSupported(supportedExtensions, RequiredExtension(deviceExtensions[ndx])))
1002 			TCU_THROW(NotSupportedError, (string(deviceExtensions[ndx]) + " is not supported").c_str());
1003 	}
1004 
1005 	const vector<VkPhysicalDeviceGroupProperties>	deviceGroupProps = enumeratePhysicalDeviceGroups(instHelper.vki, *instHelper.instance);
1006 	const std::vector<VkQueueFamilyProperties>	queueProps		= getPhysicalDeviceQueueFamilyProperties(instHelper.vki, deviceGroupProps[devGroupIdx].physicalDevices[deviceIdx]);
1007 	for (size_t queueNdx = 0; queueNdx < queueProps.size(); queueNdx++)
1008 	{
1009 		if (queueProps[queueNdx].queueFlags & VK_QUEUE_GRAPHICS_BIT)
1010 			queueFamilyIndex = (deUint32)queueNdx;
1011 	}
1012 	const VkDeviceQueueCreateInfo			deviceQueueCreateInfo =
1013 	{
1014 		VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,					//type
1015 		DE_NULL,													//pNext
1016 		(VkDeviceQueueCreateFlags)0u,								//flags
1017 		queueFamilyIndex,											//queueFamilyIndex;
1018 		1u,															//queueCount;
1019 		&queuePriority,												//pQueuePriorities;
1020 	};
1021 	const VkDeviceGroupDeviceCreateInfo			deviceGroupInfo =
1022 	{
1023 		VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO_KHR,	//stype
1024 		DE_NULL,												//pNext
1025 		deviceGroupProps[devGroupIdx].physicalDeviceCount,		//physicalDeviceCount
1026 		deviceGroupProps[devGroupIdx].physicalDevices			//physicalDevices
1027 	};
1028 	const VkDeviceCreateInfo						deviceCreateInfo =
1029 	{
1030 		VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,							//sType;
1031 		&deviceGroupInfo,												//pNext;
1032 		(VkDeviceCreateFlags)0u,										//flags
1033 		1,																//queueRecordCount;
1034 		&deviceQueueCreateInfo,											//pRequestedQueues;
1035 		0,																//layerCount;
1036 		DE_NULL,														//ppEnabledLayerNames;
1037 		deUint32(deviceExtensions.size()),								//enabledExtensionCount;
1038 		(deviceExtensions.empty() ? DE_NULL : &deviceExtensions[0]),	//ppEnabledExtensionNames;
1039 		DE_NULL,														//pEnabledFeatures;
1040 	};
1041 
1042 	Move<VkDevice>		deviceGroup = createDevice(context.getPlatformInterface(), *instHelper.instance, instHelper.vki, deviceGroupProps[devGroupIdx].physicalDevices[deviceIdx], &deviceCreateInfo);
1043 	const DeviceDriver	vk	(context.getPlatformInterface(), *instHelper.instance, *deviceGroup);
1044 	presentModeFlags = reinterpret_cast<VkDeviceGroupPresentModeFlagsKHR*>(buffer);
1045 	deMemset(buffer, GUARD_VALUE, sizeof(buffer));
1046 
1047 	VK_CHECK(vk.getDeviceGroupSurfacePresentModesKHR(deviceGroup.get(), *surface, presentModeFlags));
1048 
1049 	// Guard check
1050 	for (deInt32 ndx = 0; ndx < GUARD_SIZE; ndx++)
1051 	{
1052 		if (buffer[ndx + sizeof(VkDeviceGroupPresentModeFlagsKHR)] != GUARD_VALUE)
1053 		{
1054 			log << TestLog::Message << "queryDevGroupSurfacePresentModesTest - Guard offset " << ndx << " not valid" << TestLog::EndMessage;
1055 			return tcu::TestStatus::fail("queryDevGroupSurfacePresentModesTest buffer overflow");
1056 		}
1057 	}
1058 
1059 	// Check if flags are valid
1060 	if ((!(*presentModeFlags & requiredFlag)) ||
1061 		*presentModeFlags > maxValidFlag)
1062 		return tcu::TestStatus::fail("queryDevGroupSurfacePresentModesTest flag not valid");
1063 
1064 	// Check presentation rectangles
1065 	if (*presentModeFlags == VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_MULTI_DEVICE_BIT_KHR)
1066 	{
1067 		for (size_t physDevIdx = 0; physDevIdx < deviceGroupProps[devGroupIdx].physicalDeviceCount; physDevIdx++)
1068 		{
1069 			VK_CHECK(instHelper.vki.getPhysicalDevicePresentRectanglesKHR(deviceGroupProps[devGroupIdx].physicalDevices[physDevIdx], *surface, &rectCount, DE_NULL));
1070 			rectanglesBuffer.resize(sizeof(VkRect2D) * rectCount + GUARD_SIZE);
1071 			presentRectangles = reinterpret_cast<VkRect2D*>(rectanglesBuffer.data());
1072 			deMemset(rectanglesBuffer.data(), GUARD_VALUE, rectanglesBuffer.size());
1073 
1074 			VK_CHECK(instHelper.vki.getPhysicalDevicePresentRectanglesKHR(deviceGroupProps[devGroupIdx].physicalDevices[physDevIdx], *surface, &rectCount, presentRectangles));
1075 
1076 			// Guard check
1077 			for (deInt32 ndx = 0; ndx < GUARD_SIZE; ndx++)
1078 			{
1079 				if (rectanglesBuffer[ndx + sizeof(VkRect2D) * rectCount] != GUARD_VALUE)
1080 				{
1081 					log << TestLog::Message << "getPhysicalDevicePresentRectanglesKHR - Guard offset " << ndx << " not valid" << TestLog::EndMessage;
1082 					return tcu::TestStatus::fail("getPhysicalDevicePresentRectanglesKHR buffer overflow");
1083 				}
1084 			}
1085 
1086 			// Check rectangles do not overlap
1087 			for (size_t rectIdx1 = 0; rectIdx1 < rectCount; rectIdx1++)
1088 			{
1089 				for (size_t rectIdx2 = 0; rectIdx2 < rectCount; rectIdx2++)
1090 				{
1091 					if (rectIdx1 != rectIdx2)
1092 					{
1093 						deUint32 rectATop		= presentRectangles[rectIdx1].offset.y;
1094 						deUint32 rectALeft		= presentRectangles[rectIdx1].offset.x;
1095 						deUint32 rectABottom	= presentRectangles[rectIdx1].offset.y + presentRectangles[rectIdx1].extent.height;
1096 						deUint32 rectARight		= presentRectangles[rectIdx1].offset.x + presentRectangles[rectIdx1].extent.width;
1097 
1098 						deUint32 rectBTop		= presentRectangles[rectIdx2].offset.y;
1099 						deUint32 rectBLeft		= presentRectangles[rectIdx2].offset.x;
1100 						deUint32 rectBBottom	= presentRectangles[rectIdx2].offset.y + presentRectangles[rectIdx2].extent.height;
1101 						deUint32 rectBRight		= presentRectangles[rectIdx2].offset.x + presentRectangles[rectIdx2].extent.width;
1102 
1103 						if (rectALeft < rectBRight && rectARight > rectBLeft &&
1104 							rectATop < rectBBottom && rectABottom > rectBTop)
1105 							return tcu::TestStatus::fail("getPhysicalDevicePresentRectanglesKHR rectangles overlap");
1106 					}
1107 				}
1108 			}
1109 
1110 			// Check incomplete
1111 			incompleteRectCount = rectCount / 2;
1112 			result = instHelper.vki.getPhysicalDevicePresentRectanglesKHR(deviceGroupProps[devGroupIdx].physicalDevices[physDevIdx], *surface, &incompleteRectCount, presentRectangles);
1113 			results.check(result == VK_INCOMPLETE, "Expected VK_INCOMPLETE");
1114 		}
1115 	}
1116 	return tcu::TestStatus(results.getResult(), results.getMessage());
1117 }
1118 
createSurfaceInitialSizeTest(Context & context,Type wsiType)1119 tcu::TestStatus createSurfaceInitialSizeTest (Context& context, Type wsiType)
1120 {
1121 	tcu::TestLog&					log				= context.getTestContext().getLog();
1122 	tcu::ResultCollector			results			(log);
1123 
1124 	const InstanceHelper			instHelper		(context, wsiType);
1125 
1126 	const UniquePtr<Display>		nativeDisplay	(createDisplay(context.getTestContext().getPlatform().getVulkanPlatform(),
1127 																   instHelper.supportedExtensions,
1128 																   wsiType));
1129 
1130 	const vector<VkPhysicalDevice>	physicalDevices	= enumeratePhysicalDevices(instHelper.vki, *instHelper.instance);
1131 	const UVec2						sizes[]			=
1132 	{
1133 		UVec2(64, 64),
1134 		UVec2(124, 119),
1135 		UVec2(256, 512)
1136 	};
1137 
1138 	DE_ASSERT(getPlatformProperties(wsiType).features & PlatformProperties::FEATURE_INITIAL_WINDOW_SIZE);
1139 
1140 	for (int sizeNdx = 0; sizeNdx < DE_LENGTH_OF_ARRAY(sizes); ++sizeNdx)
1141 	{
1142 		const UVec2&				testSize		= sizes[sizeNdx];
1143 		const UniquePtr<Window>		nativeWindow	(createWindow(*nativeDisplay, tcu::just(testSize)));
1144 		const Unique<VkSurfaceKHR>	surface			(createSurface(instHelper.vki, *instHelper.instance, wsiType, *nativeDisplay, *nativeWindow));
1145 
1146 		for (size_t deviceNdx = 0; deviceNdx < physicalDevices.size(); ++deviceNdx)
1147 		{
1148 			if (isSupportedByAnyQueue(instHelper.vki, physicalDevices[deviceNdx], *surface))
1149 			{
1150 				const VkSurfaceCapabilitiesKHR	capabilities	= getPhysicalDeviceSurfaceCapabilities(instHelper.vki, physicalDevices[deviceNdx], *surface);
1151 
1152 				// \note Assumes that surface size is NOT set by swapchain if initial window size is honored by platform
1153 				results.check(capabilities.currentExtent.width == testSize.x() &&
1154 								capabilities.currentExtent.height == testSize.y(),
1155 								"currentExtent " + de::toString(capabilities.currentExtent) + " doesn't match requested size " + de::toString(testSize));
1156 			}
1157 		}
1158 	}
1159 
1160 	return tcu::TestStatus(results.getResult(), results.getMessage());
1161 }
1162 
resizeSurfaceTest(Context & context,Type wsiType)1163 tcu::TestStatus resizeSurfaceTest (Context& context, Type wsiType)
1164 {
1165 	tcu::TestLog&					log				= context.getTestContext().getLog();
1166 	tcu::ResultCollector			results			(log);
1167 
1168 	const InstanceHelper			instHelper		(context, wsiType);
1169 
1170 	const UniquePtr<Display>		nativeDisplay	(createDisplay(context.getTestContext().getPlatform().getVulkanPlatform(),
1171 																   instHelper.supportedExtensions,
1172 																   wsiType));
1173 	UniquePtr<Window>				nativeWindow	(createWindow(*nativeDisplay, tcu::nothing<UVec2>()));
1174 
1175 	const vector<VkPhysicalDevice>	physicalDevices	= enumeratePhysicalDevices(instHelper.vki, *instHelper.instance);
1176 	const Unique<VkSurfaceKHR>		surface			(createSurface(instHelper.vki, *instHelper.instance, wsiType, *nativeDisplay, *nativeWindow));
1177 
1178 	const UVec2						sizes[]			=
1179 	{
1180 		UVec2(64, 64),
1181 		UVec2(124, 119),
1182 		UVec2(256, 512)
1183 	};
1184 
1185 	DE_ASSERT(getPlatformProperties(wsiType).features & PlatformProperties::FEATURE_RESIZE_WINDOW);
1186 
1187 	for (int sizeNdx = 0; sizeNdx < DE_LENGTH_OF_ARRAY(sizes); ++sizeNdx)
1188 	{
1189 		const UVec2		testSize	= sizes[sizeNdx];
1190 
1191 		try
1192 		{
1193 			nativeWindow->resize(testSize);
1194 		}
1195 		catch (const tcu::Exception& e)
1196 		{
1197 			// Make sure all exception types result in a test failure
1198 			results.fail(e.getMessage());
1199 		}
1200 
1201 		for (size_t deviceNdx = 0; deviceNdx < physicalDevices.size(); ++deviceNdx)
1202 		{
1203 			if (isSupportedByAnyQueue(instHelper.vki, physicalDevices[deviceNdx], *surface))
1204 			{
1205 				const VkSurfaceCapabilitiesKHR	capabilities	= getPhysicalDeviceSurfaceCapabilities(instHelper.vki, physicalDevices[deviceNdx], *surface);
1206 
1207 				// \note Assumes that surface size is NOT set by swapchain if initial window size is honored by platform
1208 				results.check(capabilities.currentExtent.width == testSize.x() &&
1209 								capabilities.currentExtent.height == testSize.y(),
1210 								"currentExtent " + de::toString(capabilities.currentExtent) + " doesn't match requested size " + de::toString(testSize));
1211 			}
1212 		}
1213 	}
1214 
1215 	return tcu::TestStatus(results.getResult(), results.getMessage());
1216 }
1217 
destroyNullHandleSurfaceTest(Context & context,Type wsiType)1218 tcu::TestStatus destroyNullHandleSurfaceTest (Context& context, Type wsiType)
1219 {
1220 	const InstanceHelper	instHelper	(context, wsiType);
1221 	const VkSurfaceKHR		nullHandle	= DE_NULL;
1222 
1223 	// Default allocator
1224 	instHelper.vki.destroySurfaceKHR(*instHelper.instance, nullHandle, DE_NULL);
1225 
1226 	// Custom allocator
1227 	{
1228 		AllocationCallbackRecorder	recordingAllocator	(getSystemAllocator(), 1u);
1229 
1230 		instHelper.vki.destroySurfaceKHR(*instHelper.instance, nullHandle, recordingAllocator.getCallbacks());
1231 
1232 		if (recordingAllocator.getNumRecords() != 0u)
1233 			return tcu::TestStatus::fail("Implementation allocated/freed the memory");
1234 	}
1235 
1236 	return tcu::TestStatus::pass("Destroying a VK_NULL_HANDLE surface has no effect");
1237 }
1238 
1239 } // anonymous
1240 
createSurfaceTests(tcu::TestCaseGroup * testGroup,vk::wsi::Type wsiType)1241 void createSurfaceTests (tcu::TestCaseGroup* testGroup, vk::wsi::Type wsiType)
1242 {
1243 	const PlatformProperties&	platformProperties	= getPlatformProperties(wsiType);
1244 
1245 	addFunctionCase(testGroup, "create",								"Create surface",											createSurfaceTest,							wsiType);
1246 	addFunctionCase(testGroup, "create_custom_allocator",				"Create surface with custom allocator",						createSurfaceCustomAllocatorTest,			wsiType);
1247 	addFunctionCase(testGroup, "create_simulate_oom",					"Create surface with simulating OOM",						createSurfaceSimulateOOMTest,				wsiType);
1248 	addFunctionCase(testGroup, "query_support",							"Query surface support",									querySurfaceSupportTest,					wsiType);
1249 	addFunctionCase(testGroup, "query_capabilities",					"Query surface capabilities",								querySurfaceCapabilitiesTest,				wsiType);
1250 	addFunctionCase(testGroup, "query_capabilities2",					"Query extended surface capabilities",						querySurfaceCapabilities2Test,				wsiType);
1251 	addFunctionCase(testGroup, "query_protected_capabilities",			"Query protected surface capabilities",						querySurfaceProtectedCapabilitiesTest,		wsiType);
1252 	addFunctionCase(testGroup, "query_formats",							"Query surface formats",									querySurfaceFormatsTest,					wsiType);
1253 	addFunctionCase(testGroup, "query_formats2",						"Query extended surface formats",							querySurfaceFormats2Test,					wsiType);
1254 	addFunctionCase(testGroup, "query_present_modes",					"Query surface present modes",								querySurfacePresentModesTest,				wsiType);
1255 	addFunctionCase(testGroup, "query_devgroup_present_capabilities",	"Query surface present modes capabilities in device groups",queryDevGroupSurfacePresentCapabilitiesTest,wsiType);
1256 	addFunctionCase(testGroup, "query_devgroup_present_modes",			"Query surface present modes for device groups",			queryDevGroupSurfacePresentModesTest,		wsiType);
1257 	addFunctionCase(testGroup, "destroy_null_handle",					"Destroy VK_NULL_HANDLE surface",							destroyNullHandleSurfaceTest,				wsiType);
1258 
1259 	if ((platformProperties.features & PlatformProperties::FEATURE_INITIAL_WINDOW_SIZE) != 0)
1260 		addFunctionCase(testGroup, "initial_size",	"Create surface with initial window size set",	createSurfaceInitialSizeTest,	wsiType);
1261 
1262 	if ((platformProperties.features & PlatformProperties::FEATURE_RESIZE_WINDOW) != 0)
1263 		addFunctionCase(testGroup, "resize",		"Resize window and surface",					resizeSurfaceTest,				wsiType);
1264 }
1265 
1266 } // wsi
1267 } // vkt
1268