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