1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2019 The Khronos Group 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  * \brief VK_EXT_display_control tests
21  *//*--------------------------------------------------------------------*/
22 
23 #include "vkRefUtil.hpp"
24 #include "vkWsiPlatform.hpp"
25 #include "vkWsiUtil.hpp"
26 #include "vkQueryUtil.hpp"
27 #include "vkDeviceUtil.hpp"
28 #include "vkPlatform.hpp"
29 #include "vkTypeUtil.hpp"
30 #include "vkPrograms.hpp"
31 #include "vkCmdUtil.hpp"
32 #include "vkWsiUtil.hpp"
33 #include "vkCmdUtil.hpp"
34 #include "vkObjUtil.hpp"
35 
36 #include "vktWsiDisplayControlTests.hpp"
37 #include "vktTestCaseUtil.hpp"
38 #include "vktTestGroupUtil.hpp"
39 #include "vktCustomInstancesDevices.hpp"
40 
41 #include "tcuPlatform.hpp"
42 #include "tcuResultCollector.hpp"
43 #include "tcuTestLog.hpp"
44 #include "tcuCommandLine.hpp"
45 
46 #include "deClock.h"
47 
48 #include <vector>
49 #include <string>
50 
51 using std::vector;
52 using std::string;
53 
54 using tcu::Maybe;
55 using tcu::UVec2;
56 using tcu::TestLog;
57 
58 namespace vkt
59 {
60 namespace wsi
61 {
62 namespace
63 {
64 
65 using namespace vk;
66 using namespace vk::wsi;
67 
68 typedef vector<VkExtensionProperties> Extensions;
69 
createInstance(Context & context)70 CustomInstance createInstance (Context& context)
71 {
72 	vector<string> extensions =
73 	{
74 		"VK_KHR_surface",
75 		"VK_KHR_display",
76 		"VK_EXT_display_surface_counter",
77 	};
78 
79 	return vkt::createCustomInstanceWithExtensions(context, extensions);
80 }
81 
chooseQueueFamilyIndex(const InstanceInterface & vki,VkPhysicalDevice physicalDevice,VkSurfaceKHR surface)82 deUint32 chooseQueueFamilyIndex (const InstanceInterface& vki, VkPhysicalDevice physicalDevice, VkSurfaceKHR surface)
83 {
84 	deUint32 numTotalFamilyIndices;
85 	vki.getPhysicalDeviceQueueFamilyProperties(physicalDevice, &numTotalFamilyIndices, DE_NULL);
86 
87 	for (deUint32 queueFamilyNdx = 0; queueFamilyNdx < numTotalFamilyIndices; ++queueFamilyNdx)
88 	{
89 		if (wsi::getPhysicalDeviceSurfaceSupport(vki, physicalDevice, queueFamilyNdx, surface) == VK_TRUE)
90 			return queueFamilyNdx;
91 	}
92 
93 	TCU_THROW(NotSupportedError, "Device doesn't support presentation");
94 	return 0;
95 }
96 
createDevice(const vk::Platform & platform,const PlatformInterface & vkp,const VkInstance instance,const InstanceInterface & vki,VkPhysicalDevice physicalDevice,const Extensions & supportedExtensions,const deUint32 queueFamilyIndex,bool validationEnabled,const VkAllocationCallbacks * pAllocator=DE_NULL)97 Move<VkDevice> createDevice (const vk::Platform&		platform,
98 							 const PlatformInterface&		vkp,
99 							 const VkInstance				instance,
100 							 const InstanceInterface&		vki,
101 							 VkPhysicalDevice				physicalDevice,
102 							 const Extensions&				supportedExtensions,
103 							 const deUint32					queueFamilyIndex,
104 							 bool							validationEnabled,
105 							 const VkAllocationCallbacks*	pAllocator = DE_NULL)
106 {
107 	const float queuePriorities[] = { 1.0f };
108 	bool displayAvailable = true;
109 	const VkDeviceQueueCreateInfo queueInfos[] =
110 	{
111 		{
112 			VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
113 			DE_NULL,
114 			(VkDeviceQueueCreateFlags)0,
115 			queueFamilyIndex,
116 			DE_LENGTH_OF_ARRAY(queuePriorities),
117 			&queuePriorities[0]
118 		}
119 	};
120 
121 	VkPhysicalDeviceFeatures features;
122 	deMemset(&features, 0, sizeof(features));
123 
124 	const char* extensions[] =
125 	{
126 		"VK_KHR_swapchain",
127 		"VK_EXT_display_control"
128 	};
129 
130 	const VkDeviceCreateInfo deviceParams =
131 	{
132 		VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
133 		DE_NULL,
134 		(VkDeviceCreateFlags)0,
135 		DE_LENGTH_OF_ARRAY(queueInfos),
136 		&queueInfos[0],
137 		0u,
138 		DE_NULL,
139 		DE_LENGTH_OF_ARRAY(extensions),
140 		&extensions[0],
141 		&features
142 	};
143 
144 	for (auto ext: extensions)
145 	{
146 		if (!isExtensionSupported(supportedExtensions, RequiredExtension(ext)))
147 			TCU_THROW(NotSupportedError, (string(ext) + " is not supported").c_str());
148 	}
149 
150 	for (int typeNdx = 0; typeNdx < vk::wsi::TYPE_LAST; ++typeNdx)
151 	{
152 		vk::wsi::Type	wsiType = (vk::wsi::Type)typeNdx;
153 		if (platform.hasDisplay(wsiType))
154 		{
155 			displayAvailable = false;
156 			break;
157 		}
158 	}
159 
160 	if (!displayAvailable)
161 		TCU_THROW(NotSupportedError, "Display is unavailable as windowing system has access");
162 
163 	return createCustomDevice(validationEnabled, vkp, instance, vki, physicalDevice, &deviceParams, pAllocator);
164 }
165 
getDisplayAndDisplayPlane(const InstanceInterface & vki,VkPhysicalDevice physicalDevice,deUint32 * pPlaneIndex)166 VkDisplayKHR getDisplayAndDisplayPlane(const InstanceInterface& vki, VkPhysicalDevice physicalDevice, deUint32 *pPlaneIndex)
167 {
168 	deUint32 countDisplays = 0;
169 	VkResult result = vki.getPhysicalDeviceDisplayPropertiesKHR(physicalDevice, &countDisplays, DE_NULL);
170 	if (result != VK_SUCCESS)
171 		TCU_THROW(NotSupportedError, "vkGetPhysicalDeviceDisplayPropertiesKHR failed");
172 
173 	if (countDisplays == 0)
174 		TCU_THROW(NotSupportedError, "No displays available");
175 
176 	deUint32 countDisplayPlanes = 0;
177 	result = vki.getPhysicalDeviceDisplayPlanePropertiesKHR(physicalDevice, &countDisplayPlanes, DE_NULL);
178 	if (result != VK_SUCCESS || !countDisplayPlanes)
179 		TCU_FAIL("GetPhysicalDeviceDisplayPlanePropertiesKHR failed");
180 
181 	for (deUint32 p = 0; p < countDisplayPlanes; p++)
182 	{
183 		deUint32 count = 0u;
184 		result = vki.getDisplayPlaneSupportedDisplaysKHR(physicalDevice, p, &count, DE_NULL);
185 		if (result != VK_SUCCESS)
186 			TCU_FAIL("GetDisplayPlaneSupportedDisplaysKHR failed");
187 
188 		// No displays that can make use of this plane are available.
189 		if (!count)
190 			continue;
191 
192 		std::vector<VkDisplayKHR> displays(count);
193 		result = vki.getDisplayPlaneSupportedDisplaysKHR(physicalDevice, p, &count, &displays[0]);
194 		if (result != VK_SUCCESS)
195 			TCU_FAIL("GetDisplayPlaneSupportedDisplaysKHR failed");
196 
197 		// return first plane with an available display
198 		*pPlaneIndex = p;
199 		return displays[0];
200 	}
201 
202 	TCU_FAIL("No intersection between displays and display planes");
203 
204 	// Unreachable.
205 	return DE_NULL;
206 }
207 
createSurface(const InstanceInterface & vki,VkInstance instance,VkPhysicalDevice physicalDevice,VkDisplayKHR display,deUint32 planeIndex)208 VkSurfaceKHR createSurface(const InstanceInterface& vki, VkInstance instance, VkPhysicalDevice physicalDevice, VkDisplayKHR display, deUint32 planeIndex)
209 {
210 	// get number of display modes for this display
211 	deUint32 displayModesCount = 0;
212 	VkResult result = vki.getDisplayModePropertiesKHR(physicalDevice, display, &displayModesCount, DE_NULL);
213 	if (result != VK_SUCCESS)
214 		TCU_FAIL("GetDisplayModePropertiesKHR failed");
215 
216 	// get first display mode of this display
217 	std::vector<vk::VkDisplayModePropertiesKHR> modeProperties(displayModesCount);
218 	result = vki.getDisplayModePropertiesKHR(physicalDevice, display, &displayModesCount, &modeProperties[0]);
219 	if (result != VK_SUCCESS)
220 		TCU_FAIL("GetDisplayModePropertiesKHR failed");
221 	VkDisplayModeKHR displayMode = modeProperties[0].displayMode;
222 
223 	// get capabielieties for first plane of this display
224 	VkDisplayPlaneCapabilitiesKHR planeCapabilities;
225 	result = vki.getDisplayPlaneCapabilitiesKHR(physicalDevice, displayMode, planeIndex, &planeCapabilities);
226 	if (result != VK_SUCCESS)
227 		TCU_FAIL("GetDisplayPlaneCapabilitiesKHR failed");
228 
229 	// get plane properties count
230 	deUint32 planePropertiesCount = 0;
231 	result = vki.getPhysicalDeviceDisplayPlanePropertiesKHR(physicalDevice, &planePropertiesCount, DE_NULL);
232 	if (result != VK_SUCCESS || !planePropertiesCount)
233 		TCU_FAIL("GetPhysicalDeviceDisplayPlanePropertiesKHR failed");
234 
235 	// get plane properties
236 	std::vector <VkDisplayPlanePropertiesKHR> planeProperties(planePropertiesCount);
237 	result = vki.getPhysicalDeviceDisplayPlanePropertiesKHR(physicalDevice, &planePropertiesCount, &planeProperties[0]);
238 	if (result != VK_SUCCESS)
239 		TCU_FAIL("GetPhysicalDeviceDisplayPlanePropertiesKHR failed");
240 
241 	// define surface create info
242 	const VkDisplaySurfaceCreateInfoKHR createInfo =
243 	{
244 		VK_STRUCTURE_TYPE_DISPLAY_SURFACE_CREATE_INFO_KHR,	// VkStructureType					sType
245 		DE_NULL,											// const void*						pNext
246 		0,													// VkDisplaySurfaceCreateFlagsKHR	flags
247 		displayMode,										// VkDisplayModeKHR					displayMode
248 		planeIndex,											// uint32_t							planeIndex
249 		planeProperties[planeIndex].currentStackIndex,		// uint32_t							planeStackIndex
250 		VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR,				// VkSurfaceTransformFlagBitsKHR	transform
251 		1.0f,												// float							globalAlpha
252 		VK_DISPLAY_PLANE_ALPHA_OPAQUE_BIT_KHR,				// VkDisplayPlaneAlphaFlagBitsKHR	alphaMode
253 		{													// VkExtent2D						imageExtent
254 			planeCapabilities.minDstExtent.width,
255 			planeCapabilities.minDstExtent.height
256 		}
257 	};
258 
259 	VkSurfaceKHR surface = DE_NULL;
260 	result = vki.createDisplayPlaneSurfaceKHR(instance, &createInfo, DE_NULL, &surface);
261 	if (result != VK_SUCCESS)
262 		TCU_FAIL("CreateDisplayPlaneSurfaceKHR failed");
263 
264 	if (surface == DE_NULL)
265 		TCU_FAIL("Invalid surface handle returned");
266 
267 	return surface;
268 }
269 
initSemaphores(const DeviceInterface & vkd,VkDevice device,std::vector<VkSemaphore> & semaphores)270 void initSemaphores (const DeviceInterface&		vkd,
271 					 VkDevice					device,
272 					 std::vector<VkSemaphore>&	semaphores)
273 {
274 	for (VkSemaphore& semaphore : semaphores)
275 		semaphore = createSemaphore(vkd, device).disown();
276 }
277 
deinitSemaphores(const DeviceInterface & vkd,VkDevice device,std::vector<VkSemaphore> & semaphores)278 void deinitSemaphores (const DeviceInterface&	vkd,
279 					 VkDevice					device,
280 					 std::vector<VkSemaphore>&	semaphores)
281 {
282 	for (VkSemaphore& semaphore : semaphores)
283 	{
284 		if (semaphore == (VkSemaphore)0)
285 			continue;
286 
287 		vkd.destroySemaphore(device, semaphore, DE_NULL);
288 		semaphore = (VkSemaphore)0;
289 	}
290 
291 	semaphores.clear();
292 }
293 
initFences(const DeviceInterface & vkd,VkDevice device,std::vector<VkFence> & fences)294 void initFences (const DeviceInterface&	vkd,
295 				 VkDevice				device,
296 				 std::vector<VkFence>&	fences)
297 {
298 	for (VkFence& fence : fences)
299 		fence = createFence(vkd, device).disown();
300 }
301 
deinitFences(const DeviceInterface & vkd,VkDevice device,std::vector<VkFence> & fences)302 void deinitFences (const DeviceInterface&	vkd,
303 				   VkDevice					device,
304 				   std::vector<VkFence>&	fences)
305 {
306 	for (VkFence& fence : fences)
307 	{
308 		if (fence == (VkFence)0)
309 			continue;
310 
311 		vkd.destroyFence(device, fence, DE_NULL);
312 		fence = (VkFence)0;
313 	}
314 
315 	fences.clear();
316 }
317 
createCommandBuffer(const DeviceInterface & vkd,VkDevice device,VkCommandPool commandPool,VkRenderPass renderPass,VkImage image,VkFramebuffer framebuffer,VkPipeline pipeline,deUint32 imageWidth,deUint32 imageHeight)318 Move<VkCommandBuffer> createCommandBuffer (const DeviceInterface&	vkd,
319 										   VkDevice					device,
320 										   VkCommandPool			commandPool,
321 										   VkRenderPass				renderPass,
322 										   VkImage					image,
323 										   VkFramebuffer			framebuffer,
324 										   VkPipeline				pipeline,
325 										   deUint32					imageWidth,
326 										   deUint32					imageHeight)
327 {
328 	const VkCommandBufferAllocateInfo allocateInfo =
329 	{
330 		VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
331 		DE_NULL,
332 
333 		commandPool,
334 		VK_COMMAND_BUFFER_LEVEL_PRIMARY,
335 		1
336 	};
337 
338 	VkImageMemoryBarrier imageBarrier =
339 	{
340 		VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,		// VkStructureType			sType;
341 		DE_NULL,									// const void*				pNext;
342 		0u,											// VkAccessFlags			srcAccessMask;
343 		VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,		// VkAccessFlags			dstAccessMask;
344 		VK_IMAGE_LAYOUT_UNDEFINED,					// VkImageLayout			oldLayout;
345 		VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,	// VkImageLayout			newLayout;
346 		VK_QUEUE_FAMILY_IGNORED,					// deUint32					srcQueueFamilyIndex;
347 		VK_QUEUE_FAMILY_IGNORED,					// deUint32					dstQueueFamilyIndex;
348 		image,										// VkImage					image;
349 		{											// VkImageSubresourceRange	subresourceRange;
350 			VK_IMAGE_ASPECT_COLOR_BIT,				// VkImageAspectFlags		aspectMask;
351 			0u,										// deUint32					baseMipLevel;
352 			1u,										// deUint32					mipLevels;
353 			0u,										// deUint32					baseArraySlice;
354 			1u										// deUint32					arraySize;
355 		}
356 	};
357 
358 	Move<VkCommandBuffer>	commandBuffer	(allocateCommandBuffer(vkd, device, &allocateInfo));
359 	beginCommandBuffer(vkd, *commandBuffer, 0u);
360 
361 	vkd.cmdPipelineBarrier(*commandBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
362 		(VkDependencyFlags)0, 0, (const VkMemoryBarrier*)DE_NULL, 0, (const VkBufferMemoryBarrier*)DE_NULL, 1, &imageBarrier);
363 
364 	beginRenderPass(vkd, *commandBuffer, renderPass, framebuffer, makeRect2D(0, 0, imageWidth, imageHeight), tcu::Vec4(0.25f, 0.5f, 0.75f, 1.0f));
365 
366 	vkd.cmdBindPipeline(*commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
367 	vkd.cmdDraw(*commandBuffer, 6u, 1u, 0u, 0u);
368 
369 	endRenderPass(vkd, *commandBuffer);
370 
371 	endCommandBuffer(vkd, *commandBuffer);
372 	return commandBuffer;
373 }
374 
deinitCommandBuffers(const DeviceInterface & vkd,VkDevice device,VkCommandPool commandPool,std::vector<VkCommandBuffer> & commandBuffers)375 void deinitCommandBuffers (const DeviceInterface&			vkd,
376 						   VkDevice							device,
377 						   VkCommandPool					commandPool,
378 						   std::vector<VkCommandBuffer>&	commandBuffers)
379 {
380 	for (size_t ndx = 0; ndx < commandBuffers.size(); ndx++)
381 	{
382 		if (commandBuffers[ndx] != (VkCommandBuffer)0)
383 			vkd.freeCommandBuffers(device, commandPool, 1u,  &commandBuffers[ndx]);
384 
385 		commandBuffers[ndx] = (VkCommandBuffer)0;
386 	}
387 
388 	commandBuffers.clear();
389 }
390 
createCommandPool(const DeviceInterface & vkd,VkDevice device,deUint32 queueFamilyIndex)391 Move<VkCommandPool> createCommandPool (const DeviceInterface&	vkd,
392 									   VkDevice					device,
393 									   deUint32					queueFamilyIndex)
394 {
395 	const VkCommandPoolCreateInfo createInfo =
396 	{
397 		VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
398 		DE_NULL,
399 		0u,
400 		queueFamilyIndex
401 	};
402 
403 	return createCommandPool(vkd, device, &createInfo);
404 }
405 
initFramebuffers(const DeviceInterface & vkd,VkDevice device,VkRenderPass renderPass,std::vector<VkImageView> imageViews,deUint32 width,deUint32 height,std::vector<VkFramebuffer> & framebuffers)406 void initFramebuffers (const DeviceInterface&		vkd,
407 					   VkDevice						device,
408 					   VkRenderPass					renderPass,
409 					   std::vector<VkImageView>		imageViews,
410 					   deUint32						width,
411 					   deUint32						height,
412 					   std::vector<VkFramebuffer>&	framebuffers)
413 {
414 	DE_ASSERT(framebuffers.size() == imageViews.size());
415 
416 	for (size_t ndx = 0; ndx < framebuffers.size(); ndx++)
417 	{
418 		const VkFramebufferCreateInfo createInfo =
419 		{
420 			VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
421 			DE_NULL,
422 
423 			0u,
424 			renderPass,
425 			1u,
426 			&imageViews[ndx],
427 			width,
428 			height,
429 			1u
430 		};
431 
432 		framebuffers[ndx] = createFramebuffer(vkd, device, &createInfo).disown();
433 	}
434 }
435 
deinitFramebuffers(const DeviceInterface & vkd,VkDevice device,std::vector<VkFramebuffer> & framebuffers)436 void deinitFramebuffers (const DeviceInterface&			vkd,
437 						 VkDevice						device,
438 						 std::vector<VkFramebuffer>&	framebuffers)
439 {
440 	for (size_t ndx = 0; ndx < framebuffers.size(); ndx++)
441 	{
442 		if (framebuffers[ndx] != (VkFramebuffer)0)
443 			vkd.destroyFramebuffer(device, framebuffers[ndx], DE_NULL);
444 
445 		framebuffers[ndx] = (VkFramebuffer)0;
446 	}
447 
448 	framebuffers.clear();
449 }
450 
createImageView(const DeviceInterface & vkd,VkDevice device,VkImage image,VkFormat format)451 Move<VkImageView> createImageView (const DeviceInterface&	vkd,
452 								   VkDevice					device,
453 								   VkImage					image,
454 								   VkFormat					format)
455 {
456 	const VkImageViewCreateInfo	createInfo =
457 	{
458 		VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
459 		DE_NULL,
460 
461 		0u,
462 		image,
463 		VK_IMAGE_VIEW_TYPE_2D,
464 		format,
465 		makeComponentMappingRGBA(),
466 		{
467 			VK_IMAGE_ASPECT_COLOR_BIT,
468 			0u,
469 			1u,
470 			0u,
471 			1u
472 		}
473 	};
474 
475 	return createImageView(vkd, device, &createInfo, DE_NULL);
476 }
477 
initImageViews(const DeviceInterface & vkd,VkDevice device,const std::vector<VkImage> & images,VkFormat format,std::vector<VkImageView> & imageViews)478 void initImageViews (const DeviceInterface&			vkd,
479 					 VkDevice						device,
480 					 const std::vector<VkImage>&	images,
481 					 VkFormat						format,
482 					 std::vector<VkImageView>&		imageViews)
483 {
484 	DE_ASSERT(images.size() == imageViews.size());
485 
486 	for (size_t ndx = 0; ndx < imageViews.size(); ndx++)
487 		imageViews[ndx] = createImageView(vkd, device, images[ndx], format).disown();
488 }
489 
deinitImageViews(const DeviceInterface & vkd,VkDevice device,std::vector<VkImageView> & imageViews)490 void deinitImageViews (const DeviceInterface&		vkd,
491 					   VkDevice						device,
492 					   std::vector<VkImageView>&	imageViews)
493 {
494 	for (size_t ndx = 0; ndx < imageViews.size(); ndx++)
495 	{
496 		if (imageViews[ndx] != (VkImageView)0)
497 			vkd.destroyImageView(device, imageViews[ndx], DE_NULL);
498 
499 		imageViews[ndx] = (VkImageView)0;
500 	}
501 
502 	imageViews.clear();
503 }
504 
createPipeline(const DeviceInterface & vkd,VkDevice device,VkRenderPass renderPass,VkPipelineLayout layout,VkShaderModule vertexShaderModule,VkShaderModule fragmentShaderModule,deUint32 width,deUint32 height)505 Move<VkPipeline> createPipeline (const DeviceInterface&	vkd,
506 								 VkDevice				device,
507 								 VkRenderPass			renderPass,
508 								 VkPipelineLayout		layout,
509 								 VkShaderModule			vertexShaderModule,
510 								 VkShaderModule			fragmentShaderModule,
511 								 deUint32				width,
512 								 deUint32				height)
513 {
514 	const VkPipelineVertexInputStateCreateInfo	vertexInputState	=
515 	{
516 		VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
517 		DE_NULL,
518 		0u,
519 		0u,
520 		DE_NULL,
521 		0u,
522 		DE_NULL
523 	};
524 	const std::vector<VkViewport>	viewports	(1, makeViewport(tcu::UVec2(width, height)));
525 	const std::vector<VkRect2D>		scissors	(1, makeRect2D(tcu::UVec2(width, height)));
526 
527 	return makeGraphicsPipeline(vkd,										// const DeviceInterface&                        vk
528 								device,										// const VkDevice                                device
529 								layout,										// const VkPipelineLayout                        pipelineLayout
530 								vertexShaderModule,							// const VkShaderModule                          vertexShaderModule
531 								DE_NULL,									// const VkShaderModule                          tessellationControlShaderModule
532 								DE_NULL,									// const VkShaderModule                          tessellationEvalShaderModule
533 								DE_NULL,									// const VkShaderModule                          geometryShaderModule
534 								fragmentShaderModule,						// const VkShaderModule                          fragmentShaderModule
535 								renderPass,									// const VkRenderPass                            renderPass
536 								viewports,									// const std::vector<VkViewport>&                viewports
537 								scissors,									// const std::vector<VkRect2D>&                  scissors
538 								VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,		// const VkPrimitiveTopology                     topology
539 								0u,											// const deUint32                                subpass
540 								0u,											// const deUint32                                patchControlPoints
541 								&vertexInputState);							// const VkPipelineVertexInputStateCreateInfo*   vertexInputStateCreateInfo
542 }
543 
createPipelineLayout(const DeviceInterface & vkd,VkDevice device)544 Move<VkPipelineLayout> createPipelineLayout (const DeviceInterface&	vkd,
545 												   VkDevice			device)
546 {
547 	const VkPipelineLayoutCreateInfo createInfo	=
548 	{
549 		VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
550 		DE_NULL,
551 		0u,
552 		0u,
553 		DE_NULL,
554 		0u,
555 		DE_NULL,
556 	};
557 
558 	return createPipelineLayout(vkd, device, &createInfo);
559 }
560 
createSwapchainCounterConfig()561 VkSwapchainCounterCreateInfoEXT createSwapchainCounterConfig()
562 {
563 	const VkSwapchainCounterCreateInfoEXT swapchainCounterConfig =
564 	{
565 		VK_STRUCTURE_TYPE_SWAPCHAIN_COUNTER_CREATE_INFO_EXT,
566 		DE_NULL,
567 		VK_SURFACE_COUNTER_VBLANK_EXT
568 	};
569 	return swapchainCounterConfig;
570 }
571 
createSwapchainConfig(VkSurfaceKHR surface,deUint32 queueFamilyIndex,const VkSurfaceCapabilities2EXT & properties,const vector<VkSurfaceFormatKHR> & formats,const vector<VkPresentModeKHR> & presentModes,VkPresentModeKHR presentMode,VkSwapchainCounterCreateInfoEXT * swapchainCounterInfo)572 VkSwapchainCreateInfoKHR createSwapchainConfig (VkSurfaceKHR						surface,
573 												deUint32							queueFamilyIndex,
574 												const VkSurfaceCapabilities2EXT&	properties,
575 												const vector<VkSurfaceFormatKHR>&	formats,
576 												const vector<VkPresentModeKHR>&		presentModes,
577 												VkPresentModeKHR					presentMode,
578 												VkSwapchainCounterCreateInfoEXT *swapchainCounterInfo)
579 {
580 	if ((properties.supportedSurfaceCounters & VK_SURFACE_COUNTER_VBLANK_EXT) == 0)
581 		TCU_THROW(NotSupportedError, "vblank counter not supported");
582 
583 	const deUint32				imageLayers		= 1u;
584 	const VkImageUsageFlags		imageUsage		= properties.supportedUsageFlags;
585 	const VkBool32				clipped			= VK_FALSE;
586 
587 	const deUint32				imageWidth		= (properties.currentExtent.width != 0xFFFFFFFFu)
588 													? properties.currentExtent.width
589 													: de::min(1024u, properties.minImageExtent.width + ((properties.maxImageExtent.width - properties.minImageExtent.width) / 2));
590 	const deUint32				imageHeight		= (properties.currentExtent.height != 0xFFFFFFFFu)
591 													? properties.currentExtent.height
592 													: de::min(1024u, properties.minImageExtent.height + ((properties.maxImageExtent.height - properties.minImageExtent.height) / 2));
593 	const VkExtent2D			imageSize		= { imageWidth, imageHeight };
594 
595 	if (std::find(presentModes.begin(), presentModes.end(), presentMode) == presentModes.end())
596 		TCU_THROW(NotSupportedError, "Present mode not supported");
597 
598 	// Pick the first supported transform, alpha, and format:
599 	VkSurfaceTransformFlagsKHR transform;
600 	for (transform = 1u; transform <= properties.supportedTransforms; transform = transform << 1u)
601 	{
602 		if ((properties.supportedTransforms & transform) != 0)
603 			break;
604 	}
605 
606 	VkCompositeAlphaFlagsKHR alpha;
607 	for (alpha = 1u; alpha <= properties.supportedCompositeAlpha; alpha = alpha << 1u)
608 	{
609 		if ((alpha & properties.supportedCompositeAlpha) != 0)
610 			break;
611 	}
612 
613 	{
614 		const VkSurfaceTransformFlagBitsKHR	preTransform	= (VkSurfaceTransformFlagBitsKHR)transform;
615 		const VkCompositeAlphaFlagBitsKHR	compositeAlpha	= (VkCompositeAlphaFlagBitsKHR)alpha;
616 		const VkFormat						imageFormat		= formats[0].format;
617 		const VkColorSpaceKHR				imageColorSpace	= formats[0].colorSpace;
618 		const VkSwapchainCreateInfoKHR		createInfo		=
619 		{
620 			VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
621 			swapchainCounterInfo,
622 			0u,
623 			surface,
624 			properties.minImageCount,
625 			imageFormat,
626 			imageColorSpace,
627 			imageSize,
628 			imageLayers,
629 			imageUsage,
630 			VK_SHARING_MODE_EXCLUSIVE,
631 			1u,
632 			&queueFamilyIndex,
633 			preTransform,
634 			compositeAlpha,
635 			presentMode,
636 			clipped,
637 			(VkSwapchainKHR)0
638 		};
639 
640 		return createInfo;
641 	}
642 }
643 
644 class SwapchainCounterTestInstance : public TestInstance
645 {
646 public:
647 						SwapchainCounterTestInstance	(Context& context);
648 						~SwapchainCounterTestInstance	(void);
649 
650 	tcu::TestStatus		iterate							(void);
651 
652 private:
653 	void				initSwapchainResources			(void);
654 	void				deinitSwapchainResources		(void);
655 	void				render							(void);
656 
657 private:
658 	const PlatformInterface&			m_vkp;
659 	const CustomInstance				m_instance;
660 	const InstanceDriver&				m_vki;
661 	const VkPhysicalDevice				m_physicalDevice;
662 	deUint32							m_planeIndex;
663 	const VkDisplayKHR					m_display;
664 	const VkSurfaceKHR					m_surface;
665 
666 	const deUint32						m_queueFamilyIndex;
667 	const Extensions					m_deviceExtensions;
668 	const Unique<VkDevice>				m_device;
669 	const DeviceDriver					m_vkd;
670 	const VkQueue						m_queue;
671 
672 	const Unique<VkCommandPool>			m_commandPool;
673 	const Unique<VkShaderModule>		m_vertexShaderModule;
674 	const Unique<VkShaderModule>		m_fragmentShaderModule;
675 	const Unique<VkPipelineLayout>		m_pipelineLayout;
676 
677 	const VkSurfaceCapabilities2EXT		m_surfaceProperties;
678 	const vector<VkSurfaceFormatKHR>	m_surfaceFormats;
679 	const vector<VkPresentModeKHR>		m_presentModes;
680 
681 	tcu::ResultCollector				m_resultCollector;
682 
683 	Move<VkSwapchainKHR>				m_swapchain;
684 	std::vector<VkImage>				m_swapchainImages;
685 
686 	Move<VkRenderPass>					m_renderPass;
687 	Move<VkPipeline>					m_pipeline;
688 
689 	std::vector<VkImageView>			m_swapchainImageViews;
690 	std::vector<VkFramebuffer>			m_framebuffers;
691 	std::vector<VkCommandBuffer>		m_commandBuffers;
692 	std::vector<VkSemaphore>			m_acquireSemaphores;
693 	std::vector<VkSemaphore>			m_renderSemaphores;
694 	std::vector<VkFence>				m_fences;
695 
696 	VkSwapchainCounterCreateInfoEXT		m_swapchainCounterConfig;
697 	VkSwapchainCreateInfoKHR			m_swapchainConfig;
698 
699 	const size_t						m_frameCount;
700 	size_t								m_frameNdx;
701 
702 	const size_t						m_maxOutOfDateCount;
703 	size_t								m_outOfDateCount;
704 };
705 
SwapchainCounterTestInstance(Context & context)706 SwapchainCounterTestInstance::SwapchainCounterTestInstance (Context& context)
707 	: TestInstance				(context)
708 	, m_vkp						(context.getPlatformInterface())
709 	, m_instance				(createInstance(context))
710 	, m_vki						(m_instance.getDriver())
711 	, m_physicalDevice			(chooseDevice(m_vki, m_instance, context.getTestContext().getCommandLine()))
712 	, m_planeIndex				(0)
713 	, m_display					(getDisplayAndDisplayPlane(m_vki, m_physicalDevice, &m_planeIndex))
714 	, m_surface					(createSurface(m_vki, m_instance, m_physicalDevice, m_display, m_planeIndex))
715 
716 	, m_queueFamilyIndex		(chooseQueueFamilyIndex(m_vki, m_physicalDevice, m_surface))
717 	, m_deviceExtensions		(enumerateDeviceExtensionProperties(m_vki, m_physicalDevice, DE_NULL))
718 	, m_device					(createDevice(context.getTestContext().getPlatform().getVulkanPlatform(), m_vkp, m_instance, m_vki, m_physicalDevice, m_deviceExtensions, m_queueFamilyIndex, context.getTestContext().getCommandLine().isValidationEnabled()))
719 	, m_vkd						(m_vkp, m_instance, *m_device)
720 	, m_queue					(getDeviceQueue(m_vkd, *m_device, m_queueFamilyIndex, 0u))
721 
722 	, m_commandPool				(createCommandPool(m_vkd, *m_device, m_queueFamilyIndex))
723 	, m_vertexShaderModule		(createShaderModule(m_vkd, *m_device, context.getBinaryCollection().get("quad-vert"), 0u))
724 	, m_fragmentShaderModule	(createShaderModule(m_vkd, *m_device, context.getBinaryCollection().get("quad-frag"), 0u))
725 	, m_pipelineLayout			(createPipelineLayout(m_vkd, *m_device))
726 
727 	, m_surfaceProperties		(wsi::getPhysicalDeviceSurfaceCapabilities2EXT(m_vki, m_physicalDevice, m_surface))
728 	, m_surfaceFormats			(wsi::getPhysicalDeviceSurfaceFormats(m_vki, m_physicalDevice, m_surface))
729 	, m_presentModes			(wsi::getPhysicalDeviceSurfacePresentModes(m_vki, m_physicalDevice, m_surface))
730 
731 	, m_swapchainCounterConfig	(createSwapchainCounterConfig())
732 	, m_swapchainConfig			(createSwapchainConfig(m_surface, m_queueFamilyIndex, m_surfaceProperties, m_surfaceFormats, m_presentModes, VK_PRESENT_MODE_FIFO_KHR, &m_swapchainCounterConfig))
733 
734 	, m_frameCount				(20u)
735 	, m_frameNdx				(0u)
736 
737 	, m_maxOutOfDateCount		(10u)
738 	, m_outOfDateCount			(0u)
739 {
740 }
741 
~SwapchainCounterTestInstance(void)742 SwapchainCounterTestInstance::~SwapchainCounterTestInstance (void)
743 {
744 	deinitSwapchainResources();
745 
746 	m_vki.destroySurfaceKHR(m_instance, m_surface, DE_NULL);
747 }
748 
initSwapchainResources(void)749 void SwapchainCounterTestInstance::initSwapchainResources (void)
750 {
751 	const deUint32		imageWidth	= m_swapchainConfig.imageExtent.width;
752 	const deUint32		imageHeight	= m_swapchainConfig.imageExtent.height;
753 	const VkFormat		imageFormat	= m_swapchainConfig.imageFormat;
754 
755 	m_swapchain			= createSwapchainKHR(m_vkd, *m_device, &m_swapchainConfig);
756 	m_swapchainImages	= wsi::getSwapchainImages(m_vkd, *m_device, *m_swapchain);
757 
758 	m_renderPass		= makeRenderPass(m_vkd, *m_device, imageFormat, VK_FORMAT_UNDEFINED, VK_ATTACHMENT_LOAD_OP_LOAD, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
759 	m_pipeline			= createPipeline(m_vkd, *m_device, *m_renderPass, *m_pipelineLayout, *m_vertexShaderModule, *m_fragmentShaderModule, imageWidth, imageHeight);
760 
761 	const size_t swapchainImagesCount	= m_swapchainImages.size();
762 	const size_t fenceCount				= swapchainImagesCount * 2;
763 
764 	m_swapchainImageViews	= std::vector<VkImageView>(swapchainImagesCount, (VkImageView)0);
765 	m_framebuffers			= std::vector<VkFramebuffer>(swapchainImagesCount, (VkFramebuffer)0);
766 	m_acquireSemaphores		= std::vector<VkSemaphore>(swapchainImagesCount+1, (VkSemaphore)0);
767 	m_renderSemaphores		= std::vector<VkSemaphore>(swapchainImagesCount+1, (VkSemaphore)0);
768 
769 	m_fences				= std::vector<VkFence>(fenceCount, (VkFence)0);
770 	m_commandBuffers		= std::vector<VkCommandBuffer>(fenceCount, (VkCommandBuffer)0);
771 
772 	initImageViews(m_vkd, *m_device, m_swapchainImages, imageFormat, m_swapchainImageViews);
773 	initFramebuffers(m_vkd, *m_device, *m_renderPass, m_swapchainImageViews, imageWidth, imageHeight, m_framebuffers);
774 	initSemaphores(m_vkd, *m_device, m_acquireSemaphores);
775 	initSemaphores(m_vkd, *m_device, m_renderSemaphores);
776 
777 	initFences(m_vkd, *m_device, m_fences);
778 }
779 
deinitSwapchainResources(void)780 void SwapchainCounterTestInstance::deinitSwapchainResources (void)
781 {
782 	VK_CHECK(m_vkd.queueWaitIdle(m_queue));
783 
784 	deinitSemaphores(m_vkd, *m_device, m_acquireSemaphores);
785 	deinitSemaphores(m_vkd, *m_device, m_renderSemaphores);
786 	deinitFences(m_vkd, *m_device, m_fences);
787 	deinitCommandBuffers(m_vkd, *m_device, *m_commandPool, m_commandBuffers);
788 	deinitFramebuffers(m_vkd, *m_device, m_framebuffers);
789 	deinitImageViews(m_vkd, *m_device, m_swapchainImageViews);
790 
791 	m_swapchainImages.clear();
792 
793 	m_swapchain		= Move<VkSwapchainKHR>();
794 	m_renderPass	= Move<VkRenderPass>();
795 	m_pipeline		= Move<VkPipeline>();
796 }
797 
render(void)798 void SwapchainCounterTestInstance::render (void)
799 {
800 	const deUint64		foreverNs		= ~0x0ull;
801 	VkCommandBuffer&	commandBuffer	= m_commandBuffers[m_frameNdx % m_commandBuffers.size()];
802 	const VkFence		fence			= m_fences[m_frameNdx % m_fences.size()];
803 	const deUint32		width			= m_swapchainConfig.imageExtent.width;
804 	const deUint32		height			= m_swapchainConfig.imageExtent.height;
805 
806 	if (m_frameNdx >= m_fences.size())
807 		VK_CHECK(m_vkd.waitForFences(*m_device, 1u, &fence, VK_TRUE, foreverNs));
808 	VK_CHECK(m_vkd.resetFences(*m_device, 1u, &fence));
809 
810 	VkSemaphore currentAcquireSemaphore	= m_acquireSemaphores[m_frameNdx % m_acquireSemaphores.size()];
811 	VkSemaphore currentRenderSemaphore	= m_renderSemaphores[m_frameNdx % m_renderSemaphores.size()];
812 
813 	// Acquire next image
814 	deUint32 imageIndex;
815 	VK_CHECK(m_vkd.acquireNextImageKHR(*m_device, *m_swapchain, foreverNs, currentAcquireSemaphore, (VkFence)0, &imageIndex));
816 
817 	// Create command buffer
818 	commandBuffer = createCommandBuffer(m_vkd, *m_device, *m_commandPool, *m_renderPass, m_swapchainImages[imageIndex],
819 										m_framebuffers[imageIndex], *m_pipeline, width, height).disown();
820 
821 	// Submit command buffer
822 	{
823 		const VkPipelineStageFlags	dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
824 		const VkSubmitInfo			submitInfo =
825 		{
826 			VK_STRUCTURE_TYPE_SUBMIT_INFO,
827 			DE_NULL,
828 			1u,
829 			&currentAcquireSemaphore,
830 			&dstStageMask,
831 			1u,
832 			&commandBuffer,
833 			1u,
834 			&currentRenderSemaphore
835 		};
836 
837 		VK_CHECK(m_vkd.queueSubmit(m_queue, 1u, &submitInfo, fence));
838 	}
839 
840 	VkResult result;
841 	const VkPresentInfoKHR presentInfo =
842 	{
843 		VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
844 		DE_NULL,
845 		1u,
846 		&currentRenderSemaphore,
847 		1u,
848 		&*m_swapchain,
849 		&imageIndex,
850 		&result
851 	};
852 
853 	VK_CHECK_WSI(m_vkd.queuePresentKHR(m_queue, &presentInfo));
854 	VK_CHECK_WSI(result);
855 
856 	// verify counter on last frame - we know that we must have presented as meny frames
857 	// as we rendered minus the number of images in swapchain - that may not have been presented yet
858 	if (m_frameNdx >= m_frameCount)
859 	{
860 		deUint64 counter = 0;
861 		m_vkd.getSwapchainCounterEXT(*m_device, *m_swapchain, VK_SURFACE_COUNTER_VBLANK_EXT, &counter);
862 		if ((counter < (m_frameCount - m_swapchainImages.size())) || (counter > m_frameCount))
863 		{
864 			deinitSwapchainResources();
865 			m_resultCollector.fail("Invalid surface counter value");
866 		}
867 	}
868 }
869 
iterate(void)870 tcu::TestStatus SwapchainCounterTestInstance::iterate (void)
871 {
872 	try
873 	{
874 		// Initialize swapchain specific resources
875 		if (m_frameNdx == 0)
876 			initSwapchainResources();
877 
878 		// Render frame
879 		render();
880 	}
881 	catch (const Error& error)
882 	{
883 		if (error.getError() == VK_ERROR_OUT_OF_DATE_KHR)
884 		{
885 			if (m_outOfDateCount < m_maxOutOfDateCount)
886 			{
887 				m_context.getTestContext().getLog() << TestLog::Message << "Frame " << m_frameNdx
888 					<< ": Swapchain out of date. Recreating resources." << TestLog::EndMessage;
889 				deinitSwapchainResources();
890 				m_outOfDateCount++;
891 				m_frameNdx = 0;
892 
893 				return tcu::TestStatus::incomplete();
894 			}
895 
896 			m_context.getTestContext().getLog() << TestLog::Message << "Frame " << m_frameNdx
897 				<< ": Swapchain out of date." << TestLog::EndMessage;
898 			return tcu::TestStatus::fail("Received too many VK_ERROR_OUT_OF_DATE_KHR errors.");
899 		}
900 
901 		deinitSwapchainResources();
902 		return tcu::TestStatus::fail(error.what());
903 	}
904 
905 	m_frameNdx++;
906 	if (m_frameNdx < m_frameCount)
907 		return tcu::TestStatus::incomplete();
908 
909 	deinitSwapchainResources();
910 	return tcu::TestStatus(m_resultCollector.getResult(), m_resultCollector.getMessage());
911 }
912 
913 class SwapchainCounterTestCase : public TestCase
914 {
915 public:
916 
917 	SwapchainCounterTestCase(tcu::TestContext& context, const char* name);
918 	~SwapchainCounterTestCase() = default;
919 
920 	void					initPrograms(SourceCollections& programCollection) const;
921 	virtual TestInstance*	createInstance(Context& context) const;
922 	virtual void			checkSupport(Context& context) const;
923 };
924 
SwapchainCounterTestCase(tcu::TestContext & context,const char * name)925 SwapchainCounterTestCase::SwapchainCounterTestCase(tcu::TestContext& context, const char* name)
926 	: vkt::TestCase(context, name, name)
927 {
928 }
929 
initPrograms(SourceCollections & dst) const930 void SwapchainCounterTestCase::initPrograms(SourceCollections& dst) const
931 {
932 	dst.glslSources.add("quad-vert") << glu::VertexSource(
933 		"#version 450\n"
934 		"out gl_PerVertex {\n"
935 		"    vec4 gl_Position;\n"
936 		"};\n"
937 		"highp float;\n"
938 		"void main (void) {\n"
939 		"    gl_Position = vec4(((gl_VertexIndex + 2) / 3) % 2 == 0 ? -1.0 : 1.0,\n"
940 		"                       ((gl_VertexIndex + 1) / 3) % 2 == 0 ? -1.0 : 1.0, 0.0, 1.0);\n"
941 		"}\n");
942 	dst.glslSources.add("quad-frag") << glu::FragmentSource(
943 		"#version 450\n"
944 		"layout(location = 0) out highp vec4 o_color;\n"
945 		"void main (void)\n"
946 		"{\n"
947 		"    o_color = vec4(1.0, 0.5, 0.0, 1.0);\n"
948 		"}\n");
949 }
950 
createInstance(Context & context) const951 TestInstance* SwapchainCounterTestCase::createInstance(Context& context) const
952 {
953 	return new SwapchainCounterTestInstance(context);
954 }
955 
checkSupport(Context & context) const956 void SwapchainCounterTestCase::checkSupport(Context& context) const
957 {
958 	context.requireInstanceFunctionality("VK_KHR_display");
959 	context.requireDeviceFunctionality("VK_EXT_display_control");
960 }
961 
getDisplays(Context & context,std::vector<VkDisplayKHR> & availableDisplays)962 void getDisplays(Context& context, std::vector<VkDisplayKHR>& availableDisplays)
963 {
964 	// get number of displays
965 	deUint32					countReported		= 0u;
966 	VkPhysicalDevice			physicalDevice		= context.getPhysicalDevice();
967 	const InstanceInterface&	vki					= context.getInstanceInterface();
968 
969 	VkResult result = vki.getPhysicalDeviceDisplayPropertiesKHR(physicalDevice, &countReported, DE_NULL);
970 	if (result != VK_SUCCESS)
971 		TCU_THROW(NotSupportedError, "vkGetPhysicalDeviceDisplayPropertiesKHR failed");
972 
973 	if (countReported == 0)
974 		TCU_THROW(NotSupportedError, "No displays available");
975 
976 	// get display properties
977 	std::vector<VkDisplayPropertiesKHR> displaysProperties(countReported);
978 	result = vki.getPhysicalDeviceDisplayPropertiesKHR(physicalDevice, &countReported, &displaysProperties[0]);
979 
980 	if (result != VK_SUCCESS)
981 		TCU_THROW(NotSupportedError, "vkGetPhysicalDeviceDisplayPropertiesKHR failed");
982 
983 	availableDisplays.clear();
984 	for (const auto& dp : displaysProperties)
985 		availableDisplays.push_back(dp.display);
986 }
987 
testDisplayPowerControl(Context & context)988 tcu::TestStatus testDisplayPowerControl(Context& context)
989 {
990 	// make sure VK_EXT_display_control is available
991 	context.requireDeviceFunctionality("VK_EXT_display_control");
992 
993 	// get all connected displays
994 	std::vector<VkDisplayKHR> availableDisplays;
995 	getDisplays(context, availableDisplays);
996 
997 	struct PowerStateData
998 	{
999 		VkDisplayPowerStateEXT	state;
1000 		deUint32				waitMs;
1001 	};
1002 	vector<PowerStateData> powerStateDataVect =
1003 	{
1004 		{ VK_DISPLAY_POWER_STATE_ON_EXT,		1000 },
1005 		{ VK_DISPLAY_POWER_STATE_SUSPEND_EXT,	1000 },
1006 		{ VK_DISPLAY_POWER_STATE_OFF_EXT,		1000 },
1007 		{ VK_DISPLAY_POWER_STATE_ON_EXT,		1000 },
1008 	};
1009 
1010 	// iterate over all displays
1011 	VkDevice						device	= context.getDevice();
1012 	const vk::DeviceInterface&		vkd		= context.getDeviceInterface();
1013 	for (const auto& display : availableDisplays)
1014 	{
1015 		// iterate over tested sequence of power states
1016 		for (const auto& psd : powerStateDataVect)
1017 		{
1018 			VkDisplayPowerInfoEXT displayPowerInfo =
1019 			{
1020 				VK_STRUCTURE_TYPE_DISPLAY_POWER_INFO_EXT,
1021 				DE_NULL,
1022 				psd.state
1023 			};
1024 
1025 			VkResult result = vkd.displayPowerControlEXT(device, display, &displayPowerInfo);
1026 			if (result != VK_SUCCESS)
1027 				tcu::TestStatus::fail(std::string("vkDisplayPowerControlEXT returned invalid result for ") + de::toString(psd.state));
1028 
1029 			deSleep(psd.waitMs);
1030 		}
1031 	}
1032 
1033 	return tcu::TestStatus::pass("pass");
1034 }
1035 
testDisplayEvent(Context & context)1036 tcu::TestStatus testDisplayEvent(Context& context)
1037 {
1038 	// make sure VK_EXT_display_control is available
1039 	context.requireDeviceFunctionality("VK_EXT_display_control");
1040 
1041 	// get all connected displays
1042 	std::vector<vk::VkDisplayKHR> availableDisplays;
1043 	getDisplays(context, availableDisplays);
1044 
1045 	VkDevice				device	= context.getDevice();
1046 	const DeviceInterface&	vkd		= context.getDeviceInterface();
1047 	std::vector<VkFence>	fences	= std::vector<VkFence>(availableDisplays.size(), (VkFence)0);
1048 
1049 	// iterate over all displays
1050 	for (size_t i = 0 ; i < availableDisplays.size() ; ++i)
1051 	{
1052 		VkDisplayEventInfoEXT displayEventInfo =
1053 		{
1054 			VK_STRUCTURE_TYPE_DISPLAY_EVENT_INFO_EXT,
1055 			DE_NULL,
1056 			VK_DISPLAY_EVENT_TYPE_FIRST_PIXEL_OUT_EXT
1057 		};
1058 
1059 		VkFence&		fence		= fences[i];
1060 		VkDisplayKHR&	display		= availableDisplays[i];
1061 		VkResult		result		= vkd.registerDisplayEventEXT(device, display, &displayEventInfo, DE_NULL, &fence);
1062 		if (result != VK_SUCCESS)
1063 			tcu::TestStatus::fail(std::string("vkRegisterDisplayEventEXT returned invalid result"));
1064 	}
1065 
1066 	// deinit fence
1067 	deinitFences (vkd, device, fences);
1068 
1069 	return tcu::TestStatus::pass("pass");
1070 }
1071 
testDeviceEvent(Context & context)1072 tcu::TestStatus testDeviceEvent(Context& context)
1073 {
1074 	// make sure VK_EXT_display_control is available
1075 	context.requireDeviceFunctionality("VK_EXT_display_control");
1076 
1077 	VkDevice				device = context.getDevice();
1078 	const DeviceInterface&	vkd = context.getDeviceInterface();
1079 	std::vector<VkFence>	fences = std::vector<VkFence>(1, (VkFence)0);
1080 
1081 	vk::VkDeviceEventInfoEXT deviceEventInfo =
1082 	{
1083 		VK_STRUCTURE_TYPE_DEVICE_EVENT_INFO_EXT,
1084 		DE_NULL,
1085 		VK_DEVICE_EVENT_TYPE_DISPLAY_HOTPLUG_EXT
1086 	};
1087 
1088 	VkResult result = vkd.registerDeviceEventEXT(device, &deviceEventInfo, DE_NULL, &fences[0]);
1089 	if (result != VK_SUCCESS)
1090 		tcu::TestStatus::fail(std::string("vkRegisterDeviceEventEXT returned invalid result"));
1091 
1092 	// deinit fence
1093 	deinitFences(vkd, device, fences);
1094 
1095 	return tcu::TestStatus::pass("pass");
1096 }
1097 
1098 } // anonymous
1099 
createDisplayControlTests(tcu::TestCaseGroup * testGroup)1100 void createDisplayControlTests (tcu::TestCaseGroup* testGroup)
1101 {
1102 	testGroup->addChild(new SwapchainCounterTestCase(testGroup->getTestContext(), "swapchain_counter"));
1103 	addFunctionCase(testGroup, "display_power_control",		"Test display power control",	testDisplayPowerControl);
1104 	addFunctionCase(testGroup, "register_display_event",	"Test register display event",	testDisplayEvent);
1105 	addFunctionCase(testGroup, "register_device_event",		"Test register device event",	testDeviceEvent);
1106 }
1107 
1108 } // wsi
1109 } // vkt
1110