• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*-------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2019 The Khronos Group Inc.
6  * Copyright (c) 2019 Valve Corporation.
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *      http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  *//*!
21  * \file
22  * \brief Tests for the present id and present wait extensions.
23  *//*--------------------------------------------------------------------*/
24 
25 #include "vktWsiPresentIdWaitTests.hpp"
26 #include "vktTestCase.hpp"
27 #include "vktCustomInstancesDevices.hpp"
28 #include "vktNativeObjectsUtil.hpp"
29 
30 #include "vkQueryUtil.hpp"
31 #include "vkDeviceUtil.hpp"
32 #include "vkWsiUtil.hpp"
33 #include "vkMemUtil.hpp"
34 #include "vkTypeUtil.hpp"
35 #include "vkRefUtil.hpp"
36 
37 #include "tcuTestContext.hpp"
38 #include "tcuPlatform.hpp"
39 #include "tcuCommandLine.hpp"
40 #include "tcuTestLog.hpp"
41 
42 #include "deDefs.hpp"
43 
44 #include <vector>
45 #include <string>
46 #include <set>
47 #include <sstream>
48 #include <chrono>
49 #include <algorithm>
50 #include <utility>
51 #include <limits>
52 
53 using std::vector;
54 using std::string;
55 using std::set;
56 
57 namespace vkt
58 {
59 namespace wsi
60 {
61 
62 namespace
63 {
64 
65 // Handy time constants in nanoseconds.
66 constexpr deUint64 k10sec	= 10000000000ull;
67 constexpr deUint64 k1sec	=  1000000000ull;
68 
69 // 100 milliseconds, way above 1/50 seconds for systems with 50Hz ticks.
70 // This should also take into account possible measure deviations due to the machine being loaded.
71 constexpr deUint64 kMargin	=   100000000ull;
72 
73 using TimeoutRange = std::pair<deInt64, deInt64>;
74 
75 // Calculate acceptable timeout range based on indicated timeout and taking into account kMargin.
calcTimeoutRange(deUint64 timeout)76 TimeoutRange calcTimeoutRange (deUint64 timeout)
77 {
78 	constexpr auto kUnsignedMax	= std::numeric_limits<deUint64>::max();
79 	constexpr auto kSignedMax	= static_cast<deUint64>(std::numeric_limits<deInt64>::max());
80 
81 	// Watch for over- and under-flows.
82 	deUint64 timeoutMin = ((timeout < kMargin) ? 0ull : (timeout - kMargin));
83 	deUint64 timeoutMax = ((kUnsignedMax - timeout < kMargin) ? kUnsignedMax : timeout + kMargin);
84 
85 	// Make sure casting is safe.
86 	timeoutMin = de::min(kSignedMax, timeoutMin);
87 	timeoutMax = de::min(kSignedMax, timeoutMax);
88 
89 	return TimeoutRange(static_cast<deInt64>(timeoutMin), static_cast<deInt64>(timeoutMax));
90 }
91 
92 class PresentIdWaitInstance : public TestInstance
93 {
94 public:
PresentIdWaitInstance(Context & context,vk::wsi::Type wsiType)95 								PresentIdWaitInstance	(Context& context, vk::wsi::Type wsiType) : TestInstance(context), m_wsiType(wsiType) {}
~PresentIdWaitInstance(void)96 	virtual						~PresentIdWaitInstance	(void) {}
97 
98 	virtual tcu::TestStatus		iterate					(void);
99 
100 	virtual tcu::TestStatus		run						(const vk::DeviceInterface&				vkd,
101 														 vk::VkDevice							device,
102 														 vk::VkQueue							queue,
103 														 vk::VkCommandPool						commandPool,
104 														 vk::VkSwapchainKHR						swapchain,
105 														 size_t									swapchainSize,
106 														 const vk::wsi::WsiTriangleRenderer&	renderer) = 0;
107 
108 	// Subclasses will need to implement a static method like this one indicating which extensions they need.
requiredDeviceExts(void)109 	static vector<const char*>	requiredDeviceExts		(void) { return vector<const char*>(); }
110 
111 	// Subclasses will also need to implement this nonstatic method returning the same information as above.
112 	virtual vector<const char*>	getRequiredDeviceExts	(void) = 0;
113 
114 protected:
115 	vk::wsi::Type				m_wsiType;
116 };
117 
getRequiredInstanceExtensions(vk::wsi::Type wsiType)118 vector<const char*> getRequiredInstanceExtensions (vk::wsi::Type wsiType)
119 {
120 	vector<const char*> extensions;
121 	extensions.push_back("VK_KHR_surface");
122 	extensions.push_back(getExtensionName(wsiType));
123 	return extensions;
124 }
125 
createInstanceWithWsi(Context & context,vk::wsi::Type wsiType,const vk::VkAllocationCallbacks * pAllocator=nullptr)126 CustomInstance createInstanceWithWsi (Context&							context,
127 									  vk::wsi::Type						wsiType,
128 									  const vk::VkAllocationCallbacks*	pAllocator	= nullptr)
129 {
130 	const auto version				= context.getUsedApiVersion();
131 	const auto requiredExtensions	= getRequiredInstanceExtensions(wsiType);
132 
133 	vector<string> requestedExtensions;
134 	for (const auto& extensionName : requiredExtensions)
135 	{
136 		if (!vk::isCoreInstanceExtension(version, extensionName))
137 			requestedExtensions.push_back(extensionName);
138 	}
139 
140 	return vkt::createCustomInstanceWithExtensions(context, requestedExtensions, pAllocator);
141 }
142 
143 struct InstanceHelper
144 {
145 	const vector<vk::VkExtensionProperties>	supportedExtensions;
146 	CustomInstance							instance;
147 	const vk::InstanceDriver&				vki;
148 
InstanceHelpervkt::wsi::__anon6044021f0111::InstanceHelper149 	InstanceHelper (Context& context, vk::wsi::Type wsiType, const vk::VkAllocationCallbacks* pAllocator = nullptr)
150 		: supportedExtensions	(enumerateInstanceExtensionProperties(context.getPlatformInterface(), nullptr))
151 		, instance				(createInstanceWithWsi(context, wsiType, pAllocator))
152 		, vki					(instance.getDriver())
153 	{}
154 };
155 
getMandatoryDeviceExtensions()156 vector<const char*> getMandatoryDeviceExtensions ()
157 {
158 	vector<const char*> mandatoryExtensions;
159 	mandatoryExtensions.push_back("VK_KHR_swapchain");
160 	return mandatoryExtensions;
161 }
162 
createDeviceWithWsi(const vk::PlatformInterface & vkp,vk::VkInstance instance,const vk::InstanceInterface & vki,vk::VkPhysicalDevice physicalDevice,const vector<const char * > & extraExtensions,const deUint32 queueFamilyIndex,bool validationEnabled,const vk::VkAllocationCallbacks * pAllocator=nullptr)163 vk::Move<vk::VkDevice> createDeviceWithWsi (const vk::PlatformInterface&				vkp,
164 											vk::VkInstance								instance,
165 											const vk::InstanceInterface&				vki,
166 											vk::VkPhysicalDevice						physicalDevice,
167 											const vector<const char*>&					extraExtensions,
168 											const deUint32								queueFamilyIndex,
169 											bool										validationEnabled,
170 											const vk::VkAllocationCallbacks*			pAllocator = nullptr)
171 {
172 	const float							queuePriorities[]	= { 1.0f };
173 	const vk::VkDeviceQueueCreateInfo	queueInfos[]		=
174 	{
175 		{
176 			vk::VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
177 			nullptr,
178 			(vk::VkDeviceQueueCreateFlags)0,
179 			queueFamilyIndex,
180 			DE_LENGTH_OF_ARRAY(queuePriorities),
181 			&queuePriorities[0]
182 		}
183 	};
184 	vk::VkPhysicalDeviceFeatures		features;
185 	std::vector<const char*>			extensions			= extraExtensions;
186 	const auto							mandatoryExtensions	= getMandatoryDeviceExtensions();
187 
188 	for (const auto& ext : mandatoryExtensions)
189 		extensions.push_back(ext);
190 
191 	deMemset(&features, 0, sizeof(features));
192 	const vk::VkDeviceCreateInfo		deviceParams	=
193 	{
194 		vk::VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
195 		nullptr,
196 		(vk::VkDeviceCreateFlags)0,
197 		DE_LENGTH_OF_ARRAY(queueInfos),
198 		&queueInfos[0],
199 		0u,											// enabledLayerCount
200 		nullptr,									// ppEnabledLayerNames
201 		static_cast<deUint32>(extensions.size()),	// enabledExtensionCount
202 		extensions.data(),							// ppEnabledExtensionNames
203 		&features
204 	};
205 
206 	return createCustomDevice(validationEnabled, vkp, instance, vki, physicalDevice, &deviceParams, pAllocator);
207 }
208 
209 struct DeviceHelper
210 {
211 	const vk::VkPhysicalDevice		physicalDevice;
212 	const deUint32					queueFamilyIndex;
213 	const vk::Unique<vk::VkDevice>	device;
214 	const vk::DeviceDriver			vkd;
215 	const vk::VkQueue				queue;
216 
DeviceHelpervkt::wsi::__anon6044021f0111::DeviceHelper217 	DeviceHelper (Context&						context,
218 				  const vk::InstanceInterface&		vki,
219 				  vk::VkInstance					instance,
220 				  const vector<vk::VkSurfaceKHR>&	surfaces,
221 				  const vector<const char*>&		extraExtensions,
222 				  const vk::VkAllocationCallbacks*	pAllocator = nullptr)
223 		: physicalDevice	(chooseDevice(vki, instance, context.getTestContext().getCommandLine()))
224 		, queueFamilyIndex	(vk::wsi::chooseQueueFamilyIndex(vki, physicalDevice, surfaces))
225 		, device			(createDeviceWithWsi(context.getPlatformInterface(),
226 												 instance,
227 												 vki,
228 												 physicalDevice,
229 												 extraExtensions,
230 												 queueFamilyIndex,
231 												 context.getTestContext().getCommandLine().isValidationEnabled(),
232 												 pAllocator))
233 		, vkd				(context.getPlatformInterface(), instance, *device)
234 		, queue				(getDeviceQueue(vkd, *device, queueFamilyIndex, 0))
235 	{
236 	}
237 };
238 
getBasicSwapchainParameters(vk::wsi::Type wsiType,const vk::InstanceInterface & vki,vk::VkPhysicalDevice physicalDevice,vk::VkSurfaceKHR surface,const tcu::UVec2 & desiredSize,deUint32 desiredImageCount)239 vk::VkSwapchainCreateInfoKHR getBasicSwapchainParameters (vk::wsi::Type					wsiType,
240 														  const vk::InstanceInterface&	vki,
241 														  vk::VkPhysicalDevice			physicalDevice,
242 														  vk::VkSurfaceKHR				surface,
243 														  const tcu::UVec2&				desiredSize,
244 														  deUint32						desiredImageCount)
245 {
246 	const vk::VkSurfaceCapabilitiesKHR		capabilities		= vk::wsi::getPhysicalDeviceSurfaceCapabilities(vki,
247 																								   physicalDevice,
248 																								   surface);
249 	const vector<vk::VkSurfaceFormatKHR>	formats				= vk::wsi::getPhysicalDeviceSurfaceFormats(vki,
250 																							  physicalDevice,
251 																							  surface);
252 	const vk::wsi::PlatformProperties&		platformProperties	= vk::wsi::getPlatformProperties(wsiType);
253 	const vk::VkSurfaceTransformFlagBitsKHR transform			= (capabilities.supportedTransforms & vk::VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) ? vk::VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR : capabilities.currentTransform;
254 	const vk::VkSwapchainCreateInfoKHR		parameters			=
255 	{
256 		vk::VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
257 		nullptr,
258 		(vk::VkSwapchainCreateFlagsKHR)0,
259 		surface,
260 		de::clamp(desiredImageCount, capabilities.minImageCount, capabilities.maxImageCount > 0 ? capabilities.maxImageCount : capabilities.minImageCount + desiredImageCount),
261 		formats[0].format,
262 		formats[0].colorSpace,
263 		(platformProperties.swapchainExtent == vk::wsi::PlatformProperties::SWAPCHAIN_EXTENT_MUST_MATCH_WINDOW_SIZE
264 			? capabilities.currentExtent : vk::makeExtent2D(desiredSize.x(), desiredSize.y())),
265 		1u,									// imageArrayLayers
266 		vk::VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
267 		vk::VK_SHARING_MODE_EXCLUSIVE,
268 		0u,
269 		nullptr,
270 		transform,
271 		vk::VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
272 		vk::VK_PRESENT_MODE_FIFO_KHR,
273 		VK_FALSE,							// clipped
274 		(vk::VkSwapchainKHR)0				// oldSwapchain
275 	};
276 
277 	return parameters;
278 }
279 
280 using CommandBufferSp	= de::SharedPtr<vk::Unique<vk::VkCommandBuffer>>;
281 using FenceSp			= de::SharedPtr<vk::Unique<vk::VkFence>>;
282 using SemaphoreSp		= de::SharedPtr<vk::Unique<vk::VkSemaphore>>;
283 
createFences(const vk::DeviceInterface & vkd,const vk::VkDevice device,size_t numFences)284 vector<FenceSp> createFences (const vk::DeviceInterface&	vkd,
285 							  const vk::VkDevice			device,
286 							  size_t						numFences)
287 {
288 	vector<FenceSp> fences(numFences);
289 
290 	for (size_t ndx = 0; ndx < numFences; ++ndx)
291 		fences[ndx] = FenceSp(new vk::Unique<vk::VkFence>(createFence(vkd, device, vk::VK_FENCE_CREATE_SIGNALED_BIT)));
292 
293 	return fences;
294 }
295 
createSemaphores(const vk::DeviceInterface & vkd,const vk::VkDevice device,size_t numSemaphores)296 vector<SemaphoreSp> createSemaphores (const vk::DeviceInterface&	vkd,
297 									  const vk::VkDevice			device,
298 									  size_t						numSemaphores)
299 {
300 	vector<SemaphoreSp> semaphores(numSemaphores);
301 
302 	for (size_t ndx = 0; ndx < numSemaphores; ++ndx)
303 		semaphores[ndx] = SemaphoreSp(new vk::Unique<vk::VkSemaphore>(createSemaphore(vkd, device)));
304 
305 	return semaphores;
306 }
307 
allocateCommandBuffers(const vk::DeviceInterface & vkd,const vk::VkDevice device,const vk::VkCommandPool commandPool,const vk::VkCommandBufferLevel level,const size_t numCommandBuffers)308 vector<CommandBufferSp> allocateCommandBuffers (const vk::DeviceInterface&		vkd,
309 												const vk::VkDevice				device,
310 												const vk::VkCommandPool			commandPool,
311 												const vk::VkCommandBufferLevel	level,
312 												const size_t					numCommandBuffers)
313 {
314 	vector<CommandBufferSp>				buffers		(numCommandBuffers);
315 
316 	for (size_t ndx = 0; ndx < numCommandBuffers; ++ndx)
317 		buffers[ndx] = CommandBufferSp(new vk::Unique<vk::VkCommandBuffer>(allocateCommandBuffer(vkd, device, commandPool, level)));
318 
319 	return buffers;
320 }
321 
322 class FrameStreamObjects
323 {
324 public:
325 	struct FrameObjects
326 	{
327 		const vk::VkFence&			renderCompleteFence;
328 		const vk::VkSemaphore&		renderCompleteSemaphore;
329 		const vk::VkSemaphore&		imageAvailableSemaphore;
330 		const vk::VkCommandBuffer&	commandBuffer;
331 	};
332 
FrameStreamObjects(const vk::DeviceInterface & vkd,vk::VkDevice device,vk::VkCommandPool cmdPool,size_t maxQueuedFrames)333 	FrameStreamObjects (const vk::DeviceInterface& vkd, vk::VkDevice device, vk::VkCommandPool cmdPool, size_t maxQueuedFrames)
334 		: renderingCompleteFences		(createFences(vkd, device, maxQueuedFrames))
335 		, renderingCompleteSemaphores	(createSemaphores(vkd, device, maxQueuedFrames))
336 		, imageAvailableSemaphores		(createSemaphores(vkd, device, maxQueuedFrames))
337 		, commandBuffers				(allocateCommandBuffers(vkd, device, cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY, maxQueuedFrames))
338 		, m_maxQueuedFrames				(maxQueuedFrames)
339 		, m_nextFrame					(0u)
340 	{}
341 
frameNumber(void) const342 	size_t frameNumber (void) const { DE_ASSERT(m_nextFrame > 0u); return m_nextFrame - 1u; }
343 
newFrame()344 	FrameObjects newFrame ()
345 	{
346 		const size_t mod = m_nextFrame % m_maxQueuedFrames;
347 		FrameObjects ret =
348 		{
349 			**renderingCompleteFences[mod],
350 			**renderingCompleteSemaphores[mod],
351 			**imageAvailableSemaphores[mod],
352 			**commandBuffers[mod],
353 		};
354 		++m_nextFrame;
355 		return ret;
356 	}
357 
358 private:
359 	const vector<FenceSp>			renderingCompleteFences;
360 	const vector<SemaphoreSp>		renderingCompleteSemaphores;
361 	const vector<SemaphoreSp>		imageAvailableSemaphores;
362 	const vector<CommandBufferSp>	commandBuffers;
363 
364 	const size_t	m_maxQueuedFrames;
365 	size_t			m_nextFrame;
366 };
367 
iterate(void)368 tcu::TestStatus PresentIdWaitInstance::iterate (void)
369 {
370 	const tcu::UVec2						desiredSize					(256, 256);
371 	const InstanceHelper					instHelper					(m_context, m_wsiType);
372 	const NativeObjects						native						(m_context, instHelper.supportedExtensions, m_wsiType, 1u, tcu::just(desiredSize));
373 	const vk::Unique<vk::VkSurfaceKHR>		surface						(createSurface(instHelper.vki, instHelper.instance, m_wsiType, native.getDisplay(), native.getWindow()));
374 	const DeviceHelper						devHelper					(m_context, instHelper.vki, instHelper.instance, vector<vk::VkSurfaceKHR>(1u, surface.get()), getRequiredDeviceExts());
375 	const vk::DeviceInterface&				vkd							= devHelper.vkd;
376 	const vk::VkDevice						device						= *devHelper.device;
377 	vk::SimpleAllocator						allocator					(vkd, device, getPhysicalDeviceMemoryProperties(instHelper.vki, devHelper.physicalDevice));
378 	const vk::VkSwapchainCreateInfoKHR		swapchainInfo				= getBasicSwapchainParameters(m_wsiType, instHelper.vki, devHelper.physicalDevice, *surface, desiredSize, 2);
379 	const vk::Unique<vk::VkSwapchainKHR>	swapchain					(vk::createSwapchainKHR(vkd, device, &swapchainInfo));
380 	const vector<vk::VkImage>				swapchainImages				= vk::wsi::getSwapchainImages(vkd, device, *swapchain);
381 	const vk::Unique<vk::VkCommandPool>		commandPool					(createCommandPool(vkd, device, vk::VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, devHelper.queueFamilyIndex));
382 	const vk::wsi::WsiTriangleRenderer		renderer					(vkd,
383 																		 device,
384 																		 allocator,
385 																		 m_context.getBinaryCollection(),
386 																		 false,
387 																		 swapchainImages,
388 																		 swapchainImages,
389 																		 swapchainInfo.imageFormat,
390 																		 tcu::UVec2(swapchainInfo.imageExtent.width, swapchainInfo.imageExtent.height));
391 
392 	try
393 	{
394 		return run(vkd, device, devHelper.queue, commandPool.get(), swapchain.get(), swapchainImages.size(), renderer);
395 	}
396 	catch (...)
397 	{
398 		// Make sure device is idle before destroying resources
399 		vkd.deviceWaitIdle(device);
400 		throw;
401 	}
402 
403 	return tcu::TestStatus(QP_TEST_RESULT_INTERNAL_ERROR, "Reached unreachable code");
404 }
405 
406 struct PresentParameters
407 {
408 	tcu::Maybe<deUint64>		presentId;
409 	tcu::Maybe<vk::VkResult>	expectedResult;
410 };
411 
412 struct WaitParameters
413 {
414 	deUint64	presentId;
415 	deUint64	timeout; // Nanoseconds.
416 	bool		timeoutExpected;
417 };
418 
419 // This structure represents a set of present operations to be run followed by a set of wait operations to be run after them.
420 // When running the present operations, the present id can be provided, together with an optional expected result to be checked.
421 // When runing the wait operations, the present id must be provided together with a timeout and an indication of whether the operation is expected to time out or not.
422 struct PresentAndWaitOps
423 {
424 	vector<PresentParameters>	presentOps;
425 	vector<WaitParameters>		waitOps;
426 };
427 
428 // Parent class for VK_KHR_present_id and VK_KHR_present_wait simple tests.
429 class PresentIdWaitSimpleInstance : public PresentIdWaitInstance
430 {
431 public:
PresentIdWaitSimpleInstance(Context & context,vk::wsi::Type wsiType,const vector<PresentAndWaitOps> & sequence)432 	PresentIdWaitSimpleInstance(Context& context, vk::wsi::Type wsiType, const vector<PresentAndWaitOps>& sequence)
433 		: PresentIdWaitInstance(context, wsiType), m_sequence(sequence)
434 	{}
435 
~PresentIdWaitSimpleInstance()436 	virtual ~PresentIdWaitSimpleInstance() {}
437 
438 	virtual tcu::TestStatus		run						(const vk::DeviceInterface&				vkd,
439 														 vk::VkDevice							device,
440 														 vk::VkQueue							queue,
441 														 vk::VkCommandPool						commandPool,
442 														 vk::VkSwapchainKHR						swapchain,
443 														 size_t									swapchainSize,
444 														 const vk::wsi::WsiTriangleRenderer&	renderer);
445 protected:
446 	const vector<PresentAndWaitOps> m_sequence;
447 };
448 
449 // Waits for the appropriate fences, acquires swapchain image, records frame and submits it to the given queue, signaling the appropriate frame semaphores.
450 // Returns the image index from the swapchain.
recordAndSubmitFrame(FrameStreamObjects::FrameObjects & frameObjects,const vk::wsi::WsiTriangleRenderer & triangleRenderer,const vk::DeviceInterface & vkd,vk::VkDevice device,vk::VkSwapchainKHR swapchain,size_t swapchainSize,vk::VkQueue queue,size_t frameNumber,tcu::TestLog & testLog)451 deUint32 recordAndSubmitFrame (FrameStreamObjects::FrameObjects& frameObjects, const vk::wsi::WsiTriangleRenderer& triangleRenderer, const vk::DeviceInterface& vkd, vk::VkDevice device, vk::VkSwapchainKHR swapchain, size_t swapchainSize, vk::VkQueue queue, size_t frameNumber, tcu::TestLog& testLog)
452 {
453 	// Wait and reset the render complete fence to avoid having too many submitted frames.
454 	VK_CHECK(vkd.waitForFences(device, 1u, &frameObjects.renderCompleteFence, VK_TRUE, std::numeric_limits<deUint64>::max()));
455 	VK_CHECK(vkd.resetFences(device, 1, &frameObjects.renderCompleteFence));
456 
457 	// Acquire swapchain image.
458 	deUint32 imageNdx = std::numeric_limits<deUint32>::max();
459 	const vk::VkResult acquireResult = vkd.acquireNextImageKHR(device,
460 																swapchain,
461 																std::numeric_limits<deUint64>::max(),
462 																frameObjects.imageAvailableSemaphore,
463 																(vk::VkFence)0,
464 																&imageNdx);
465 
466 	if (acquireResult == vk::VK_SUBOPTIMAL_KHR)
467 		testLog << tcu::TestLog::Message << "Got " << acquireResult << " at frame " << frameNumber << tcu::TestLog::EndMessage;
468 	else
469 		VK_CHECK(acquireResult);
470 	TCU_CHECK(static_cast<size_t>(imageNdx) < swapchainSize);
471 
472 	// Submit frame to the queue.
473 	const vk::VkPipelineStageFlags	waitDstStage	= vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
474 	const vk::VkSubmitInfo			submitInfo		=
475 	{
476 		vk::VK_STRUCTURE_TYPE_SUBMIT_INFO,
477 		nullptr,
478 		1u,
479 		&frameObjects.imageAvailableSemaphore,
480 		&waitDstStage,
481 		1u,
482 		&frameObjects.commandBuffer,
483 		1u,
484 		&frameObjects.renderCompleteSemaphore,
485 	};
486 
487 	triangleRenderer.recordFrame(frameObjects.commandBuffer, imageNdx, static_cast<deUint32>(frameNumber));
488 	VK_CHECK(vkd.queueSubmit(queue, 1u, &submitInfo, frameObjects.renderCompleteFence));
489 
490 	return imageNdx;
491 }
492 
run(const vk::DeviceInterface & vkd,vk::VkDevice device,vk::VkQueue queue,vk::VkCommandPool commandPool,vk::VkSwapchainKHR swapchain,size_t swapchainSize,const vk::wsi::WsiTriangleRenderer & renderer)493 tcu::TestStatus PresentIdWaitSimpleInstance::run (const vk::DeviceInterface& vkd, vk::VkDevice device, vk::VkQueue queue, vk::VkCommandPool commandPool, vk::VkSwapchainKHR swapchain, size_t swapchainSize, const vk::wsi::WsiTriangleRenderer& renderer)
494 {
495 	const size_t		maxQueuedFrames		= swapchainSize*2;
496 	FrameStreamObjects	frameStreamObjects	(vkd, device, commandPool, maxQueuedFrames);
497 
498 	for (const auto& step : m_sequence)
499 	{
500 		for (const auto& presentOp : step.presentOps)
501 		{
502 			// Get objects for the next frame.
503 			FrameStreamObjects::FrameObjects frameObjects = frameStreamObjects.newFrame();
504 
505 			// Record and submit new frame.
506 			deUint32 imageNdx = recordAndSubmitFrame(frameObjects, renderer, vkd, device, swapchain, swapchainSize, queue, frameStreamObjects.frameNumber(), m_context.getTestContext().getLog());
507 
508 			// Present rendered frame.
509 			const vk::VkPresentIdKHR		presentId		=
510 			{
511 				vk::VK_STRUCTURE_TYPE_PRESENT_ID_KHR,							// VkStructureType		sType;
512 				nullptr,														// const void*			pNext;
513 				(presentOp.presentId ? 1u : 0u),								// deUint32				swapchainCount;
514 				(presentOp.presentId ? &presentOp.presentId.get() : nullptr ),	// const deUint64*		pPresentIds;
515 			};
516 
517 			const vk::VkPresentInfoKHR		presentInfo		=
518 			{
519 				vk::VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
520 				(presentOp.presentId ? &presentId : nullptr),
521 				1u,
522 				&frameObjects.renderCompleteSemaphore,
523 				1u,
524 				&swapchain,
525 				&imageNdx,
526 				nullptr,
527 			};
528 
529 			vk::VkResult result = vkd.queuePresentKHR(queue, &presentInfo);
530 
531 			if (presentOp.expectedResult)
532 			{
533 				const vk::VkResult expected = presentOp.expectedResult.get();
534 				if ((expected == vk::VK_SUCCESS && result != vk::VK_SUCCESS && result != vk::VK_SUBOPTIMAL_KHR) ||
535 					(expected != vk::VK_SUCCESS && result != expected))
536 				{
537 					std::ostringstream msg;
538 					msg << "Got " << result << " while expecting " << expected << " after presenting with ";
539 					if (presentOp.presentId)
540 						msg << "id " << presentOp.presentId.get();
541 					else
542 						msg << "no id";
543 					TCU_FAIL(msg.str());
544 				}
545 			}
546 		}
547 
548 		// Wait operations.
549 		for (const auto& waitOp : step.waitOps)
550 		{
551 			auto			before		= std::chrono::high_resolution_clock::now();
552 			vk::VkResult	waitResult	= vkd.waitForPresentKHR(device, swapchain, waitOp.presentId, waitOp.timeout);
553 			auto			after		= std::chrono::high_resolution_clock::now();
554 			auto			diff		= std::chrono::nanoseconds(after - before).count();
555 
556 			if (waitOp.timeoutExpected)
557 			{
558 				if (waitResult != vk::VK_TIMEOUT)
559 				{
560 					std::ostringstream msg;
561 					msg << "Got " << waitResult << " while expecting a timeout in vkWaitForPresentKHR call";
562 					TCU_FAIL(msg.str());
563 				}
564 
565 				const auto timeoutRange = calcTimeoutRange(waitOp.timeout);
566 
567 				if (diff < timeoutRange.first || diff > timeoutRange.second)
568 				{
569 					std::ostringstream msg;
570 					msg << "vkWaitForPresentKHR waited for " << diff << " nanoseconds with a timeout of " << waitOp.timeout << " nanoseconds";
571 					TCU_FAIL(msg.str());
572 				}
573 			}
574 			else if (waitResult != vk::VK_SUCCESS)
575 			{
576 				std::ostringstream msg;
577 				msg << "Got " << waitResult << " while expecting success in vkWaitForPresentKHR call";
578 				TCU_FAIL(msg.str());
579 			}
580 		}
581 	}
582 
583 	// Wait until device is idle.
584 	VK_CHECK(vkd.deviceWaitIdle(device));
585 
586 	return tcu::TestStatus::pass("Pass");
587 }
588 
589 // Parent class for VK_KHR_present_id simple tests.
590 class PresentIdInstance : public PresentIdWaitSimpleInstance
591 {
592 public:
PresentIdInstance(Context & context,vk::wsi::Type wsiType,const vector<PresentAndWaitOps> & sequence)593 	PresentIdInstance(Context& context, vk::wsi::Type wsiType, const vector<PresentAndWaitOps>& sequence)
594 		: PresentIdWaitSimpleInstance(context, wsiType, sequence)
595 	{}
596 
~PresentIdInstance()597 	virtual ~PresentIdInstance() {}
598 
requiredDeviceExts(void)599 	static vector<const char*>	requiredDeviceExts (void)
600 	{
601 		vector<const char*> extensions;
602 		extensions.push_back("VK_KHR_present_id");
603 		return extensions;
604 	}
605 
getRequiredDeviceExts(void)606 	virtual vector<const char*> getRequiredDeviceExts (void)
607 	{
608 		return requiredDeviceExts();
609 	}
610 };
611 
612 // Parent class for VK_KHR_present_wait simple tests.
613 class PresentWaitInstance : public PresentIdWaitSimpleInstance
614 {
615 public:
PresentWaitInstance(Context & context,vk::wsi::Type wsiType,const vector<PresentAndWaitOps> & sequence)616 	PresentWaitInstance(Context& context, vk::wsi::Type wsiType, const vector<PresentAndWaitOps>& sequence)
617 		: PresentIdWaitSimpleInstance(context, wsiType, sequence)
618 	{}
619 
~PresentWaitInstance()620 	virtual ~PresentWaitInstance() {}
621 
requiredDeviceExts(void)622 	static vector<const char*>	requiredDeviceExts (void)
623 	{
624 		vector<const char*> extensions;
625 		extensions.push_back("VK_KHR_present_id");
626 		extensions.push_back("VK_KHR_present_wait");
627 		return extensions;
628 	}
629 
getRequiredDeviceExts(void)630 	virtual vector<const char*>	getRequiredDeviceExts (void)
631 	{
632 		return requiredDeviceExts();
633 	}
634 };
635 
636 class PresentIdZeroInstance : public PresentIdInstance
637 {
638 public:
639 	static const vector<PresentAndWaitOps> sequence;
640 
PresentIdZeroInstance(Context & context,vk::wsi::Type wsiType)641 	PresentIdZeroInstance (Context& context, vk::wsi::Type wsiType)
642 		: PresentIdInstance(context, wsiType, sequence)
643 	{}
644 };
645 
646 const vector<PresentAndWaitOps> PresentIdZeroInstance::sequence =
647 {
648 	{ // PresentAndWaitOps
649 		{	// presentOps vector
650 			{ tcu::just<deUint64>(0), tcu::just(vk::VK_SUCCESS) },
651 		},
652 		{	// waitOps vector
653 		},
654 	},
655 };
656 
657 class PresentIdIncreasingInstance : public PresentIdInstance
658 {
659 public:
660 	static const vector<PresentAndWaitOps> sequence;
661 
PresentIdIncreasingInstance(Context & context,vk::wsi::Type wsiType)662 	PresentIdIncreasingInstance (Context& context, vk::wsi::Type wsiType)
663 		: PresentIdInstance(context, wsiType, sequence)
664 	{}
665 };
666 
667 const vector<PresentAndWaitOps> PresentIdIncreasingInstance::sequence =
668 {
669 	{ // PresentAndWaitOps
670 		{	// presentOps vector
671 			{ tcu::just<deUint64>(1),							tcu::just(vk::VK_SUCCESS) },
672 			{ tcu::just(std::numeric_limits<deUint64>::max()),	tcu::just(vk::VK_SUCCESS) },
673 		},
674 		{	// waitOps vector
675 		},
676 	},
677 };
678 
679 class PresentIdInterleavedInstance : public PresentIdInstance
680 {
681 public:
682 	static const vector<PresentAndWaitOps> sequence;
683 
PresentIdInterleavedInstance(Context & context,vk::wsi::Type wsiType)684 	PresentIdInterleavedInstance (Context& context, vk::wsi::Type wsiType)
685 		: PresentIdInstance(context, wsiType, sequence)
686 	{}
687 };
688 
689 const vector<PresentAndWaitOps> PresentIdInterleavedInstance::sequence =
690 {
691 	{ // PresentAndWaitOps
692 		{	// presentOps vector
693 			{ tcu::just<deUint64>(0),							tcu::just(vk::VK_SUCCESS) },
694 			{ tcu::just<deUint64>(1),							tcu::just(vk::VK_SUCCESS) },
695 			{ tcu::Nothing,										tcu::just(vk::VK_SUCCESS) },
696 			{ tcu::just(std::numeric_limits<deUint64>::max()),	tcu::just(vk::VK_SUCCESS) },
697 		},
698 		{	// waitOps vector
699 		},
700 	},
701 };
702 
703 class PresentWaitSingleFrameInstance : public PresentWaitInstance
704 {
705 public:
706 	static const vector<PresentAndWaitOps> sequence;
707 
PresentWaitSingleFrameInstance(Context & context,vk::wsi::Type wsiType)708 	PresentWaitSingleFrameInstance (Context& context, vk::wsi::Type wsiType)
709 		: PresentWaitInstance(context, wsiType, sequence)
710 	{}
711 };
712 
713 const vector<PresentAndWaitOps> PresentWaitSingleFrameInstance::sequence =
714 {
715 	{ // PresentAndWaitOps
716 		{	// presentOps vector
717 			{ tcu::just<deUint64>(1), tcu::just(vk::VK_SUCCESS) },
718 		},
719 		{	// waitOps vector
720 			{ 1ull, k10sec, false },
721 		},
722 	},
723 };
724 
725 class PresentWaitPastFrameInstance : public PresentWaitInstance
726 {
727 public:
728 	static const vector<PresentAndWaitOps> sequence;
729 
PresentWaitPastFrameInstance(Context & context,vk::wsi::Type wsiType)730 	PresentWaitPastFrameInstance (Context& context, vk::wsi::Type wsiType)
731 		: PresentWaitInstance(context, wsiType, sequence)
732 	{}
733 };
734 
735 const vector<PresentAndWaitOps> PresentWaitPastFrameInstance::sequence =
736 {
737 	// Start with present id 1.
738 	{ // PresentAndWaitOps
739 		{	// presentOps vector
740 			{ tcu::just<deUint64>(1), tcu::just(vk::VK_SUCCESS) },
741 		},
742 		{	// waitOps vector
743 			{ 1ull, k10sec, false },
744 			{ 1ull, 0ull,   false },
745 		},
746 	},
747 	// Then the maximum value. Both waiting for id 1 and the max id should work.
748 	{ // PresentAndWaitOps
749 		{	// presentOps vector
750 			{ tcu::just(std::numeric_limits<deUint64>::max()), tcu::just(vk::VK_SUCCESS) },
751 		},
752 		{	// waitOps vector
753 			{ 1ull,                                 0ull,   false },
754 			{ 1ull,                                 k10sec, false },
755 			{ std::numeric_limits<deUint64>::max(), k10sec, false },
756 			{ std::numeric_limits<deUint64>::max(), 0ull,   false },
757 		},
758 	},
759 	// Submit some frames without id after having used the maximum value. This should also work.
760 	{ // PresentAndWaitOps
761 		{	// presentOps vector
762 			{ tcu::Nothing,				tcu::just(vk::VK_SUCCESS) },
763 			{ tcu::just<deUint64>(0),	tcu::just(vk::VK_SUCCESS) },
764 		},
765 		{	// waitOps vector
766 		},
767 	},
768 };
769 
770 class PresentWaitNoFramesInstance : public PresentWaitInstance
771 {
772 public:
773 	static const vector<PresentAndWaitOps> sequence;
774 
PresentWaitNoFramesInstance(Context & context,vk::wsi::Type wsiType)775 	PresentWaitNoFramesInstance (Context& context, vk::wsi::Type wsiType)
776 		: PresentWaitInstance(context, wsiType, sequence)
777 	{}
778 };
779 
780 const vector<PresentAndWaitOps> PresentWaitNoFramesInstance::sequence =
781 {
782 	{ // PresentAndWaitOps
783 		{	// presentOps vector
784 		},
785 		{	// waitOps vector
786 			{ 1ull, 0ull,  true },
787 			{ 1ull, k1sec, true },
788 		},
789 	},
790 };
791 
792 class PresentWaitNoFrameIdInstance : public PresentWaitInstance
793 {
794 public:
795 	static const vector<PresentAndWaitOps> sequence;
796 
PresentWaitNoFrameIdInstance(Context & context,vk::wsi::Type wsiType)797 	PresentWaitNoFrameIdInstance (Context& context, vk::wsi::Type wsiType)
798 		: PresentWaitInstance(context, wsiType, sequence)
799 	{}
800 };
801 
802 const vector<PresentAndWaitOps> PresentWaitNoFrameIdInstance::sequence =
803 {
804 	{ // PresentAndWaitOps
805 		{	// presentOps vector
806 			{ tcu::just<deUint64>(0), tcu::just(vk::VK_SUCCESS) },
807 		},
808 		{	// waitOps vector
809 			{ 1ull, 0ull,  true },
810 			{ 1ull, k1sec, true },
811 		},
812 	},
813 	{ // PresentAndWaitOps
814 		{	// presentOps vector
815 			{ tcu::Nothing, tcu::just(vk::VK_SUCCESS) },
816 		},
817 		{	// waitOps vector
818 			{ 1ull, 0ull,  true },
819 			{ 1ull, k1sec, true },
820 		},
821 	},
822 };
823 
824 class PresentWaitFutureFrameInstance : public PresentWaitInstance
825 {
826 public:
827 	static const vector<PresentAndWaitOps> sequence;
828 
PresentWaitFutureFrameInstance(Context & context,vk::wsi::Type wsiType)829 	PresentWaitFutureFrameInstance (Context& context, vk::wsi::Type wsiType)
830 		: PresentWaitInstance(context, wsiType, sequence)
831 	{}
832 };
833 
834 const vector<PresentAndWaitOps> PresentWaitFutureFrameInstance::sequence =
835 {
836 	{ // PresentAndWaitOps
837 		{	// presentOps vector
838 			{ tcu::just<deUint64>(1), tcu::just(vk::VK_SUCCESS) },
839 		},
840 		{	// waitOps vector
841 			{ std::numeric_limits<deUint64>::max(), k1sec, true },
842 			{ std::numeric_limits<deUint64>::max(), 0ull,  true },
843 			{ 2ull,                                 0ull,  true },
844 			{ 2ull,                                 k1sec, true },
845 		},
846 	},
847 };
848 
849 // Instance with two windows and surfaces to check present ids are not mixed up.
850 class PresentWaitDualInstance : public TestInstance
851 {
852 public:
PresentWaitDualInstance(Context & context,vk::wsi::Type wsiType)853 								PresentWaitDualInstance		(Context& context, vk::wsi::Type wsiType) : TestInstance(context), m_wsiType(wsiType) {}
~PresentWaitDualInstance(void)854 	virtual						~PresentWaitDualInstance	(void) {}
855 
856 	virtual tcu::TestStatus		iterate						(void);
857 
requiredDeviceExts(void)858 	static vector<const char*>	requiredDeviceExts			(void)
859 	{
860 		vector<const char*> extensions;
861 		extensions.push_back("VK_KHR_present_id");
862 		extensions.push_back("VK_KHR_present_wait");
863 		return extensions;
864 	}
865 
getRequiredDeviceExts(void)866 	virtual vector<const char*>	getRequiredDeviceExts		(void)
867 	{
868 		return requiredDeviceExts();
869 	}
870 
871 protected:
872 	vk::wsi::Type				m_wsiType;
873 };
874 
875 struct IdAndWait
876 {
877 	deUint64	presentId;
878 	bool		wait;
879 };
880 
881 struct DualIdAndWait
882 {
883 	IdAndWait idWait1;
884 	IdAndWait idWait2;
885 };
886 
iterate(void)887 tcu::TestStatus PresentWaitDualInstance::iterate (void)
888 {
889 	const tcu::UVec2						desiredSize					(256, 256);
890 	const InstanceHelper					instHelper					(m_context, m_wsiType);
891 	const NativeObjects						native						(m_context, instHelper.supportedExtensions, m_wsiType, 2u, tcu::just(desiredSize));
892 	const vk::Unique<vk::VkSurfaceKHR>		surface1					(createSurface(instHelper.vki, instHelper.instance, m_wsiType, native.getDisplay(), native.getWindow(0)));
893 	const vk::Unique<vk::VkSurfaceKHR>		surface2					(createSurface(instHelper.vki, instHelper.instance, m_wsiType, native.getDisplay(), native.getWindow(1)));
894 	const DeviceHelper						devHelper					(m_context, instHelper.vki, instHelper.instance, vector<vk::VkSurfaceKHR>{surface1.get(), surface2.get()}, getRequiredDeviceExts());
895 	const vk::DeviceInterface&				vkd							= devHelper.vkd;
896 	const vk::VkDevice						device						= *devHelper.device;
897 	vk::SimpleAllocator						allocator					(vkd, device, getPhysicalDeviceMemoryProperties(instHelper.vki, devHelper.physicalDevice));
898 	const vk::VkSwapchainCreateInfoKHR		swapchainInfo1				= getBasicSwapchainParameters(m_wsiType, instHelper.vki, devHelper.physicalDevice, surface1.get(), desiredSize, 2);
899 	const vk::VkSwapchainCreateInfoKHR		swapchainInfo2				= getBasicSwapchainParameters(m_wsiType, instHelper.vki, devHelper.physicalDevice, surface2.get(), desiredSize, 2);
900 	const vk::Unique<vk::VkSwapchainKHR>	swapchain1					(vk::createSwapchainKHR(vkd, device, &swapchainInfo1));
901 	const vk::Unique<vk::VkSwapchainKHR>	swapchain2					(vk::createSwapchainKHR(vkd, device, &swapchainInfo2));
902 	const vector<vk::VkImage>				swapchainImages1			= vk::wsi::getSwapchainImages(vkd, device, swapchain1.get());
903 	const vector<vk::VkImage>				swapchainImages2			= vk::wsi::getSwapchainImages(vkd, device, swapchain2.get());
904 	const vk::Unique<vk::VkCommandPool>		commandPool					(createCommandPool(vkd, device, vk::VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, devHelper.queueFamilyIndex));
905 	const vk::wsi::WsiTriangleRenderer		renderer1					(vkd,
906 																		 device,
907 																		 allocator,
908 																		 m_context.getBinaryCollection(),
909 																		 false,
910 																		 swapchainImages1,
911 																		 swapchainImages1,
912 																		 swapchainInfo1.imageFormat,
913 																		 tcu::UVec2(swapchainInfo1.imageExtent.width, swapchainInfo1.imageExtent.height));
914 	const vk::wsi::WsiTriangleRenderer		renderer2					(vkd,
915 																		 device,
916 																		 allocator,
917 																		 m_context.getBinaryCollection(),
918 																		 false,
919 																		 swapchainImages2,
920 																		 swapchainImages2,
921 																		 swapchainInfo2.imageFormat,
922 																		 tcu::UVec2(swapchainInfo2.imageExtent.width, swapchainInfo2.imageExtent.height));
923 	tcu::TestLog&							testLog						= m_context.getTestContext().getLog();
924 
925 	try
926 	{
927 		const size_t		maxQueuedFrames		= swapchainImages1.size()*2;
928 		FrameStreamObjects	frameStreamObjects1	(vkd, device, commandPool.get(), maxQueuedFrames);
929 		FrameStreamObjects	frameStreamObjects2	(vkd, device, commandPool.get(), maxQueuedFrames);
930 
931 		// Increasing ids for both swapchains, waiting on some to make sure we do not time out unexpectedly.
932 		const vector<DualIdAndWait> sequence =
933 		{
934 			{
935 				{ 1ull, false },
936 				{ 2ull, true  },
937 			},
938 			{
939 				{ 4ull, true  },
940 				{ 3ull, false },
941 			},
942 			{
943 				{ 5ull, true  },
944 				{ 6ull, true  },
945 			},
946 		};
947 
948 		for (const auto& step : sequence)
949 		{
950 			// Get objects for the next frames.
951 			FrameStreamObjects::FrameObjects frameObjects1 = frameStreamObjects1.newFrame();
952 			FrameStreamObjects::FrameObjects frameObjects2 = frameStreamObjects2.newFrame();
953 
954 			// Record and submit frame.
955 			deUint32 imageNdx1 = recordAndSubmitFrame(frameObjects1, renderer1, vkd, device, swapchain1.get(), swapchainImages1.size(), devHelper.queue, frameStreamObjects1.frameNumber(), testLog);
956 			deUint32 imageNdx2 = recordAndSubmitFrame(frameObjects2, renderer2, vkd, device, swapchain2.get(), swapchainImages2.size(), devHelper.queue, frameStreamObjects2.frameNumber(), testLog);
957 
958 			// Present both images at the same time with their corresponding ids.
959 			const deUint64				presentIdsArr[] = { step.idWait1.presentId, step.idWait2.presentId };
960 			const vk::VkPresentIdKHR	presentId		=
961 			{
962 				vk::VK_STRUCTURE_TYPE_PRESENT_ID_KHR,							// VkStructureType		sType;
963 				nullptr,														// const void*			pNext;
964 				static_cast<deUint32>(DE_LENGTH_OF_ARRAY(presentIdsArr)),		// deUint32				swapchainCount;
965 				presentIdsArr,													// const deUint64*		pPresentIds;
966 			};
967 
968 			const vk::VkSemaphore		semaphoreArr[]	= { frameObjects1.renderCompleteSemaphore, frameObjects2.renderCompleteSemaphore };
969 			const vk::VkSwapchainKHR	swapchainArr[]	= { swapchain1.get(), swapchain2.get() };
970 			const deUint32				imgIndexArr[]	= { imageNdx1, imageNdx2 };
971 			const vk::VkPresentInfoKHR	presentInfo		=
972 			{
973 				vk::VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
974 				&presentId,
975 				static_cast<deUint32>(DE_LENGTH_OF_ARRAY(semaphoreArr)),
976 				semaphoreArr,
977 				static_cast<deUint32>(DE_LENGTH_OF_ARRAY(swapchainArr)),
978 				swapchainArr,
979 				imgIndexArr,
980 				nullptr,
981 			};
982 
983 			VK_CHECK(vkd.queuePresentKHR(devHelper.queue, &presentInfo));
984 
985 			const IdAndWait* idWaitArr[] = { &step.idWait1, &step.idWait2 };
986 			for (int i = 0; i < DE_LENGTH_OF_ARRAY(idWaitArr); ++i)
987 			{
988 				if (idWaitArr[i]->wait)
989 					VK_CHECK(vkd.waitForPresentKHR(device, swapchainArr[i], idWaitArr[i]->presentId, k10sec));
990 			}
991 		}
992 
993 		// Wait until device is idle.
994 		VK_CHECK(vkd.deviceWaitIdle(device));
995 
996 		return tcu::TestStatus::pass("Pass");
997 	}
998 	catch (...)
999 	{
1000 		// Make sure device is idle before destroying resources
1001 		vkd.deviceWaitIdle(device);
1002 		throw;
1003 	}
1004 
1005 	return tcu::TestStatus(QP_TEST_RESULT_INTERNAL_ERROR, "Reached unreachable code");
1006 }
1007 
1008 // Templated class for every instance type.
1009 template <class T>	// T is the test instance class.
1010 class PresentIdWaitCase : public TestCase
1011 {
1012 public:
1013 							PresentIdWaitCase	(vk::wsi::Type wsiType, tcu::TestContext& ctx, const std::string& name, const std::string& description);
~PresentIdWaitCase(void)1014 	virtual					~PresentIdWaitCase	(void) {}
1015 	virtual void			initPrograms		(vk::SourceCollections& programCollection) const;
1016 	virtual TestInstance*	createInstance		(Context& context) const;
1017 	virtual void			checkSupport		(Context& context) const;
1018 
1019 protected:
1020 	vk::wsi::Type			m_wsiType;
1021 };
1022 
1023 template <class T>
PresentIdWaitCase(vk::wsi::Type wsiType,tcu::TestContext & ctx,const std::string & name,const std::string & description)1024 PresentIdWaitCase<T>::PresentIdWaitCase (vk::wsi::Type wsiType, tcu::TestContext& ctx, const std::string& name, const std::string& description)
1025 	: TestCase(ctx, name, description), m_wsiType(wsiType)
1026 {
1027 }
1028 
1029 template <class T>
initPrograms(vk::SourceCollections & programCollection) const1030 void PresentIdWaitCase<T>::initPrograms (vk::SourceCollections& programCollection) const
1031 {
1032 	vk::wsi::WsiTriangleRenderer::getPrograms(programCollection);
1033 }
1034 
1035 template <class T>
createInstance(Context & context) const1036 TestInstance* PresentIdWaitCase<T>::createInstance (Context& context) const
1037 {
1038 	return new T(context, m_wsiType);
1039 }
1040 
1041 template <class T>
checkSupport(Context & context) const1042 void PresentIdWaitCase<T>::checkSupport (Context& context) const
1043 {
1044 	// Check instance extension support.
1045 	const auto instanceExtensions = getRequiredInstanceExtensions(m_wsiType);
1046 	for (const auto& ext : instanceExtensions)
1047 	{
1048 		if (!context.isInstanceFunctionalitySupported(ext))
1049 			TCU_THROW(NotSupportedError, ext + string(" is not supported"));
1050 	}
1051 
1052 	// Check device extension support.
1053 	const auto& vki                 = context.getInstanceInterface();
1054 	const auto  physDev             = context.getPhysicalDevice();
1055 	const auto  supportedDeviceExts = vk::enumerateDeviceExtensionProperties(vki, physDev, nullptr);
1056 	const auto  mandatoryDeviceExts = getMandatoryDeviceExtensions();
1057 
1058 	auto checkedDeviceExts = T::requiredDeviceExts();
1059 	for (const auto& ext : mandatoryDeviceExts)
1060 		checkedDeviceExts.push_back(ext);
1061 
1062 	for (const auto& ext : checkedDeviceExts)
1063 	{
1064 		if (!vk::isExtensionSupported(supportedDeviceExts, vk::RequiredExtension(ext)))
1065 			TCU_THROW(NotSupportedError, ext + string(" is not supported"));
1066 	}
1067 }
1068 
createPresentIdTests(tcu::TestCaseGroup * testGroup,vk::wsi::Type wsiType)1069 void createPresentIdTests (tcu::TestCaseGroup* testGroup, vk::wsi::Type wsiType)
1070 {
1071 	testGroup->addChild(new PresentIdWaitCase<PresentIdZeroInstance>		(wsiType, testGroup->getTestContext(), "zero",			"Use present id zero"));
1072 	testGroup->addChild(new PresentIdWaitCase<PresentIdIncreasingInstance>	(wsiType, testGroup->getTestContext(), "increasing",	"Use increasing present ids"));
1073 	testGroup->addChild(new PresentIdWaitCase<PresentIdInterleavedInstance>	(wsiType, testGroup->getTestContext(), "interleaved",	"Use increasing present ids interleaved with no ids"));
1074 }
1075 
createPresentWaitTests(tcu::TestCaseGroup * testGroup,vk::wsi::Type wsiType)1076 void createPresentWaitTests (tcu::TestCaseGroup* testGroup, vk::wsi::Type wsiType)
1077 {
1078 	testGroup->addChild(new PresentIdWaitCase<PresentWaitSingleFrameInstance>	(wsiType, testGroup->getTestContext(), "single_no_timeout",	"Present single frame with no expected timeout"));
1079 	testGroup->addChild(new PresentIdWaitCase<PresentWaitPastFrameInstance>		(wsiType, testGroup->getTestContext(), "past_no_timeout",	"Wait for past frame with no expected timeout"));
1080 	testGroup->addChild(new PresentIdWaitCase<PresentWaitNoFramesInstance>		(wsiType, testGroup->getTestContext(), "no_frames",			"Expect timeout before submitting any frame"));
1081 	testGroup->addChild(new PresentIdWaitCase<PresentWaitNoFrameIdInstance>		(wsiType, testGroup->getTestContext(), "no_frame_id",		"Expect timeout after submitting frames with no id"));
1082 	testGroup->addChild(new PresentIdWaitCase<PresentWaitFutureFrameInstance>	(wsiType, testGroup->getTestContext(), "future_frame",		"Expect timeout when waiting for a future frame"));
1083 	testGroup->addChild(new PresentIdWaitCase<PresentWaitDualInstance>			(wsiType, testGroup->getTestContext(), "two_swapchains",	"Smoke test using two windows, surfaces and swapchains"));
1084 }
1085 
1086 } // anonymous
1087 
createPresentIdWaitTests(tcu::TestCaseGroup * testGroup,vk::wsi::Type wsiType)1088 void createPresentIdWaitTests (tcu::TestCaseGroup* testGroup, vk::wsi::Type wsiType)
1089 {
1090 	de::MovePtr<tcu::TestCaseGroup>	idGroup		(new tcu::TestCaseGroup(testGroup->getTestContext(), "id",		"VK_KHR_present_id tests"));
1091 	de::MovePtr<tcu::TestCaseGroup>	waitGroup	(new tcu::TestCaseGroup(testGroup->getTestContext(), "wait",	"VK_KHR_present_wait tests"));
1092 
1093 	createPresentIdTests	(idGroup.get(),		wsiType);
1094 	createPresentWaitTests	(waitGroup.get(),	wsiType);
1095 
1096 	testGroup->addChild(idGroup.release());
1097 	testGroup->addChild(waitGroup.release());
1098 }
1099 
1100 } // wsi
1101 } // vkt
1102 
1103