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