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