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