1 /*-------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2017 Google Inc.
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  *//*!
20  * \file
21  * \brief Tests for VK_GOOGLE_display_timing
22  *//*--------------------------------------------------------------------*/
23 
24 #include "vkRefUtil.hpp"
25 #include "vkWsiPlatform.hpp"
26 #include "vkWsiUtil.hpp"
27 #include "vkQueryUtil.hpp"
28 #include "vkDeviceUtil.hpp"
29 #include "vkPlatform.hpp"
30 #include "vkTypeUtil.hpp"
31 #include "vkPrograms.hpp"
32 #include "vkCmdUtil.hpp"
33 #include "vkWsiUtil.hpp"
34 #include "vkCmdUtil.hpp"
35 #include "vkObjUtil.hpp"
36 
37 #include "vktWsiDisplayTimingTests.hpp"
38 #include "vktTestCaseUtil.hpp"
39 #include "vktTestGroupUtil.hpp"
40 
41 #include "tcuPlatform.hpp"
42 #include "tcuResultCollector.hpp"
43 #include "tcuTestLog.hpp"
44 
45 #include "deClock.h"
46 
47 #include <vector>
48 #include <string>
49 
50 using std::vector;
51 using std::string;
52 
53 using tcu::Maybe;
54 using tcu::UVec2;
55 using tcu::TestLog;
56 
57 namespace vkt
58 {
59 namespace wsi
60 {
61 namespace
62 {
63 static const deUint64 MILLISECOND = 1000ull * 1000ull;
64 static const deUint64 SECOND = 1000ull * MILLISECOND;
65 
66 typedef vector<vk::VkExtensionProperties> Extensions;
67 
checkAllSupported(const Extensions & supportedExtensions,const vector<string> & requiredExtensions)68 void checkAllSupported (const Extensions& supportedExtensions, const vector<string>& requiredExtensions)
69 {
70 	for (vector<string>::const_iterator requiredExtName = requiredExtensions.begin();
71 		 requiredExtName != requiredExtensions.end();
72 		 ++requiredExtName)
73 	{
74 		if (!isExtensionSupported(supportedExtensions, vk::RequiredExtension(*requiredExtName)))
75 			TCU_THROW(NotSupportedError, (*requiredExtName + " is not supported").c_str());
76 	}
77 }
78 
createInstanceWithWsi(const vk::PlatformInterface & vkp,deUint32 version,const Extensions & supportedExtensions,vk::wsi::Type wsiType)79 vk::Move<vk::VkInstance> createInstanceWithWsi (const vk::PlatformInterface&		vkp,
80 												deUint32							version,
81 												const Extensions&					supportedExtensions,
82 												vk::wsi::Type						wsiType)
83 {
84 	vector<string>	extensions;
85 
86 	extensions.push_back("VK_KHR_surface");
87 	extensions.push_back(getExtensionName(wsiType));
88 
89 	checkAllSupported(supportedExtensions, extensions);
90 
91 	return vk::createDefaultInstance(vkp, version, vector<string>(), extensions);
92 }
93 
getDeviceNullFeatures(void)94 vk::VkPhysicalDeviceFeatures getDeviceNullFeatures (void)
95 {
96 	vk::VkPhysicalDeviceFeatures features;
97 	deMemset(&features, 0, sizeof(features));
98 	return features;
99 }
100 
getNumQueueFamilyIndices(const vk::InstanceInterface & vki,vk::VkPhysicalDevice physicalDevice)101 deUint32 getNumQueueFamilyIndices (const vk::InstanceInterface& vki, vk::VkPhysicalDevice physicalDevice)
102 {
103 	deUint32	numFamilies		= 0;
104 
105 	vki.getPhysicalDeviceQueueFamilyProperties(physicalDevice, &numFamilies, DE_NULL);
106 
107 	return numFamilies;
108 }
109 
getSupportedQueueFamilyIndices(const vk::InstanceInterface & vki,vk::VkPhysicalDevice physicalDevice,vk::VkSurfaceKHR surface)110 vector<deUint32> getSupportedQueueFamilyIndices (const vk::InstanceInterface& vki, vk::VkPhysicalDevice physicalDevice, vk::VkSurfaceKHR surface)
111 {
112 	const deUint32		numTotalFamilyIndices	= getNumQueueFamilyIndices(vki, physicalDevice);
113 	vector<deUint32>	supportedFamilyIndices;
114 
115 	for (deUint32 queueFamilyNdx = 0; queueFamilyNdx < numTotalFamilyIndices; ++queueFamilyNdx)
116 	{
117 		if (vk::wsi::getPhysicalDeviceSurfaceSupport(vki, physicalDevice, queueFamilyNdx, surface) == VK_TRUE)
118 			supportedFamilyIndices.push_back(queueFamilyNdx);
119 	}
120 
121 	return supportedFamilyIndices;
122 }
123 
chooseQueueFamilyIndex(const vk::InstanceInterface & vki,vk::VkPhysicalDevice physicalDevice,vk::VkSurfaceKHR surface)124 deUint32 chooseQueueFamilyIndex (const vk::InstanceInterface& vki, vk::VkPhysicalDevice physicalDevice, vk::VkSurfaceKHR surface)
125 {
126 	const vector<deUint32>	supportedFamilyIndices	= getSupportedQueueFamilyIndices(vki, physicalDevice, surface);
127 
128 	if (supportedFamilyIndices.empty())
129 		TCU_THROW(NotSupportedError, "Device doesn't support presentation");
130 
131 	return supportedFamilyIndices[0];
132 }
133 
createDeviceWithWsi(const vk::PlatformInterface & vkp,const vk::VkInstance instance,const vk::InstanceInterface & vki,vk::VkPhysicalDevice physicalDevice,const Extensions & supportedExtensions,const deUint32 queueFamilyIndex,bool requiresDisplayTiming,const vk::VkAllocationCallbacks * pAllocator=DE_NULL)134 vk::Move<vk::VkDevice> createDeviceWithWsi (const vk::PlatformInterface&		vkp,
135 											const vk::VkInstance				instance,
136 											const vk::InstanceInterface&		vki,
137 											vk::VkPhysicalDevice				physicalDevice,
138 											const Extensions&					supportedExtensions,
139 											const deUint32						queueFamilyIndex,
140 											bool								requiresDisplayTiming,
141 											const vk::VkAllocationCallbacks*	pAllocator = DE_NULL)
142 {
143 	const float							queuePriorities[]	= { 1.0f };
144 	const vk::VkDeviceQueueCreateInfo	queueInfos[]		=
145 	{
146 		{
147 			vk::VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
148 			DE_NULL,
149 			(vk::VkDeviceQueueCreateFlags)0,
150 			queueFamilyIndex,
151 			DE_LENGTH_OF_ARRAY(queuePriorities),
152 			&queuePriorities[0]
153 		}
154 	};
155 	const vk::VkPhysicalDeviceFeatures	features		= getDeviceNullFeatures();
156 	const char* const					extensions[]	=
157 	{
158 		"VK_KHR_swapchain",
159 		"VK_GOOGLE_display_timing"
160 	};
161 
162 	const vk::VkDeviceCreateInfo		deviceParams	=
163 	{
164 		vk::VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
165 		DE_NULL,
166 		(vk::VkDeviceCreateFlags)0,
167 		DE_LENGTH_OF_ARRAY(queueInfos),
168 		&queueInfos[0],
169 		0u,
170 		DE_NULL,
171 		requiresDisplayTiming ? 2u : 1u,
172 		DE_ARRAY_BEGIN(extensions),
173 		&features
174 	};
175 
176 	for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(extensions); ++ndx)
177 	{
178 		if (!isExtensionSupported(supportedExtensions, vk::RequiredExtension(extensions[ndx])))
179 			TCU_THROW(NotSupportedError, (string(extensions[ndx]) + " is not supported").c_str());
180 	}
181 
182 	return createDevice(vkp, instance, vki, physicalDevice, &deviceParams, pAllocator);
183 }
184 
createDisplay(const vk::Platform & platform,const Extensions & supportedExtensions,vk::wsi::Type wsiType)185 de::MovePtr<vk::wsi::Display> createDisplay (const vk::Platform&	platform,
186 											 const Extensions&		supportedExtensions,
187 											 vk::wsi::Type			wsiType)
188 {
189 	try
190 	{
191 		return de::MovePtr<vk::wsi::Display>(platform.createWsiDisplay(wsiType));
192 	}
193 	catch (const tcu::NotSupportedError& e)
194 	{
195 		if (isExtensionSupported(supportedExtensions, vk::RequiredExtension(getExtensionName(wsiType))) &&
196 		    platform.hasDisplay(wsiType))
197 		{
198 			// If VK_KHR_{platform}_surface was supported, vk::Platform implementation
199 			// must support creating native display & window for that WSI type.
200 			throw tcu::TestError(e.getMessage());
201 		}
202 		else
203 			throw;
204 	}
205 }
206 
createWindow(const vk::wsi::Display & display,const Maybe<UVec2> & initialSize)207 de::MovePtr<vk::wsi::Window> createWindow (const vk::wsi::Display& display, const Maybe<UVec2>& initialSize)
208 {
209 	try
210 	{
211 		return de::MovePtr<vk::wsi::Window>(display.createWindow(initialSize));
212 	}
213 	catch (const tcu::NotSupportedError& e)
214 	{
215 		// See createDisplay - assuming that wsi::Display was supported platform port
216 		// should also support creating a window.
217 		throw tcu::TestError(e.getMessage());
218 	}
219 }
220 
initSemaphores(const vk::DeviceInterface & vkd,vk::VkDevice device,std::vector<vk::VkSemaphore> & semaphores)221 void initSemaphores (const vk::DeviceInterface&		vkd,
222 					 vk::VkDevice					device,
223 					 std::vector<vk::VkSemaphore>&	semaphores)
224 {
225 	for (size_t ndx = 0; ndx < semaphores.size(); ndx++)
226 		semaphores[ndx] = createSemaphore(vkd, device).disown();
227 }
228 
deinitSemaphores(const vk::DeviceInterface & vkd,vk::VkDevice device,std::vector<vk::VkSemaphore> & semaphores)229 void deinitSemaphores (const vk::DeviceInterface&	vkd,
230 					 vk::VkDevice					device,
231 					 std::vector<vk::VkSemaphore>&	semaphores)
232 {
233 	for (size_t ndx = 0; ndx < semaphores.size(); ndx++)
234 	{
235 		if (semaphores[ndx] != (vk::VkSemaphore)0)
236 			vkd.destroySemaphore(device, semaphores[ndx], DE_NULL);
237 
238 		semaphores[ndx] = (vk::VkSemaphore)0;
239 	}
240 
241 	semaphores.clear();
242 }
243 
initFences(const vk::DeviceInterface & vkd,vk::VkDevice device,std::vector<vk::VkFence> & fences)244 void initFences (const vk::DeviceInterface&	vkd,
245 				 vk::VkDevice				device,
246 				 std::vector<vk::VkFence>&	fences)
247 {
248 	for (size_t ndx = 0; ndx < fences.size(); ndx++)
249 		fences[ndx] = createFence(vkd, device).disown();
250 }
251 
deinitFences(const vk::DeviceInterface & vkd,vk::VkDevice device,std::vector<vk::VkFence> & fences)252 void deinitFences (const vk::DeviceInterface&	vkd,
253 				   vk::VkDevice					device,
254 				   std::vector<vk::VkFence>&	fences)
255 {
256 	for (size_t ndx = 0; ndx < fences.size(); ndx++)
257 	{
258 		if (fences[ndx] != (vk::VkFence)0)
259 			vkd.destroyFence(device, fences[ndx], DE_NULL);
260 
261 		fences[ndx] = (vk::VkFence)0;
262 	}
263 
264 	fences.clear();
265 }
266 
cmdRenderFrame(const vk::DeviceInterface & vkd,vk::VkCommandBuffer commandBuffer,vk::VkPipelineLayout pipelineLayout,vk::VkPipeline pipeline,size_t frameNdx,deUint32 quadCount)267 void cmdRenderFrame (const vk::DeviceInterface&	vkd,
268 					 vk::VkCommandBuffer		commandBuffer,
269 					 vk::VkPipelineLayout		pipelineLayout,
270 					 vk::VkPipeline				pipeline,
271 					 size_t						frameNdx,
272 					 deUint32					quadCount)
273 {
274 	const deUint32	frameNdxValue	= (deUint32)frameNdx;
275 
276 	vkd.cmdPushConstants(commandBuffer, pipelineLayout, vk::VK_SHADER_STAGE_FRAGMENT_BIT, 0u, 4u, &frameNdxValue);
277 	vkd.cmdBindPipeline(commandBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
278 	vkd.cmdDraw(commandBuffer, quadCount * 6u, 1u, 0u, 0u);
279 }
280 
createCommandBuffer(const vk::DeviceInterface & vkd,vk::VkDevice device,vk::VkCommandPool commandPool,vk::VkPipelineLayout pipelineLayout,vk::VkRenderPass renderPass,vk::VkFramebuffer framebuffer,vk::VkPipeline pipeline,size_t frameNdx,deUint32 quadCount,deUint32 imageWidth,deUint32 imageHeight)281 vk::Move<vk::VkCommandBuffer> createCommandBuffer (const vk::DeviceInterface&	vkd,
282 												   vk::VkDevice					device,
283 												   vk::VkCommandPool			commandPool,
284 												   vk::VkPipelineLayout			pipelineLayout,
285 												   vk::VkRenderPass				renderPass,
286 												   vk::VkFramebuffer			framebuffer,
287 												   vk::VkPipeline				pipeline,
288 												   size_t						frameNdx,
289 												   deUint32						quadCount,
290 												   deUint32						imageWidth,
291 												   deUint32						imageHeight)
292 {
293 	const vk::VkCommandBufferAllocateInfo allocateInfo =
294 	{
295 		vk::VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
296 		DE_NULL,
297 
298 		commandPool,
299 		vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY,
300 		1
301 	};
302 
303 	vk::Move<vk::VkCommandBuffer>	commandBuffer	(vk::allocateCommandBuffer(vkd, device, &allocateInfo));
304 	beginCommandBuffer(vkd, *commandBuffer, 0u);
305 
306 	beginRenderPass(vkd, *commandBuffer, renderPass, framebuffer, vk::makeRect2D(0, 0, imageWidth, imageHeight), tcu::Vec4(0.25f, 0.5f, 0.75f, 1.0f));
307 
308 	cmdRenderFrame(vkd, *commandBuffer, pipelineLayout, pipeline, frameNdx, quadCount);
309 
310 	endRenderPass(vkd, *commandBuffer);
311 
312 	endCommandBuffer(vkd, *commandBuffer);
313 	return commandBuffer;
314 }
315 
deinitCommandBuffers(const vk::DeviceInterface & vkd,vk::VkDevice device,vk::VkCommandPool commandPool,std::vector<vk::VkCommandBuffer> & commandBuffers)316 void deinitCommandBuffers (const vk::DeviceInterface&			vkd,
317 						   vk::VkDevice							device,
318 						   vk::VkCommandPool					commandPool,
319 						   std::vector<vk::VkCommandBuffer>&	commandBuffers)
320 {
321 	for (size_t ndx = 0; ndx < commandBuffers.size(); ndx++)
322 	{
323 		if (commandBuffers[ndx] != (vk::VkCommandBuffer)0)
324 			vkd.freeCommandBuffers(device, commandPool, 1u,  &commandBuffers[ndx]);
325 
326 		commandBuffers[ndx] = (vk::VkCommandBuffer)0;
327 	}
328 
329 	commandBuffers.clear();
330 }
331 
createCommandPool(const vk::DeviceInterface & vkd,vk::VkDevice device,deUint32 queueFamilyIndex)332 vk::Move<vk::VkCommandPool> createCommandPool (const vk::DeviceInterface&	vkd,
333 											   vk::VkDevice					device,
334 											   deUint32						queueFamilyIndex)
335 {
336 	const vk::VkCommandPoolCreateInfo createInfo =
337 	{
338 		vk::VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
339 		DE_NULL,
340 		0u,
341 		queueFamilyIndex
342 	};
343 
344 	return vk::createCommandPool(vkd, device, &createInfo);
345 }
346 
createFramebuffer(const vk::DeviceInterface & vkd,vk::VkDevice device,vk::VkRenderPass renderPass,vk::VkImageView imageView,deUint32 width,deUint32 height)347 vk::Move<vk::VkFramebuffer>	createFramebuffer (const vk::DeviceInterface&	vkd,
348 											   vk::VkDevice					device,
349 											   vk::VkRenderPass				renderPass,
350 											   vk::VkImageView				imageView,
351 											   deUint32						width,
352 											   deUint32						height)
353 {
354 	const vk::VkFramebufferCreateInfo createInfo =
355 	{
356 		vk::VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
357 		DE_NULL,
358 
359 		0u,
360 		renderPass,
361 		1u,
362 		&imageView,
363 		width,
364 		height,
365 		1u
366 	};
367 
368 	return vk::createFramebuffer(vkd, device, &createInfo);
369 }
370 
initFramebuffers(const vk::DeviceInterface & vkd,vk::VkDevice device,vk::VkRenderPass renderPass,std::vector<vk::VkImageView> imageViews,deUint32 width,deUint32 height,std::vector<vk::VkFramebuffer> & framebuffers)371 void initFramebuffers (const vk::DeviceInterface&		vkd,
372 					   vk::VkDevice						device,
373 					   vk::VkRenderPass					renderPass,
374 					   std::vector<vk::VkImageView>		imageViews,
375 					   deUint32							width,
376 					   deUint32							height,
377 					   std::vector<vk::VkFramebuffer>&	framebuffers)
378 {
379 	DE_ASSERT(framebuffers.size() == imageViews.size());
380 
381 	for (size_t ndx = 0; ndx < framebuffers.size(); ndx++)
382 		framebuffers[ndx] = createFramebuffer(vkd, device, renderPass, imageViews[ndx], width, height).disown();
383 }
384 
deinitFramebuffers(const vk::DeviceInterface & vkd,vk::VkDevice device,std::vector<vk::VkFramebuffer> & framebuffers)385 void deinitFramebuffers (const vk::DeviceInterface&			vkd,
386 						 vk::VkDevice						device,
387 						 std::vector<vk::VkFramebuffer>&	framebuffers)
388 {
389 	for (size_t ndx = 0; ndx < framebuffers.size(); ndx++)
390 	{
391 		if (framebuffers[ndx] != (vk::VkFramebuffer)0)
392 			vkd.destroyFramebuffer(device, framebuffers[ndx], DE_NULL);
393 
394 		framebuffers[ndx] = (vk::VkFramebuffer)0;
395 	}
396 
397 	framebuffers.clear();
398 }
399 
createImageView(const vk::DeviceInterface & vkd,vk::VkDevice device,vk::VkImage image,vk::VkFormat format)400 vk::Move<vk::VkImageView> createImageView (const vk::DeviceInterface&	vkd,
401 										   vk::VkDevice					device,
402 										   vk::VkImage					image,
403 										   vk::VkFormat					format)
404 {
405 	const vk::VkImageViewCreateInfo	createInfo =
406 	{
407 		vk::VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
408 		DE_NULL,
409 
410 		0u,
411 		image,
412 		vk::VK_IMAGE_VIEW_TYPE_2D,
413 		format,
414 		vk::makeComponentMappingRGBA(),
415 		{
416 			vk::VK_IMAGE_ASPECT_COLOR_BIT,
417 			0u,
418 			1u,
419 			0u,
420 			1u
421 		}
422 	};
423 
424 	return vk::createImageView(vkd, device, &createInfo, DE_NULL);
425 }
426 
initImageViews(const vk::DeviceInterface & vkd,vk::VkDevice device,const std::vector<vk::VkImage> & images,vk::VkFormat format,std::vector<vk::VkImageView> & imageViews)427 void initImageViews (const vk::DeviceInterface&			vkd,
428 					 vk::VkDevice						device,
429 					 const std::vector<vk::VkImage>&	images,
430 					 vk::VkFormat						format,
431 					 std::vector<vk::VkImageView>&		imageViews)
432 {
433 	DE_ASSERT(images.size() == imageViews.size());
434 
435 	for (size_t ndx = 0; ndx < imageViews.size(); ndx++)
436 		imageViews[ndx] = createImageView(vkd, device, images[ndx], format).disown();
437 }
438 
deinitImageViews(const vk::DeviceInterface & vkd,vk::VkDevice device,std::vector<vk::VkImageView> & imageViews)439 void deinitImageViews (const vk::DeviceInterface&		vkd,
440 					   vk::VkDevice						device,
441 					   std::vector<vk::VkImageView>&	imageViews)
442 {
443 	for (size_t ndx = 0; ndx < imageViews.size(); ndx++)
444 	{
445 		if (imageViews[ndx] != (vk::VkImageView)0)
446 			vkd.destroyImageView(device, imageViews[ndx], DE_NULL);
447 
448 		imageViews[ndx] = (vk::VkImageView)0;
449 	}
450 
451 	imageViews.clear();
452 }
453 
createRenderPass(const vk::DeviceInterface & vkd,vk::VkDevice device,vk::VkFormat format)454 vk::Move<vk::VkRenderPass> createRenderPass (const vk::DeviceInterface&	vkd,
455 											 vk::VkDevice				device,
456 											 vk::VkFormat				format)
457 {
458 	return vk::makeRenderPass(vkd, device, format, vk::VK_FORMAT_UNDEFINED, vk::VK_ATTACHMENT_LOAD_OP_LOAD, vk::VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
459 }
460 
createPipeline(const vk::DeviceInterface & vkd,vk::VkDevice device,vk::VkRenderPass renderPass,vk::VkPipelineLayout layout,vk::VkShaderModule vertexShaderModule,vk::VkShaderModule fragmentShaderModule,deUint32 width,deUint32 height)461 vk::Move<vk::VkPipeline> createPipeline (const vk::DeviceInterface&	vkd,
462 										 vk::VkDevice				device,
463 										 vk::VkRenderPass			renderPass,
464 										 vk::VkPipelineLayout		layout,
465 										 vk::VkShaderModule			vertexShaderModule,
466 										 vk::VkShaderModule			fragmentShaderModule,
467 										 deUint32					width,
468 										 deUint32					height)
469 {
470 	const vk::VkPipelineVertexInputStateCreateInfo	vertexInputState	=
471 	{
472 		vk::VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
473 		DE_NULL,
474 		0u,
475 		0u,
476 		DE_NULL,
477 		0u,
478 		DE_NULL
479 	};
480 	const std::vector<vk::VkViewport>				viewports			(1, vk::makeViewport(tcu::UVec2(width, height)));
481 	const std::vector<vk::VkRect2D>					scissors			(1, vk::makeRect2D(tcu::UVec2(width, height)));
482 
483 	return vk::makeGraphicsPipeline(vkd,										// const DeviceInterface&                        vk
484 									device,										// const VkDevice                                device
485 									layout,										// const VkPipelineLayout                        pipelineLayout
486 									vertexShaderModule,							// const VkShaderModule                          vertexShaderModule
487 									DE_NULL,									// const VkShaderModule                          tessellationControlShaderModule
488 									DE_NULL,									// const VkShaderModule                          tessellationEvalShaderModule
489 									DE_NULL,									// const VkShaderModule                          geometryShaderModule
490 									fragmentShaderModule,						// const VkShaderModule                          fragmentShaderModule
491 									renderPass,									// const VkRenderPass                            renderPass
492 									viewports,									// const std::vector<VkViewport>&                viewports
493 									scissors,									// const std::vector<VkRect2D>&                  scissors
494 									vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,	// const VkPrimitiveTopology                     topology
495 									0u,											// const deUint32                                subpass
496 									0u,											// const deUint32                                patchControlPoints
497 									&vertexInputState);							// const VkPipelineVertexInputStateCreateInfo*   vertexInputStateCreateInfo
498 }
499 
createPipelineLayout(const vk::DeviceInterface & vkd,vk::VkDevice device)500 vk::Move<vk::VkPipelineLayout> createPipelineLayout (const vk::DeviceInterface&	vkd,
501 													 vk::VkDevice				device)
502 {
503 	const vk::VkPushConstantRange			pushConstants[] =
504 	{
505 		{
506 			vk::VK_SHADER_STAGE_FRAGMENT_BIT,
507 			0u,
508 			4u
509 		}
510 	};
511 	const vk::VkPipelineLayoutCreateInfo	createInfo	=
512 	{
513 		vk::VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
514 		DE_NULL,
515 		0u,
516 
517 		0u,
518 		DE_NULL,
519 
520 		DE_LENGTH_OF_ARRAY(pushConstants),
521 		pushConstants
522 	};
523 
524 	return vk::createPipelineLayout(vkd, device, &createInfo);
525 }
526 
527 struct TestConfig
528 {
529 	vk::wsi::Type			wsiType;
530 	bool					useDisplayTiming;
531 	vk::VkPresentModeKHR	presentMode;
532 };
533 
534 class DisplayTimingTestInstance : public TestInstance
535 {
536 public:
537 												DisplayTimingTestInstance	(Context& context, const TestConfig& testConfig);
538 												~DisplayTimingTestInstance	(void);
539 
540 	tcu::TestStatus								iterate						(void);
541 
542 private:
543 	const bool								m_useDisplayTiming;
544 	const deUint32							m_quadCount;
545 	const vk::PlatformInterface&			m_vkp;
546 	const Extensions						m_instanceExtensions;
547 	const vk::Unique<vk::VkInstance>		m_instance;
548 	const vk::InstanceDriver				m_vki;
549 	const vk::VkPhysicalDevice				m_physicalDevice;
550 	const de::UniquePtr<vk::wsi::Display>	m_nativeDisplay;
551 	const de::UniquePtr<vk::wsi::Window>	m_nativeWindow;
552 	const vk::Unique<vk::VkSurfaceKHR>		m_surface;
553 
554 	const deUint32							m_queueFamilyIndex;
555 	const Extensions						m_deviceExtensions;
556 	const vk::Unique<vk::VkDevice>			m_device;
557 	const vk::DeviceDriver					m_vkd;
558 	const vk::VkQueue						m_queue;
559 
560 	const vk::Unique<vk::VkCommandPool>		m_commandPool;
561 	const vk::Unique<vk::VkShaderModule>	m_vertexShaderModule;
562 	const vk::Unique<vk::VkShaderModule>	m_fragmentShaderModule;
563 	const vk::Unique<vk::VkPipelineLayout>	m_pipelineLayout;
564 
565 	const vk::VkSurfaceCapabilitiesKHR		m_surfaceProperties;
566 	const vector<vk::VkSurfaceFormatKHR>	m_surfaceFormats;
567 	const vector<vk::VkPresentModeKHR>		m_presentModes;
568 
569 	tcu::ResultCollector					m_resultCollector;
570 
571 	vk::Move<vk::VkSwapchainKHR>			m_swapchain;
572 	std::vector<vk::VkImage>				m_swapchainImages;
573 
574 	vk::Move<vk::VkRenderPass>				m_renderPass;
575 	vk::Move<vk::VkPipeline>				m_pipeline;
576 
577 	std::vector<vk::VkImageView>			m_swapchainImageViews;
578 	std::vector<vk::VkFramebuffer>			m_framebuffers;
579 	std::vector<vk::VkCommandBuffer>		m_commandBuffers;
580 	std::vector<vk::VkSemaphore>			m_acquireSemaphores;
581 	std::vector<vk::VkSemaphore>			m_renderSemaphores;
582 	std::vector<vk::VkFence>				m_fences;
583 
584 	vk::VkSemaphore							m_freeAcquireSemaphore;
585 	vk::VkSemaphore							m_freeRenderSemaphore;
586 
587 	vk::VkSwapchainCreateInfoKHR			m_swapchainConfig;
588 
589 	const size_t							m_frameCount;
590 	size_t									m_frameNdx;
591 
592 	const size_t							m_maxOutOfDateCount;
593 	size_t									m_outOfDateCount;
594 
595 	std::map<deUint32, deUint64>			m_queuePresentTimes;
596 
597     vk::VkRefreshCycleDurationGOOGLE		m_rcDuration;
598 	deUint64								m_refreshDurationMultiplier;
599 	deUint64								m_targetIPD;
600 	deUint64								m_prevDesiredPresentTime;
601 	deUint32								m_nextPresentID;
602 	deUint32								m_ignoreThruPresentID;
603 	bool									m_ExpectImage80Late;
604 
605 	void									initSwapchainResources		(void);
606 	void									deinitSwapchainResources	(void);
607 	void									render						(void);
608 };
609 
createSwapchainConfig(vk::VkSurfaceKHR surface,deUint32 queueFamilyIndex,const vk::VkSurfaceCapabilitiesKHR & properties,const vector<vk::VkSurfaceFormatKHR> & formats,const vector<vk::VkPresentModeKHR> & presentModes,vk::VkPresentModeKHR presentMode)610 vk::VkSwapchainCreateInfoKHR createSwapchainConfig (vk::VkSurfaceKHR						surface,
611 													deUint32								queueFamilyIndex,
612 													const vk::VkSurfaceCapabilitiesKHR&		properties,
613 													const vector<vk::VkSurfaceFormatKHR>&	formats,
614 													const vector<vk::VkPresentModeKHR>&		presentModes,
615 													vk::VkPresentModeKHR					presentMode)
616 {
617 	const deUint32				imageLayers		= 1u;
618 	const vk::VkImageUsageFlags	imageUsage		= properties.supportedUsageFlags;
619 	const vk::VkBool32			clipped			= VK_FALSE;
620 
621 	const deUint32				imageWidth		= (properties.currentExtent.width != 0xFFFFFFFFu)
622 													? properties.currentExtent.width
623 													: de::min(1024u, properties.minImageExtent.width + ((properties.maxImageExtent.width - properties.minImageExtent.width) / 2));
624 	const deUint32				imageHeight		= (properties.currentExtent.height != 0xFFFFFFFFu)
625 													? properties.currentExtent.height
626 													: de::min(1024u, properties.minImageExtent.height + ((properties.maxImageExtent.height - properties.minImageExtent.height) / 2));
627 	const vk::VkExtent2D		imageSize		= { imageWidth, imageHeight };
628 
629 	{
630 		size_t presentModeNdx;
631 
632 		for (presentModeNdx = 0; presentModeNdx < presentModes.size(); presentModeNdx++)
633 		{
634 			if (presentModes[presentModeNdx] == presentMode)
635 				break;
636 		}
637 
638 		if (presentModeNdx == presentModes.size())
639 			TCU_THROW(NotSupportedError, "Present mode not supported");
640 	}
641 
642 	// Pick the first supported transform, alpha, and format:
643 	vk::VkSurfaceTransformFlagsKHR transform;
644 	for (transform = 1u; transform <= properties.supportedTransforms; transform = transform << 1u)
645 	{
646 		if ((properties.supportedTransforms & transform) != 0)
647 			break;
648     }
649 
650 	vk::VkCompositeAlphaFlagsKHR alpha;
651 	for (alpha = 1u; alpha <= properties.supportedCompositeAlpha; alpha = alpha << 1u)
652 	{
653 		if ((alpha & properties.supportedCompositeAlpha) != 0)
654 			break;
655 	}
656 
657 	{
658 		const vk::VkSurfaceTransformFlagBitsKHR	preTransform	= (vk::VkSurfaceTransformFlagBitsKHR)transform;
659 		const vk::VkCompositeAlphaFlagBitsKHR	compositeAlpha	= (vk::VkCompositeAlphaFlagBitsKHR)alpha;
660 		const vk::VkFormat						imageFormat		= formats[0].format;
661 		const vk::VkColorSpaceKHR				imageColorSpace	= formats[0].colorSpace;
662 		const vk::VkSwapchainCreateInfoKHR		createInfo		=
663 		{
664 			vk::VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
665 			DE_NULL,
666 			0u,
667 			surface,
668 			properties.minImageCount,
669 			imageFormat,
670 			imageColorSpace,
671 			imageSize,
672 			imageLayers,
673 			imageUsage,
674 			vk::VK_SHARING_MODE_EXCLUSIVE,
675 			1u,
676 			&queueFamilyIndex,
677 			preTransform,
678 			compositeAlpha,
679 			presentMode,
680 			clipped,
681 			(vk::VkSwapchainKHR)0
682 		};
683 
684 		return createInfo;
685 	}
686 }
687 
DisplayTimingTestInstance(Context & context,const TestConfig & testConfig)688 DisplayTimingTestInstance::DisplayTimingTestInstance (Context& context, const TestConfig& testConfig)
689 	: TestInstance				(context)
690 	, m_useDisplayTiming		(testConfig.useDisplayTiming)
691 	, m_quadCount				(16u)
692 	, m_vkp						(context.getPlatformInterface())
693 	, m_instanceExtensions		(vk::enumerateInstanceExtensionProperties(m_vkp, DE_NULL))
694 	, m_instance				(createInstanceWithWsi(m_vkp, context.getUsedApiVersion(), m_instanceExtensions, testConfig.wsiType))
695 	, m_vki						(m_vkp, *m_instance)
696 	, m_physicalDevice			(vk::chooseDevice(m_vki, *m_instance, context.getTestContext().getCommandLine()))
697 	, m_nativeDisplay			(createDisplay(context.getTestContext().getPlatform().getVulkanPlatform(), m_instanceExtensions, testConfig.wsiType))
698 	, m_nativeWindow			(createWindow(*m_nativeDisplay, tcu::nothing<UVec2>()))
699 	, m_surface					(vk::wsi::createSurface(m_vki, *m_instance, testConfig.wsiType, *m_nativeDisplay, *m_nativeWindow))
700 
701 	, m_queueFamilyIndex		(chooseQueueFamilyIndex(m_vki, m_physicalDevice, *m_surface))
702 	, m_deviceExtensions		(vk::enumerateDeviceExtensionProperties(m_vki, m_physicalDevice, DE_NULL))
703 	, m_device					(createDeviceWithWsi(m_vkp, *m_instance, m_vki, m_physicalDevice, m_deviceExtensions, m_queueFamilyIndex, testConfig.useDisplayTiming))
704 	, m_vkd						(m_vkp, *m_instance, *m_device)
705 	, m_queue					(getDeviceQueue(m_vkd, *m_device, m_queueFamilyIndex, 0u))
706 
707 	, m_commandPool				(createCommandPool(m_vkd, *m_device, m_queueFamilyIndex))
708 	, m_vertexShaderModule		(vk::createShaderModule(m_vkd, *m_device, context.getBinaryCollection().get("quad-vert"), 0u))
709 	, m_fragmentShaderModule	(vk::createShaderModule(m_vkd, *m_device, context.getBinaryCollection().get("quad-frag"), 0u))
710 	, m_pipelineLayout			(createPipelineLayout(m_vkd, *m_device))
711 
712 	, m_surfaceProperties		(vk::wsi::getPhysicalDeviceSurfaceCapabilities(m_vki, m_physicalDevice, *m_surface))
713 	, m_surfaceFormats			(vk::wsi::getPhysicalDeviceSurfaceFormats(m_vki, m_physicalDevice, *m_surface))
714 	, m_presentModes			(vk::wsi::getPhysicalDeviceSurfacePresentModes(m_vki, m_physicalDevice, *m_surface))
715 
716 	, m_freeAcquireSemaphore	((vk::VkSemaphore)0)
717 	, m_freeRenderSemaphore		((vk::VkSemaphore)0)
718 
719 	, m_swapchainConfig			(createSwapchainConfig(*m_surface, m_queueFamilyIndex, m_surfaceProperties, m_surfaceFormats, m_presentModes, testConfig.presentMode))
720 
721 	, m_frameCount				(60u * 5u)
722 	, m_frameNdx				(0u)
723 
724 	, m_maxOutOfDateCount		(20u)
725 	, m_outOfDateCount			(0u)
726 	, m_ExpectImage80Late		(false)
727 {
728 	{
729 		const tcu::ScopedLogSection surfaceInfo (m_context.getTestContext().getLog(), "SurfaceCapabilities", "SurfaceCapabilities");
730 		m_context.getTestContext().getLog() << TestLog::Message << m_surfaceProperties << TestLog::EndMessage;
731 	}
732 }
733 
~DisplayTimingTestInstance(void)734 DisplayTimingTestInstance::~DisplayTimingTestInstance (void)
735 {
736 	deinitSwapchainResources();
737 }
738 
initSwapchainResources(void)739 void DisplayTimingTestInstance::initSwapchainResources (void)
740 {
741 	const size_t		fenceCount	= 6;
742 	const deUint32		imageWidth	= m_swapchainConfig.imageExtent.width;
743 	const deUint32		imageHeight	= m_swapchainConfig.imageExtent.height;
744 	const vk::VkFormat	imageFormat	= m_swapchainConfig.imageFormat;
745 
746 	m_swapchain				= vk::createSwapchainKHR(m_vkd, *m_device, &m_swapchainConfig);
747 	m_swapchainImages		= vk::wsi::getSwapchainImages(m_vkd, *m_device, *m_swapchain);
748 
749 	m_renderPass			= createRenderPass(m_vkd, *m_device, imageFormat);
750 	m_pipeline				= createPipeline(m_vkd, *m_device, *m_renderPass, *m_pipelineLayout, *m_vertexShaderModule, *m_fragmentShaderModule, imageWidth, imageHeight);
751 
752 	m_swapchainImageViews	= std::vector<vk::VkImageView>(m_swapchainImages.size(), (vk::VkImageView)0);
753 	m_framebuffers			= std::vector<vk::VkFramebuffer>(m_swapchainImages.size(), (vk::VkFramebuffer)0);
754 	m_acquireSemaphores		= std::vector<vk::VkSemaphore>(m_swapchainImages.size(), (vk::VkSemaphore)0);
755 	m_renderSemaphores		= std::vector<vk::VkSemaphore>(m_swapchainImages.size(), (vk::VkSemaphore)0);
756 
757 	m_fences				= std::vector<vk::VkFence>(fenceCount, (vk::VkFence)0);
758 	m_commandBuffers		= std::vector<vk::VkCommandBuffer>(m_fences.size(), (vk::VkCommandBuffer)0);
759 
760 	m_freeAcquireSemaphore	= (vk::VkSemaphore)0;
761 	m_freeRenderSemaphore	= (vk::VkSemaphore)0;
762 
763 	m_freeAcquireSemaphore	= createSemaphore(m_vkd, *m_device).disown();
764 	m_freeRenderSemaphore	= createSemaphore(m_vkd, *m_device).disown();
765 
766 	initImageViews(m_vkd, *m_device, m_swapchainImages, imageFormat, m_swapchainImageViews);
767 	initFramebuffers(m_vkd, *m_device, *m_renderPass, m_swapchainImageViews, imageWidth, imageHeight, m_framebuffers);
768 	initSemaphores(m_vkd, *m_device, m_acquireSemaphores);
769 	initSemaphores(m_vkd, *m_device, m_renderSemaphores);
770 
771 	initFences(m_vkd, *m_device, m_fences);
772 
773 	if (m_useDisplayTiming)
774 	{
775 		// This portion should do interesting bits
776 		m_queuePresentTimes			= std::map<deUint32, deUint64>();
777 
778 		m_vkd.getRefreshCycleDurationGOOGLE(*m_device, *m_swapchain, &m_rcDuration);
779 
780 		m_refreshDurationMultiplier	= 1u;
781 		m_targetIPD					= m_rcDuration.refreshDuration;
782 		m_prevDesiredPresentTime	= 0u;
783 		m_nextPresentID				= 0u;
784 		m_ignoreThruPresentID		= 0u;
785 	}
786 }
787 
deinitSwapchainResources(void)788 void DisplayTimingTestInstance::deinitSwapchainResources (void)
789 {
790 	VK_CHECK(m_vkd.queueWaitIdle(m_queue));
791 
792 	if (m_freeAcquireSemaphore != (vk::VkSemaphore)0)
793 	{
794 		m_vkd.destroySemaphore(*m_device, m_freeAcquireSemaphore, DE_NULL);
795 		m_freeAcquireSemaphore = (vk::VkSemaphore)0;
796 	}
797 
798 	if (m_freeRenderSemaphore != (vk::VkSemaphore)0)
799 	{
800 		m_vkd.destroySemaphore(*m_device, m_freeRenderSemaphore, DE_NULL);
801 		m_freeRenderSemaphore = (vk::VkSemaphore)0;
802 	}
803 
804 	deinitSemaphores(m_vkd, *m_device, m_acquireSemaphores);
805 	deinitSemaphores(m_vkd, *m_device, m_renderSemaphores);
806 	deinitFences(m_vkd, *m_device, m_fences);
807 	deinitCommandBuffers(m_vkd, *m_device, *m_commandPool, m_commandBuffers);
808 	deinitFramebuffers(m_vkd, *m_device, m_framebuffers);
809 	deinitImageViews(m_vkd, *m_device, m_swapchainImageViews);
810 
811 	m_swapchainImages.clear();
812 
813 	m_swapchain		= vk::Move<vk::VkSwapchainKHR>();
814 	m_renderPass	= vk::Move<vk::VkRenderPass>();
815 	m_pipeline		= vk::Move<vk::VkPipeline>();
816 
817 }
818 
getPastPresentationTiming(const vk::DeviceInterface & vkd,vk::VkDevice device,vk::VkSwapchainKHR swapchain)819 vector<vk::VkPastPresentationTimingGOOGLE> getPastPresentationTiming (const vk::DeviceInterface&	vkd,
820 																	  vk::VkDevice					device,
821 																	  vk::VkSwapchainKHR			swapchain)
822 {
823 	vector<vk::VkPastPresentationTimingGOOGLE>	pastPresentationTimings;
824 	deUint32									numPastPresentationTimings = 0;
825 
826 	vkd.getPastPresentationTimingGOOGLE(device, swapchain, &numPastPresentationTimings, DE_NULL);
827 
828 	pastPresentationTimings.resize(numPastPresentationTimings);
829 
830 	if (numPastPresentationTimings > 0)
831 		vkd.getPastPresentationTimingGOOGLE(device, swapchain, &numPastPresentationTimings, &pastPresentationTimings[0]);
832 
833 	return pastPresentationTimings;
834 }
835 
render(void)836 void DisplayTimingTestInstance::render (void)
837 {
838 	const deUint64		foreverNs		= ~0x0ull;
839 	const vk::VkFence	fence			= m_fences[m_frameNdx % m_fences.size()];
840 	const deUint32		width			= m_swapchainConfig.imageExtent.width;
841 	const deUint32		height			= m_swapchainConfig.imageExtent.height;
842 	tcu::TestLog&		log				= m_context.getTestContext().getLog();
843 
844 	// Throttle execution
845 	if (m_frameNdx >= m_fences.size())
846 	{
847 		VK_CHECK(m_vkd.waitForFences(*m_device, 1u, &fence, VK_TRUE, foreverNs));
848 		VK_CHECK(m_vkd.resetFences(*m_device, 1u, &fence));
849 
850 		m_vkd.freeCommandBuffers(*m_device, *m_commandPool, 1u, &m_commandBuffers[m_frameNdx % m_commandBuffers.size()]);
851 		m_commandBuffers[m_frameNdx % m_commandBuffers.size()] = (vk::VkCommandBuffer)0;
852 	}
853 
854 	vk::VkSemaphore		currentAcquireSemaphore	= m_freeAcquireSemaphore;
855 	vk::VkSemaphore		currentRenderSemaphore	= m_freeRenderSemaphore;
856 	deUint32			imageIndex;
857 
858 	// Acquire next image
859 	VK_CHECK(m_vkd.acquireNextImageKHR(*m_device, *m_swapchain, foreverNs, currentAcquireSemaphore, (vk::VkFence)0, &imageIndex));
860 
861 	// Create command buffer
862 	m_commandBuffers[m_frameNdx % m_commandBuffers.size()] = createCommandBuffer(m_vkd, *m_device, *m_commandPool, *m_pipelineLayout, *m_renderPass, m_framebuffers[imageIndex], *m_pipeline, m_frameNdx, m_quadCount, width, height).disown();
863 
864 	// Obtain timing data from previous frames
865 	if (m_useDisplayTiming)
866 	{
867 		const vector<vk::VkPastPresentationTimingGOOGLE>	pastPresentationTimings	(getPastPresentationTiming(m_vkd, *m_device, *m_swapchain));
868 		bool												isEarly					= false;
869 		bool												isLate					= false;
870 
871 		for (size_t pastPresentationInfoNdx = 0 ; pastPresentationInfoNdx < pastPresentationTimings.size(); pastPresentationInfoNdx++)
872 		{
873 			if (m_queuePresentTimes[pastPresentationTimings[pastPresentationInfoNdx].presentID] > pastPresentationTimings[pastPresentationInfoNdx].actualPresentTime)
874 			{
875 				m_resultCollector.fail("Image with PresentID " + de::toString(pastPresentationTimings[pastPresentationInfoNdx].presentID) + "was displayed before vkQueuePresentKHR was called.");
876 			}
877 			if (!m_ignoreThruPresentID)
878 			{
879 				// This is the first time that we've received an
880 				// actualPresentTime for this swapchain.  In order to not
881 				// perceive these early frames as "late", we need to sync-up
882 				// our future desiredPresentTime's with the
883 				// actualPresentTime(s) that we're receiving now.
884 				const deInt64	multiple	= m_nextPresentID - pastPresentationTimings.back().presentID;
885 
886 				m_prevDesiredPresentTime	= pastPresentationTimings.back().actualPresentTime + (multiple * m_targetIPD);
887 				m_ignoreThruPresentID		= pastPresentationTimings[pastPresentationInfoNdx].presentID + 1;
888 			}
889 			else if (pastPresentationTimings[pastPresentationInfoNdx].presentID > m_ignoreThruPresentID)
890 			{
891 				if (pastPresentationTimings[pastPresentationInfoNdx].actualPresentTime > (pastPresentationTimings[pastPresentationInfoNdx].desiredPresentTime + m_rcDuration.refreshDuration + MILLISECOND))
892 				{
893 					const deUint64 actual	= pastPresentationTimings[pastPresentationInfoNdx].actualPresentTime;
894 					const deUint64 desired	= pastPresentationTimings[pastPresentationInfoNdx].desiredPresentTime;
895 					const deUint64 rdur		= m_rcDuration.refreshDuration;
896 					const deUint64 diff1	= actual - (desired + rdur);
897 					const deUint64 diff2	= actual - desired;
898 
899 					log << TestLog::Message << "Image PresentID " << pastPresentationTimings[pastPresentationInfoNdx].presentID << " was " << diff1 << " nsec late." << TestLog::EndMessage;
900 					if (m_ExpectImage80Late && (pastPresentationTimings[pastPresentationInfoNdx].presentID == 80))
901 					{
902 						if (diff1 > (SECOND / 2))
903 							log << TestLog::Message << "\tNote: Image PresentID 80 was expected to be late by approximately 1 second." << TestLog::EndMessage;
904 						else
905 							m_resultCollector.fail("Image PresentID 80 was not late by approximately 1 second, as expected.");
906 					}
907 					log << TestLog::Message << "\t\t   actualPresentTime = " << actual << " nsec" << TestLog::EndMessage;
908 					log << TestLog::Message << "\t\t - desiredPresentTime= " << desired << " nsec" << TestLog::EndMessage;
909 					log << TestLog::Message << "\t\t =========================================" << TestLog::EndMessage;
910 					log << TestLog::Message << "\t\t   diff              =       " << diff2 << " nsec" << TestLog::EndMessage;
911 					log << TestLog::Message << "\t\t - refreshDuration   =       "    << rdur << " nsec" << TestLog::EndMessage;
912 					log << TestLog::Message << "\t\t =========================================" << TestLog::EndMessage;
913 					log << TestLog::Message << "\t\t   diff              =        " << diff1 << " nsec" << TestLog::EndMessage;
914 
915 					isLate = true;
916 				}
917 				else if ((pastPresentationTimings[pastPresentationInfoNdx].actualPresentTime > pastPresentationTimings[pastPresentationInfoNdx].earliestPresentTime) &&
918 						 (pastPresentationTimings[pastPresentationInfoNdx].presentMargin > (2 * MILLISECOND)))
919 				{
920 					const deUint64 actual	= pastPresentationTimings[pastPresentationInfoNdx].actualPresentTime;
921 					const deUint64 earliest	= pastPresentationTimings[pastPresentationInfoNdx].earliestPresentTime;
922 					const deUint64 diff		= actual - earliest;
923 
924 					log << TestLog::Message << "Image PresentID " << pastPresentationTimings[pastPresentationInfoNdx].presentID << " can be presented " << diff << " nsec earlier." << TestLog::EndMessage;
925 					log << TestLog::Message << "\t\t   actualPresentTime = " << actual << " nsec" << TestLog::EndMessage;
926 					log << TestLog::Message << "\t\t -earliestPresentTime= " << earliest << " nsec" << TestLog::EndMessage;
927 					log << TestLog::Message << "\t\t =========================================" << TestLog::EndMessage;
928 					log << TestLog::Message << "\t\t   diff              =        " << diff << " nsec" << TestLog::EndMessage;
929 
930 					isEarly = true;
931 				}
932 			}
933 		}
934 		// Preference is given to late presents over early presents:
935 		if (isLate)
936 		{
937 			// Demonstrate how to slow down the frame rate if a frame is late,
938 			// but don't go too slow (for test time reasons):
939 			if (++m_refreshDurationMultiplier > 2)
940 				m_refreshDurationMultiplier = 2;
941 			else
942 				log << TestLog::Message << "Increasing multiplier." << TestLog::EndMessage;
943 		}
944 		else if (isEarly)
945 		{
946 			// Demonstrate how to speed up the frame rate if a frame is early,
947 			// but don't let the multiplier hit zero:
948 			if (--m_refreshDurationMultiplier == 0)
949 				m_refreshDurationMultiplier = 1;
950 			else
951 				log << TestLog::Message << "Decreasing multiplier." << TestLog::EndMessage;
952 		}
953 		m_targetIPD = m_rcDuration.refreshDuration * m_refreshDurationMultiplier;
954 	}
955 
956 	// Submit command buffer
957 	{
958 		const vk::VkPipelineStageFlags	dstStageMask	= vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
959 		const vk::VkSubmitInfo			submitInfo		=
960 		{
961 			vk::VK_STRUCTURE_TYPE_SUBMIT_INFO,
962 			DE_NULL,
963 			1u,
964 			&currentAcquireSemaphore,
965 			&dstStageMask,
966 			1u,
967 			&m_commandBuffers[m_frameNdx % m_commandBuffers.size()],
968 			1u,
969 			&currentRenderSemaphore
970 		};
971 
972 		VK_CHECK(m_vkd.queueSubmit(m_queue, 1u, &submitInfo, fence));
973 	}
974 
975 	// Present frame
976 	if (m_useDisplayTiming)
977 	{
978 		// This portion should do interesting bits
979 
980 		// Initially, mirror reference to move things along
981 		vk::VkResult result;
982 		vk::VkPresentTimeGOOGLE presentTime =
983 		{
984 			++m_nextPresentID,
985 			m_prevDesiredPresentTime
986 		};
987 		// Record the current time, to record as the time of the vkQueuePresentKHR() call:
988 		const deUint64 curtimeNano = deGetMicroseconds() * 1000;
989 		m_queuePresentTimes[m_nextPresentID] = curtimeNano;
990 
991 		deUint64 desiredPresentTime = 0u;
992 		if (m_prevDesiredPresentTime == 0)
993 		{
994 			// This must be the first present for this swapchain.  Find out the
995 			// current time, as the basis for desiredPresentTime:
996 			if (curtimeNano != 0)
997 			{
998 				presentTime.desiredPresentTime = curtimeNano;
999 				presentTime.desiredPresentTime += (m_targetIPD / 2);
1000 			}
1001 			else
1002 			{
1003 				// Since we didn't find out the current time, don't give a
1004 				// desiredPresentTime:
1005 				presentTime.desiredPresentTime = 0;
1006 			}
1007 		}
1008 		else
1009 		{
1010 			desiredPresentTime = m_prevDesiredPresentTime + m_targetIPD;
1011 			if ((presentTime.presentID == 80) && (m_swapchainConfig.presentMode != vk::VK_PRESENT_MODE_MAILBOX_KHR))
1012 			{
1013 				// Test if desiredPresentTime is 1 second earlier (i.e. before the previous image could have been presented)
1014 				presentTime.desiredPresentTime -= SECOND;
1015 				m_ExpectImage80Late = true;
1016 			}
1017 		}
1018 		m_prevDesiredPresentTime = desiredPresentTime;
1019 
1020 		const vk::VkPresentTimesInfoGOOGLE presentTimesInfo =
1021 		{
1022 			vk::VK_STRUCTURE_TYPE_PRESENT_TIMES_INFO_GOOGLE,
1023 			DE_NULL,
1024 			1u,
1025 			&presentTime
1026 		};
1027 		const vk::VkPresentInfoKHR presentInfo =
1028 		{
1029 			vk::VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
1030 			&presentTimesInfo,
1031 			1u,
1032 			&currentRenderSemaphore,
1033 			1u,
1034 			&*m_swapchain,
1035 			&imageIndex,
1036 			&result
1037 		};
1038 
1039 		VK_CHECK_WSI(m_vkd.queuePresentKHR(m_queue, &presentInfo));
1040 		VK_CHECK_WSI(result);
1041 	}
1042 	else
1043 	{
1044 		vk::VkResult result;
1045 		const vk::VkPresentInfoKHR presentInfo =
1046 		{
1047 			vk::VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
1048 			DE_NULL,
1049 			1u,
1050 			&currentRenderSemaphore,
1051 			1u,
1052 			&*m_swapchain,
1053 			&imageIndex,
1054 			&result
1055 		};
1056 
1057 		VK_CHECK_WSI(m_vkd.queuePresentKHR(m_queue, &presentInfo));
1058 		VK_CHECK_WSI(result);
1059 	}
1060 
1061 	{
1062 		m_freeAcquireSemaphore = m_acquireSemaphores[imageIndex];
1063 		m_acquireSemaphores[imageIndex] = currentAcquireSemaphore;
1064 
1065 		m_freeRenderSemaphore = m_renderSemaphores[imageIndex];
1066 		m_renderSemaphores[imageIndex] = currentRenderSemaphore;
1067 	}
1068 }
1069 
iterate(void)1070 tcu::TestStatus DisplayTimingTestInstance::iterate (void)
1071 {
1072 	// Initialize swapchain specific resources
1073 	// Render test
1074 	try
1075 	{
1076 		if (m_frameNdx == 0)
1077 		{
1078 			if (m_outOfDateCount == 0)
1079 				m_context.getTestContext().getLog() << tcu::TestLog::Message << "Swapchain: " << m_swapchainConfig << tcu::TestLog::EndMessage;
1080 
1081 			initSwapchainResources();
1082 		}
1083 
1084 		render();
1085 	}
1086 	catch (const vk::Error& error)
1087 	{
1088 		if (error.getError() == vk::VK_ERROR_OUT_OF_DATE_KHR)
1089 		{
1090 			if (m_outOfDateCount < m_maxOutOfDateCount)
1091 			{
1092 				m_context.getTestContext().getLog() << TestLog::Message << "Frame " << m_frameNdx << ": Swapchain out of date. Recreating resources." << TestLog::EndMessage;
1093 				deinitSwapchainResources();
1094 				m_frameNdx = 0;
1095 				m_outOfDateCount++;
1096 
1097 				return tcu::TestStatus::incomplete();
1098 			}
1099 			else
1100 			{
1101 				m_context.getTestContext().getLog() << TestLog::Message << "Frame " << m_frameNdx << ": Swapchain out of date." << TestLog::EndMessage;
1102 				m_resultCollector.fail("Received too many VK_ERROR_OUT_OF_DATE_KHR errors. Received " + de::toString(m_outOfDateCount) + ", max " + de::toString(m_maxOutOfDateCount));
1103 			}
1104 		}
1105 		else
1106 		{
1107 			m_resultCollector.fail(error.what());
1108 		}
1109 
1110 		deinitSwapchainResources();
1111 
1112 		return tcu::TestStatus(m_resultCollector.getResult(), m_resultCollector.getMessage());
1113 	}
1114 
1115 	m_frameNdx++;
1116 
1117 	if (m_frameNdx >= m_frameCount)
1118 	{
1119 		deinitSwapchainResources();
1120 
1121 		return tcu::TestStatus(m_resultCollector.getResult(), m_resultCollector.getMessage());
1122 	}
1123 	else
1124 		return tcu::TestStatus::incomplete();
1125 }
1126 
1127 struct Programs
1128 {
initvkt::wsi::__anonba12eeda0111::Programs1129 	static void init (vk::SourceCollections& dst, TestConfig)
1130 	{
1131 		dst.glslSources.add("quad-vert") << glu::VertexSource(
1132 			"#version 450\n"
1133 			"out gl_PerVertex {\n"
1134 			"\tvec4 gl_Position;\n"
1135 			"};\n"
1136 			"highp float;\n"
1137 			"void main (void) {\n"
1138 			"\tgl_Position = vec4(((gl_VertexIndex + 2) / 3) % 2 == 0 ? -1.0 : 1.0,\n"
1139 			"\t                   ((gl_VertexIndex + 1) / 3) % 2 == 0 ? -1.0 : 1.0, 0.0, 1.0);\n"
1140 			"}\n");
1141 		dst.glslSources.add("quad-frag") << glu::FragmentSource(
1142 			"#version 310 es\n"
1143 			"layout(location = 0) out highp vec4 o_color;\n"
1144 			"layout(push_constant) uniform PushConstant {\n"
1145 			"\thighp uint frameNdx;\n"
1146 			"} pushConstants;\n"
1147 			"void main (void)\n"
1148 			"{\n"
1149 			"\thighp uint frameNdx = pushConstants.frameNdx;\n"
1150 			"\thighp uint x = frameNdx + uint(gl_FragCoord.x);\n"
1151 			"\thighp uint y = frameNdx + uint(gl_FragCoord.y);\n"
1152 			"\thighp uint r = 128u * bitfieldExtract(x, 0, 1)\n"
1153 			"\t             +  64u * bitfieldExtract(y, 1, 1)\n"
1154 			"\t             +  32u * bitfieldExtract(x, 3, 1);\n"
1155 			"\thighp uint g = 128u * bitfieldExtract(y, 0, 1)\n"
1156 			"\t             +  64u * bitfieldExtract(x, 2, 1)\n"
1157 			"\t             +  32u * bitfieldExtract(y, 3, 1);\n"
1158 			"\thighp uint b = 128u * bitfieldExtract(x, 1, 1)\n"
1159 			"\t             +  64u * bitfieldExtract(y, 2, 1)\n"
1160 			"\t             +  32u * bitfieldExtract(x, 4, 1);\n"
1161 			"\to_color = vec4(float(r) / 255.0, float(g) / 255.0, float(b) / 255.0, 1.0);\n"
1162 			"}\n");
1163 	}
1164 };
1165 
1166 } // anonymous
1167 
createDisplayTimingTests(tcu::TestCaseGroup * testGroup,vk::wsi::Type wsiType)1168 void createDisplayTimingTests (tcu::TestCaseGroup* testGroup, vk::wsi::Type wsiType)
1169 {
1170 	const struct
1171 	{
1172 		vk::VkPresentModeKHR	mode;
1173 		const char*				name;
1174 	} presentModes[] =
1175 	{
1176 		{ vk::VK_PRESENT_MODE_FIFO_KHR,			"fifo"			},
1177 		{ vk::VK_PRESENT_MODE_FIFO_RELAXED_KHR,	"fifo_relaxed"	},
1178 		{ vk::VK_PRESENT_MODE_IMMEDIATE_KHR,	"immediate"		},
1179 		{ vk::VK_PRESENT_MODE_MAILBOX_KHR,		"mailbox"		},
1180 	};
1181 
1182 	for (size_t presentModeNdx = 0; presentModeNdx < DE_LENGTH_OF_ARRAY(presentModes); presentModeNdx++)
1183 	{
1184 		de::MovePtr<tcu::TestCaseGroup>	presentModeGroup	(new tcu::TestCaseGroup(testGroup->getTestContext(), presentModes[presentModeNdx].name, presentModes[presentModeNdx].name));
1185 
1186 		for (size_t ref = 0; ref < 2; ref++)
1187 		{
1188 			const bool						isReference	= (ref == 0);
1189 			const char* const				name		= isReference ? "reference" : "display_timing";
1190 			TestConfig						config;
1191 
1192 			config.wsiType					= wsiType;
1193 			config.useDisplayTiming			= !isReference;
1194 			config.presentMode				= presentModes[presentModeNdx].mode;
1195 
1196 			presentModeGroup->addChild(new vkt::InstanceFactory1<DisplayTimingTestInstance, TestConfig, Programs>(testGroup->getTestContext(), tcu::NODETYPE_SELF_VALIDATE, name, name, Programs(), config));
1197 		}
1198 
1199 		testGroup->addChild(presentModeGroup.release());
1200 	}
1201 }
1202 
1203 } // wsi
1204 } // vkt
1205