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