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