Home | History | Annotate | Download | only in wsi
      1 /*-------------------------------------------------------------------------
      2  * Vulkan Conformance Tests
      3  * ------------------------
      4  *
      5  * Copyright (c) 2017 Google Inc.
      6  *
      7  * Licensed under the Apache License, Version 2.0 (the "License");
      8  * you may not use this file except in compliance with the License.
      9  * You may obtain a copy of the License at
     10  *
     11  *      http://www.apache.org/licenses/LICENSE-2.0
     12  *
     13  * Unless required by applicable law or agreed to in writing, software
     14  * distributed under the License is distributed on an "AS IS" BASIS,
     15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     16  * See the License for the specific language governing permissions and
     17  * limitations under the License.
     18  *
     19  *//*!
     20  * \file
     21  * \brief Tests for shared presentable image extension
     22  *//*--------------------------------------------------------------------*/
     23 
     24 #include "vktWsiSharedPresentableImageTests.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 	if (!vk::isCoreInstanceExtension(version, "VK_KHR_get_physical_device_properties2"))
     87 		extensions.push_back("VK_KHR_get_physical_device_properties2");
     88 
     89 	extensions.push_back("VK_KHR_surface");
     90 	extensions.push_back("VK_KHR_get_surface_capabilities2");
     91 	// Required for device extension to expose new physical device bits (in this
     92 	// case, presentation mode enums)
     93 	extensions.push_back(getExtensionName(wsiType));
     94 
     95 	checkAllSupported(supportedExtensions, extensions);
     96 
     97 	return vk::createDefaultInstance(vkp, version, vector<string>(), extensions);
     98 }
     99 
    100 vk::VkPhysicalDeviceFeatures getDeviceNullFeatures (void)
    101 {
    102 	vk::VkPhysicalDeviceFeatures features;
    103 	deMemset(&features, 0, sizeof(features));
    104 	return features;
    105 }
    106 
    107 deUint32 getNumQueueFamilyIndices (const vk::InstanceInterface& vki, vk::VkPhysicalDevice physicalDevice)
    108 {
    109 	deUint32	numFamilies		= 0;
    110 
    111 	vki.getPhysicalDeviceQueueFamilyProperties(physicalDevice, &numFamilies, DE_NULL);
    112 
    113 	return numFamilies;
    114 }
    115 
    116 vector<deUint32> getSupportedQueueFamilyIndices (const vk::InstanceInterface& vki, vk::VkPhysicalDevice physicalDevice, vk::VkSurfaceKHR surface)
    117 {
    118 	const deUint32		numTotalFamilyIndices	= getNumQueueFamilyIndices(vki, physicalDevice);
    119 	vector<deUint32>	supportedFamilyIndices;
    120 
    121 	for (deUint32 queueFamilyNdx = 0; queueFamilyNdx < numTotalFamilyIndices; ++queueFamilyNdx)
    122 	{
    123 		if (vk::wsi::getPhysicalDeviceSurfaceSupport(vki, physicalDevice, queueFamilyNdx, surface) != VK_FALSE)
    124 			supportedFamilyIndices.push_back(queueFamilyNdx);
    125 	}
    126 
    127 	return supportedFamilyIndices;
    128 }
    129 
    130 deUint32 chooseQueueFamilyIndex (const vk::InstanceInterface& vki, vk::VkPhysicalDevice physicalDevice, vk::VkSurfaceKHR surface)
    131 {
    132 	const vector<deUint32>	supportedFamilyIndices	= getSupportedQueueFamilyIndices(vki, physicalDevice, surface);
    133 
    134 	if (supportedFamilyIndices.empty())
    135 		TCU_THROW(NotSupportedError, "Device doesn't support presentation");
    136 
    137 	return supportedFamilyIndices[0];
    138 }
    139 
    140 vk::Move<vk::VkDevice> createDeviceWithWsi (const vk::InstanceInterface&		vki,
    141 											vk::VkPhysicalDevice				physicalDevice,
    142 											const Extensions&					supportedExtensions,
    143 											const deUint32						queueFamilyIndex,
    144 											bool								requiresSharedPresentableImage,
    145 											const vk::VkAllocationCallbacks*	pAllocator = DE_NULL)
    146 {
    147 	const float							queuePriorities[]	= { 1.0f };
    148 	const vk::VkDeviceQueueCreateInfo	queueInfos[]		=
    149 	{
    150 		{
    151 			vk::VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
    152 			DE_NULL,
    153 			(vk::VkDeviceQueueCreateFlags)0,
    154 			queueFamilyIndex,
    155 			DE_LENGTH_OF_ARRAY(queuePriorities),
    156 			&queuePriorities[0]
    157 		}
    158 	};
    159 	const vk::VkPhysicalDeviceFeatures	features		= getDeviceNullFeatures();
    160 	const char* const					extensions[]	=
    161 	{
    162 		"VK_KHR_swapchain",
    163 		"VK_KHR_shared_presentable_image"
    164 	};
    165 
    166 	const vk::VkDeviceCreateInfo		deviceParams	=
    167 	{
    168 		vk::VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
    169 		DE_NULL,
    170 		(vk::VkDeviceCreateFlags)0,
    171 		DE_LENGTH_OF_ARRAY(queueInfos),
    172 		&queueInfos[0],
    173 		0u,
    174 		DE_NULL,
    175 		requiresSharedPresentableImage ? 2u : 1u,
    176 		DE_ARRAY_BEGIN(extensions),
    177 		&features
    178 	};
    179 
    180 	for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(extensions); ++ndx)
    181 	{
    182 		if (!isExtensionSupported(supportedExtensions, vk::RequiredExtension(extensions[ndx])))
    183 			TCU_THROW(NotSupportedError, (string(extensions[ndx]) + " is not supported").c_str());
    184 	}
    185 
    186 	return createDevice(vki, physicalDevice, &deviceParams, pAllocator);
    187 }
    188 
    189 de::MovePtr<vk::wsi::Display> createDisplay (const vk::Platform&	platform,
    190 											 const Extensions&		supportedExtensions,
    191 											 vk::wsi::Type			wsiType)
    192 {
    193 	try
    194 	{
    195 		return de::MovePtr<vk::wsi::Display>(platform.createWsiDisplay(wsiType));
    196 	}
    197 	catch (const tcu::NotSupportedError& e)
    198 	{
    199 		if (isExtensionSupported(supportedExtensions, vk::RequiredExtension(getExtensionName(wsiType))))
    200 		{
    201 			// If VK_KHR_{platform}_surface was supported, vk::Platform implementation
    202 			// must support creating native display & window for that WSI type.
    203 			throw tcu::TestError(e.getMessage());
    204 		}
    205 		else
    206 			throw;
    207 	}
    208 }
    209 
    210 de::MovePtr<vk::wsi::Window> createWindow (const vk::wsi::Display& display, const Maybe<UVec2>& initialSize)
    211 {
    212 	try
    213 	{
    214 		return de::MovePtr<vk::wsi::Window>(display.createWindow(initialSize));
    215 	}
    216 	catch (const tcu::NotSupportedError& e)
    217 	{
    218 		// See createDisplay - assuming that wsi::Display was supported platform port
    219 		// should also support creating a window.
    220 		throw tcu::TestError(e.getMessage());
    221 	}
    222 }
    223 
    224 bool wsiTypeSupportsScaling (vk::wsi::Type wsiType)
    225 {
    226 	return vk::wsi::getPlatformProperties(wsiType).swapchainExtent == vk::wsi::PlatformProperties::SWAPCHAIN_EXTENT_SCALED_TO_WINDOW_SIZE;
    227 }
    228 
    229 void initSemaphores (const vk::DeviceInterface&		vkd,
    230 					 vk::VkDevice					device,
    231 					 std::vector<vk::VkSemaphore>&	semaphores)
    232 {
    233 	for (size_t ndx = 0; ndx < semaphores.size(); ndx++)
    234 		semaphores[ndx] = createSemaphore(vkd, device).disown();
    235 }
    236 
    237 void deinitSemaphores (const vk::DeviceInterface&	vkd,
    238 					 vk::VkDevice					device,
    239 					 std::vector<vk::VkSemaphore>&	semaphores)
    240 {
    241 	for (size_t ndx = 0; ndx < semaphores.size(); ndx++)
    242 	{
    243 		if (semaphores[ndx] != (vk::VkSemaphore)0)
    244 			vkd.destroySemaphore(device, semaphores[ndx], DE_NULL);
    245 
    246 		semaphores[ndx] = (vk::VkSemaphore)0;
    247 	}
    248 
    249 	semaphores.clear();
    250 }
    251 
    252 void initFences (const vk::DeviceInterface&	vkd,
    253 				 vk::VkDevice				device,
    254 				 std::vector<vk::VkFence>&	fences)
    255 {
    256 	for (size_t ndx = 0; ndx < fences.size(); ndx++)
    257 		fences[ndx] = createFence(vkd, device).disown();
    258 }
    259 
    260 void deinitFences (const vk::DeviceInterface&	vkd,
    261 				   vk::VkDevice					device,
    262 				   std::vector<vk::VkFence>&	fences)
    263 {
    264 	for (size_t ndx = 0; ndx < fences.size(); ndx++)
    265 	{
    266 		if (fences[ndx] != (vk::VkFence)0)
    267 			vkd.destroyFence(device, fences[ndx], DE_NULL);
    268 
    269 		fences[ndx] = (vk::VkFence)0;
    270 	}
    271 
    272 	fences.clear();
    273 }
    274 
    275 void cmdRenderFrame (const vk::DeviceInterface&	vkd,
    276 					 vk::VkCommandBuffer		commandBuffer,
    277 					 vk::VkPipelineLayout		pipelineLayout,
    278 					 vk::VkPipeline				pipeline,
    279 					 size_t						frameNdx,
    280 					 deUint32					quadCount)
    281 {
    282 	const deUint32 frameNdxValue  =	(deUint32)frameNdx;
    283 
    284 	vkd.cmdPushConstants(commandBuffer, pipelineLayout, vk::VK_SHADER_STAGE_FRAGMENT_BIT, 0u, 4u, &frameNdxValue);
    285 	vkd.cmdBindPipeline(commandBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
    286 	vkd.cmdDraw(commandBuffer, quadCount * 6u, 1u, 0u, 0u);
    287 }
    288 
    289 vk::Move<vk::VkCommandBuffer> createCommandBuffer (const vk::DeviceInterface&	vkd,
    290 												   vk::VkDevice					device,
    291 												   vk::VkCommandPool			commandPool,
    292 												   vk::VkPipelineLayout			pipelineLayout,
    293 												   vk::VkRenderPass				renderPass,
    294 												   vk::VkFramebuffer			framebuffer,
    295 												   vk::VkPipeline				pipeline,
    296 												   size_t						frameNdx,
    297 												   deUint32						quadCount,
    298 												   deUint32						imageWidth,
    299 												   deUint32						imageHeight)
    300 {
    301 	const vk::VkCommandBufferAllocateInfo allocateInfo =
    302 	{
    303 		vk::VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
    304 		DE_NULL,
    305 
    306 		commandPool,
    307 		vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY,
    308 		1
    309 	};
    310 	const vk::VkCommandBufferBeginInfo	beginInfo		=
    311 	{
    312 		vk::VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
    313 		DE_NULL,
    314 		0u,
    315 		DE_NULL
    316 	};
    317 
    318 	vk::Move<vk::VkCommandBuffer>	commandBuffer	(vk::allocateCommandBuffer(vkd, device, &allocateInfo));
    319 	VK_CHECK(vkd.beginCommandBuffer(*commandBuffer, &beginInfo));
    320 
    321 	{
    322 		const vk::VkClearValue			clearValue			= vk::makeClearValueColorF32(0.25f, 0.50f, 0.75f, 1.00f);
    323 		const vk::VkRenderPassBeginInfo	renderPassBeginInfo	=
    324 		{
    325 			vk::VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
    326 			DE_NULL,
    327 
    328 			renderPass,
    329 			framebuffer,
    330 
    331 			{
    332 				{ (deInt32)0, (deInt32)0 },
    333 				{ imageWidth, imageHeight }
    334 			},
    335 			1u,
    336 			&clearValue
    337 		};
    338 		vkd.cmdBeginRenderPass(*commandBuffer, &renderPassBeginInfo, vk::VK_SUBPASS_CONTENTS_INLINE);
    339 	}
    340 
    341 	cmdRenderFrame(vkd, *commandBuffer, pipelineLayout, pipeline, frameNdx, quadCount);
    342 
    343 	vkd.cmdEndRenderPass(*commandBuffer);
    344 
    345 	VK_CHECK(vkd.endCommandBuffer(*commandBuffer));
    346 	return commandBuffer;
    347 }
    348 
    349 void deinitCommandBuffers (const vk::DeviceInterface&			vkd,
    350 						   vk::VkDevice							device,
    351 						   vk::VkCommandPool					commandPool,
    352 						   std::vector<vk::VkCommandBuffer>&	commandBuffers)
    353 {
    354 	for (size_t ndx = 0; ndx < commandBuffers.size(); ndx++)
    355 	{
    356 		if (commandBuffers[ndx] != (vk::VkCommandBuffer)0)
    357 			vkd.freeCommandBuffers(device, commandPool, 1u,  &commandBuffers[ndx]);
    358 
    359 		commandBuffers[ndx] = (vk::VkCommandBuffer)0;
    360 	}
    361 
    362 	commandBuffers.clear();
    363 }
    364 
    365 vk::Move<vk::VkCommandPool> createCommandPool (const vk::DeviceInterface&	vkd,
    366 											   vk::VkDevice					device,
    367 											   deUint32						queueFamilyIndex)
    368 {
    369 	const vk::VkCommandPoolCreateInfo createInfo =
    370 	{
    371 		vk::VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
    372 		DE_NULL,
    373 		0u,
    374 		queueFamilyIndex
    375 	};
    376 
    377 	return vk::createCommandPool(vkd, device, &createInfo);
    378 }
    379 
    380 vk::Move<vk::VkFramebuffer>	createFramebuffer (const vk::DeviceInterface&	vkd,
    381 											   vk::VkDevice					device,
    382 											   vk::VkRenderPass				renderPass,
    383 											   vk::VkImageView				imageView,
    384 											   deUint32						width,
    385 											   deUint32						height)
    386 {
    387 	const vk::VkFramebufferCreateInfo createInfo =
    388 	{
    389 		vk::VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
    390 		DE_NULL,
    391 
    392 		0u,
    393 		renderPass,
    394 		1u,
    395 		&imageView,
    396 		width,
    397 		height,
    398 		1u
    399 	};
    400 
    401 	return vk::createFramebuffer(vkd, device, &createInfo);
    402 }
    403 
    404 vk::Move<vk::VkImageView> createImageView (const vk::DeviceInterface&	vkd,
    405 										   vk::VkDevice					device,
    406 										   vk::VkImage					image,
    407 										   vk::VkFormat					format)
    408 {
    409 	const vk::VkImageViewCreateInfo	createInfo =
    410 	{
    411 		vk::VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
    412 		DE_NULL,
    413 
    414 		0u,
    415 		image,
    416 		vk::VK_IMAGE_VIEW_TYPE_2D,
    417 		format,
    418 		vk::makeComponentMappingRGBA(),
    419 		{
    420 			vk::VK_IMAGE_ASPECT_COLOR_BIT,
    421 			0u,
    422 			1u,
    423 			0u,
    424 			1u
    425 		}
    426 	};
    427 
    428 	return vk::createImageView(vkd, device, &createInfo, DE_NULL);
    429 }
    430 
    431 vk::Move<vk::VkRenderPass> createRenderPass (const vk::DeviceInterface&	vkd,
    432 											 vk::VkDevice				device,
    433 											 vk::VkFormat				format)
    434 {
    435 	const vk::VkAttachmentDescription	attachments[]			=
    436 	{
    437 		{
    438 			0u,
    439 			format,
    440 			vk::VK_SAMPLE_COUNT_1_BIT,
    441 
    442 			vk::VK_ATTACHMENT_LOAD_OP_LOAD,
    443 			vk::VK_ATTACHMENT_STORE_OP_STORE,
    444 
    445 			vk::VK_ATTACHMENT_LOAD_OP_DONT_CARE,
    446 			vk::VK_ATTACHMENT_STORE_OP_DONT_CARE,
    447 
    448 			// This differs from the usual layout handling in that the
    449 			// swapchain image remains in IMAGE_LAYOUT_SHARED_PRESENT_KHR all
    450 			// the time. We should not ever transition it away (or discard the
    451 			// contents with a transition from UNDEFINED) as the PE is accessing
    452 			// the image concurrently with our rendering.
    453 			vk::VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR,
    454 			vk::VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR
    455 		}
    456 	};
    457 	const vk::VkAttachmentReference		colorAttachmentRefs[]	=
    458 	{
    459 		{
    460 			0u,
    461 			vk::VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR
    462 		}
    463 	};
    464 	const vk::VkSubpassDescription		subpasses[]				=
    465 	{
    466 		{
    467 			0u,
    468 			vk::VK_PIPELINE_BIND_POINT_GRAPHICS,
    469 			0u,
    470 			DE_NULL,
    471 
    472 			DE_LENGTH_OF_ARRAY(colorAttachmentRefs),
    473 			colorAttachmentRefs,
    474 			DE_NULL,
    475 
    476 			DE_NULL,
    477 			0u,
    478 			DE_NULL
    479 		}
    480 	};
    481 
    482 	const vk::VkRenderPassCreateInfo	createInfo				=
    483 	{
    484 		vk::VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
    485 		DE_NULL,
    486 		0u,
    487 
    488 		DE_LENGTH_OF_ARRAY(attachments),
    489 		attachments,
    490 
    491 		DE_LENGTH_OF_ARRAY(subpasses),
    492 		subpasses,
    493 
    494 		0u,
    495 		DE_NULL
    496 	};
    497 
    498 	return vk::createRenderPass(vkd, device, &createInfo);
    499 }
    500 
    501 vk::Move<vk::VkPipeline> createPipeline (const vk::DeviceInterface&	vkd,
    502 										 vk::VkDevice				device,
    503 										 vk::VkRenderPass			renderPass,
    504 										 vk::VkPipelineLayout		layout,
    505 										 vk::VkShaderModule			vertexShaderModule,
    506 										 vk::VkShaderModule			fragmentShaderModule,
    507 										 deUint32					width,
    508 										 deUint32					height)
    509 {
    510 	const vk::VkSpecializationInfo				shaderSpecialization	=
    511 	{
    512 		0u,
    513 		DE_NULL,
    514 		0,
    515 		DE_NULL
    516 	};
    517 	const vk::VkPipelineShaderStageCreateInfo		stages[]			=
    518 	{
    519 		{
    520 			vk::VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
    521 			DE_NULL,
    522 			0u,
    523 			vk::VK_SHADER_STAGE_VERTEX_BIT,
    524 			vertexShaderModule,
    525 			"main",
    526 			&shaderSpecialization
    527 		},
    528 		{
    529 			vk::VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
    530 			DE_NULL,
    531 			0u,
    532 			vk::VK_SHADER_STAGE_FRAGMENT_BIT,
    533 			fragmentShaderModule,
    534 			"main",
    535 			&shaderSpecialization
    536 		}
    537 	};
    538 	const vk::VkPipelineVertexInputStateCreateInfo	vertexInputState	=
    539 	{
    540 		vk::VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
    541 		DE_NULL,
    542 		0u,
    543 		0u,
    544 		DE_NULL,
    545 		0u,
    546 		DE_NULL
    547 	};
    548 	const vk::VkPipelineInputAssemblyStateCreateInfo	inputAssemblyState	=
    549 	{
    550 		vk::VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
    551 		DE_NULL,
    552 		0u,
    553 		vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
    554 		VK_FALSE
    555 	};
    556 	const vk::VkViewport viewports[] =
    557 	{
    558 		{
    559 			0.0f, 0.0f,
    560 			(float)width, (float)height,
    561 			0.0f, 1.0f
    562 		}
    563 	};
    564 	const vk::VkRect2D scissors[] =
    565 	{
    566 		{
    567 			{ 0u, 0u },
    568 			{ width, height }
    569 		}
    570 	};
    571 	const vk::VkPipelineViewportStateCreateInfo			viewportState		=
    572 	{
    573 		vk::VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
    574 		DE_NULL,
    575 		0u,
    576 
    577 		DE_LENGTH_OF_ARRAY(viewports),
    578 		viewports,
    579 		DE_LENGTH_OF_ARRAY(scissors),
    580 		scissors
    581 	};
    582 	const vk::VkPipelineRasterizationStateCreateInfo	rasterizationState	=
    583 	{
    584 		vk::VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
    585 		DE_NULL,
    586 		0u,
    587 		VK_TRUE,
    588 		VK_FALSE,
    589 		vk::VK_POLYGON_MODE_FILL,
    590 		vk::VK_CULL_MODE_NONE,
    591 		vk::VK_FRONT_FACE_CLOCKWISE,
    592 		VK_FALSE,
    593 		0.0f,
    594 		0.0f,
    595 		0.0f,
    596 		1.0f
    597 	};
    598 	const vk::VkSampleMask								sampleMask			= ~0u;
    599 	const vk::VkPipelineMultisampleStateCreateInfo		multisampleState	=
    600 	{
    601 		vk::VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
    602 		DE_NULL,
    603 		0u,
    604 		vk::VK_SAMPLE_COUNT_1_BIT,
    605 		VK_FALSE,
    606 		0.0f,
    607 		&sampleMask,
    608 		VK_FALSE,
    609 		VK_FALSE
    610 	};
    611 	const vk::VkPipelineDepthStencilStateCreateInfo	depthStencilState		=
    612 	{
    613 		vk::VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,
    614 		DE_NULL,
    615 		0u,
    616 		DE_FALSE,
    617 		DE_FALSE,
    618 		vk::VK_COMPARE_OP_ALWAYS,
    619 		DE_FALSE,
    620 		DE_FALSE,
    621 		{
    622 			vk::VK_STENCIL_OP_KEEP,
    623 			vk::VK_STENCIL_OP_KEEP,
    624 			vk::VK_STENCIL_OP_KEEP,
    625 			vk::VK_COMPARE_OP_ALWAYS,
    626 			0u,
    627 			0u,
    628 			0u,
    629 		},
    630 		{
    631 			vk::VK_STENCIL_OP_KEEP,
    632 			vk::VK_STENCIL_OP_KEEP,
    633 			vk::VK_STENCIL_OP_KEEP,
    634 			vk::VK_COMPARE_OP_ALWAYS,
    635 			0u,
    636 			0u,
    637 			0u,
    638 		},
    639 		0.0f,
    640 		1.0f
    641 	};
    642 	const vk::VkPipelineColorBlendAttachmentState	attachmentBlendState			=
    643 	{
    644 		VK_FALSE,
    645 		vk::VK_BLEND_FACTOR_ONE,
    646 		vk::VK_BLEND_FACTOR_ZERO,
    647 		vk::VK_BLEND_OP_ADD,
    648 		vk::VK_BLEND_FACTOR_ONE,
    649 		vk::VK_BLEND_FACTOR_ZERO,
    650 		vk::VK_BLEND_OP_ADD,
    651 		(vk::VK_COLOR_COMPONENT_R_BIT|
    652 		 vk::VK_COLOR_COMPONENT_G_BIT|
    653 		 vk::VK_COLOR_COMPONENT_B_BIT|
    654 		 vk::VK_COLOR_COMPONENT_A_BIT),
    655 	};
    656 	const vk::VkPipelineColorBlendStateCreateInfo	blendState				=
    657 	{
    658 		vk::VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
    659 		DE_NULL,
    660 		0u,
    661 		DE_FALSE,
    662 		vk::VK_LOGIC_OP_COPY,
    663 		1u,
    664 		&attachmentBlendState,
    665 		{ 0.0f, 0.0f, 0.0f, 0.0f }
    666 	};
    667 	const vk::VkDynamicState							dynamicStates[]		=
    668 	{
    669 		vk::VK_DYNAMIC_STATE_SCISSOR
    670 	};
    671 	const vk::VkPipelineDynamicStateCreateInfo			dynamicState		=
    672 	{
    673 		vk::VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,
    674 		DE_NULL,
    675 		0u,
    676 
    677 		DE_LENGTH_OF_ARRAY(dynamicStates),
    678 		dynamicStates
    679 	};
    680 	const vk::VkGraphicsPipelineCreateInfo				createInfo			=
    681 	{
    682 		vk::VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
    683 		DE_NULL,
    684 		0u,
    685 
    686 		DE_LENGTH_OF_ARRAY(stages),
    687 		stages,
    688 		&vertexInputState,
    689 		&inputAssemblyState,
    690 		DE_NULL,
    691 		&viewportState,
    692 		&rasterizationState,
    693 		&multisampleState,
    694 		&depthStencilState,
    695 		&blendState,
    696 		&dynamicState,
    697 		layout,
    698 		renderPass,
    699 		0u,
    700 		DE_NULL,
    701 		0u
    702 	};
    703 
    704 	return vk::createGraphicsPipeline(vkd, device, DE_NULL,  &createInfo);
    705 }
    706 
    707 vk::Move<vk::VkPipelineLayout> createPipelineLayout (const vk::DeviceInterface&	vkd,
    708 													 vk::VkDevice				device)
    709 {
    710 	const vk::VkPushConstantRange			pushConstants[] =
    711 	{
    712 		{
    713 			vk::VK_SHADER_STAGE_FRAGMENT_BIT,
    714 			0u,
    715 			4u
    716 		}
    717 	};
    718 	const vk::VkPipelineLayoutCreateInfo	createInfo	=
    719 	{
    720 		vk::VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
    721 		DE_NULL,
    722 		0u,
    723 
    724 		0u,
    725 		DE_NULL,
    726 
    727 		DE_LENGTH_OF_ARRAY(pushConstants),
    728 		pushConstants,
    729 	};
    730 
    731 	return vk::createPipelineLayout(vkd, device, &createInfo);
    732 }
    733 
    734 struct TestConfig
    735 {
    736 	vk::wsi::Type			wsiType;
    737 	Scaling					scaling;
    738 	bool					useSharedPresentableImage;
    739 	vk::VkPresentModeKHR	presentMode;
    740 };
    741 
    742 class SharedPresentableImageTestInstance : public TestInstance
    743 {
    744 public:
    745 													SharedPresentableImageTestInstance	(Context& context, const TestConfig& testConfig);
    746 													~SharedPresentableImageTestInstance	(void);
    747 
    748 	tcu::TestStatus									iterate								(void);
    749 
    750 private:
    751 	const TestConfig								m_testConfig;
    752 	const deUint32									m_quadCount;
    753 	const vk::PlatformInterface&					m_vkp;
    754 	const Extensions								m_instanceExtensions;
    755 	const vk::Unique<vk::VkInstance>				m_instance;
    756 	const vk::InstanceDriver						m_vki;
    757 	const vk::VkPhysicalDevice						m_physicalDevice;
    758 	const de::UniquePtr<vk::wsi::Display>			m_nativeDisplay;
    759 	const de::UniquePtr<vk::wsi::Window>			m_nativeWindow;
    760 	const vk::Unique<vk::VkSurfaceKHR>				m_surface;
    761 
    762 	const deUint32									m_queueFamilyIndex;
    763 	const Extensions								m_deviceExtensions;
    764 	const vk::Unique<vk::VkDevice>					m_device;
    765 	const vk::DeviceDriver							m_vkd;
    766 	const vk::VkQueue								m_queue;
    767 
    768 	const vk::Unique<vk::VkCommandPool>				m_commandPool;
    769 	const vk::Unique<vk::VkShaderModule>			m_vertexShaderModule;
    770 	const vk::Unique<vk::VkShaderModule>			m_fragmentShaderModule;
    771 	const vk::Unique<vk::VkPipelineLayout>			m_pipelineLayout;
    772 
    773 	vk::VkImageUsageFlags							m_supportedUsageFlags;
    774 	const vk::VkSurfaceCapabilitiesKHR				m_surfaceProperties;
    775 	const vector<vk::VkSurfaceFormatKHR>			m_surfaceFormats;
    776 	const vector<vk::VkPresentModeKHR>				m_presentModes;
    777 
    778 	tcu::ResultCollector							m_resultCollector;
    779 
    780 	vk::Move<vk::VkSwapchainKHR>					m_swapchain;
    781 	vk::VkImage										m_swapchainImage;			  // NOTE: not owning. lifetime managed by swapchain
    782 	vk::Move<vk::VkImageView>						m_swapchainImageView;
    783 	vk::Move<vk::VkFramebuffer>						m_framebuffer;
    784 
    785 	vk::Move<vk::VkRenderPass>						m_renderPass;
    786 	vk::Move<vk::VkPipeline>						m_pipeline;
    787 
    788 	std::vector<vk::VkCommandBuffer>				m_commandBuffers;
    789 	std::vector<vk::VkSemaphore>					m_renderSemaphores;
    790 	std::vector<vk::VkFence>						m_fences;
    791 
    792 	std::vector<vk::VkSwapchainCreateInfoKHR>		m_swapchainConfigs;
    793 	size_t											m_swapchainConfigNdx;
    794 
    795 	const size_t									m_frameCount;
    796 	size_t											m_frameNdx;
    797 
    798 	const size_t									m_maxOutOfDateCount;
    799 	size_t											m_outOfDateCount;
    800 
    801 	void											initSwapchainResources		(void);
    802 	void											deinitSwapchainResources	(void);
    803 	void											render						(void);
    804 };
    805 
    806 std::vector<vk::VkSwapchainCreateInfoKHR> generateSwapchainConfigs (vk::VkSurfaceKHR						surface,
    807 																	deUint32								queueFamilyIndex,
    808 																	Scaling									scaling,
    809 																	const vk::VkSurfaceCapabilitiesKHR&		properties,
    810 																	const vector<vk::VkSurfaceFormatKHR>&	formats,
    811 																	const vector<vk::VkPresentModeKHR>&		presentModes,
    812 																	vk::VkPresentModeKHR					presentMode,
    813 																	vk::VkImageUsageFlags					supportedImageUsage)
    814 {
    815 	const deUint32							imageLayers			= 1u;
    816 	const vk::VkImageUsageFlags				imageUsage			= properties.supportedUsageFlags & supportedImageUsage;
    817 	const vk::VkBool32						clipped				= VK_FALSE;
    818 	vector<vk::VkSwapchainCreateInfoKHR>	createInfos;
    819 
    820 	const deUint32				imageWidth		= scaling == SCALING_NONE
    821 												? (properties.currentExtent.width != 0xFFFFFFFFu
    822 													? properties.currentExtent.width
    823 													: de::min(1024u, properties.minImageExtent.width + ((properties.maxImageExtent.width - properties.minImageExtent.width) / 2)))
    824 												: (scaling == SCALING_UP
    825 													? de::max(31u, properties.minImageExtent.width)
    826 													: properties.maxImageExtent.width);
    827 	const deUint32				imageHeight		= scaling == SCALING_NONE
    828 												? (properties.currentExtent.height != 0xFFFFFFFFu
    829 													? properties.currentExtent.height
    830 													: de::min(1024u, properties.minImageExtent.height + ((properties.maxImageExtent.height - properties.minImageExtent.height) / 2)))
    831 												: (scaling == SCALING_UP
    832 													? de::max(31u, properties.minImageExtent.height)
    833 													: properties.maxImageExtent.height);
    834 	const vk::VkExtent2D		imageSize		= { imageWidth, imageHeight };
    835 
    836 	{
    837 		size_t presentModeNdx;
    838 
    839 		for (presentModeNdx = 0; presentModeNdx < presentModes.size(); presentModeNdx++)
    840 		{
    841 			if (presentModes[presentModeNdx] == presentMode)
    842 				break;
    843 		}
    844 
    845 		if (presentModeNdx == presentModes.size())
    846 			TCU_THROW(NotSupportedError, "Present mode not supported");
    847 	}
    848 
    849 	for (size_t formatNdx = 0; formatNdx < formats.size(); formatNdx++)
    850 	{
    851 		for (vk::VkSurfaceTransformFlagsKHR transform = 1u; transform <= properties.supportedTransforms; transform = transform << 1u)
    852 		{
    853 			if ((properties.supportedTransforms & transform) == 0)
    854 				continue;
    855 
    856 			for (vk::VkCompositeAlphaFlagsKHR alpha = 1u; alpha <= properties.supportedCompositeAlpha; alpha = alpha << 1u)
    857 			{
    858 				if ((alpha & properties.supportedCompositeAlpha) == 0)
    859 					continue;
    860 
    861 				const vk::VkSurfaceTransformFlagBitsKHR	preTransform	= (vk::VkSurfaceTransformFlagBitsKHR)transform;
    862 				const vk::VkCompositeAlphaFlagBitsKHR	compositeAlpha	= (vk::VkCompositeAlphaFlagBitsKHR)alpha;
    863 				const vk::VkFormat						imageFormat		= formats[formatNdx].format;
    864 				const vk::VkColorSpaceKHR				imageColorSpace	= formats[formatNdx].colorSpace;
    865 				const vk::VkSwapchainCreateInfoKHR		createInfo		=
    866 				{
    867 					vk::VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
    868 					DE_NULL,
    869 					0u,
    870 					surface,
    871 					1,														// Always 1 image for a shared presentable image swapchain.
    872 					imageFormat,
    873 					imageColorSpace,
    874 					imageSize,
    875 					imageLayers,
    876 					imageUsage,
    877 					vk::VK_SHARING_MODE_EXCLUSIVE,
    878 					1u,
    879 					&queueFamilyIndex,
    880 					preTransform,
    881 					compositeAlpha,
    882 					presentMode,
    883 					clipped,
    884 					(vk::VkSwapchainKHR)0
    885 				};
    886 
    887 				createInfos.push_back(createInfo);
    888 			}
    889 		}
    890 	}
    891 
    892 	return createInfos;
    893 }
    894 
    895 vk::VkSurfaceCapabilitiesKHR getPhysicalDeviceSurfaceCapabilities (const vk::InstanceInterface&	vki,
    896 																   vk::VkPhysicalDevice			physicalDevice,
    897 																   vk::VkSurfaceKHR				surface,
    898 																   vk::VkImageUsageFlags*		usage)
    899 {
    900 	const vk::VkPhysicalDeviceSurfaceInfo2KHR	info	=
    901 	{
    902 		vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SURFACE_INFO_2_KHR,
    903 		DE_NULL,
    904 
    905 		surface
    906 	};
    907 	vk::VkSharedPresentSurfaceCapabilitiesKHR	sharedCapabilities;
    908 	vk::VkSurfaceCapabilities2KHR				capabilities;
    909 
    910 	sharedCapabilities.sType	= vk::VK_STRUCTURE_TYPE_SHARED_PRESENT_SURFACE_CAPABILITIES_KHR;
    911 	sharedCapabilities.pNext	= DE_NULL;
    912 
    913 	capabilities.sType			= vk::VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR,
    914 	capabilities.pNext			= &sharedCapabilities;
    915 
    916 	VK_CHECK(vki.getPhysicalDeviceSurfaceCapabilities2KHR(physicalDevice, &info, &capabilities));
    917 
    918 	TCU_CHECK(sharedCapabilities.sharedPresentSupportedUsageFlags & vk::VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT);
    919 	*usage = sharedCapabilities.sharedPresentSupportedUsageFlags;
    920 
    921 	return capabilities.surfaceCapabilities;
    922 }
    923 
    924 SharedPresentableImageTestInstance::SharedPresentableImageTestInstance (Context& context, const TestConfig& testConfig)
    925 	: TestInstance				(context)
    926 	, m_testConfig				(testConfig)
    927 	, m_quadCount				(16u)
    928 	, m_vkp						(context.getPlatformInterface())
    929 	, m_instanceExtensions		(vk::enumerateInstanceExtensionProperties(m_vkp, DE_NULL))
    930 	, m_instance				(createInstanceWithWsi(m_vkp, context.getUsedApiVersion(), m_instanceExtensions, testConfig.wsiType))
    931 	, m_vki						(m_vkp, *m_instance)
    932 	, m_physicalDevice			(vk::chooseDevice(m_vki, *m_instance, context.getTestContext().getCommandLine()))
    933 	, m_nativeDisplay			(createDisplay(context.getTestContext().getPlatform().getVulkanPlatform(), m_instanceExtensions, testConfig.wsiType))
    934 	, m_nativeWindow			(createWindow(*m_nativeDisplay, tcu::nothing<UVec2>()))
    935 	, m_surface					(vk::wsi::createSurface(m_vki, *m_instance, testConfig.wsiType, *m_nativeDisplay, *m_nativeWindow))
    936 
    937 	, m_queueFamilyIndex		(chooseQueueFamilyIndex(m_vki, m_physicalDevice, *m_surface))
    938 	, m_deviceExtensions		(vk::enumerateDeviceExtensionProperties(m_vki, m_physicalDevice, DE_NULL))
    939 	, m_device					(createDeviceWithWsi(m_vki, m_physicalDevice, m_deviceExtensions, m_queueFamilyIndex, testConfig.useSharedPresentableImage))
    940 	, m_vkd						(m_vki, *m_device)
    941 	, m_queue					(getDeviceQueue(m_vkd, *m_device, m_queueFamilyIndex, 0u))
    942 
    943 	, m_commandPool				(createCommandPool(m_vkd, *m_device, m_queueFamilyIndex))
    944 	, m_vertexShaderModule		(vk::createShaderModule(m_vkd, *m_device, context.getBinaryCollection().get("quad-vert"), 0u))
    945 	, m_fragmentShaderModule	(vk::createShaderModule(m_vkd, *m_device, context.getBinaryCollection().get("quad-frag"), 0u))
    946 	, m_pipelineLayout			(createPipelineLayout(m_vkd, *m_device))
    947 
    948 	, m_supportedUsageFlags		(0u)
    949 	, m_surfaceProperties		(getPhysicalDeviceSurfaceCapabilities(m_vki, m_physicalDevice, *m_surface, &m_supportedUsageFlags))
    950 	, m_surfaceFormats			(vk::wsi::getPhysicalDeviceSurfaceFormats(m_vki, m_physicalDevice, *m_surface))
    951 	, m_presentModes			(vk::wsi::getPhysicalDeviceSurfacePresentModes(m_vki, m_physicalDevice, *m_surface))
    952 
    953 	, m_swapchainConfigs		(generateSwapchainConfigs(*m_surface, m_queueFamilyIndex, testConfig.scaling, m_surfaceProperties, m_surfaceFormats, m_presentModes, testConfig.presentMode, m_supportedUsageFlags))
    954 	, m_swapchainConfigNdx		(0u)
    955 
    956 	, m_frameCount				(60u * 5u)
    957 	, m_frameNdx				(0u)
    958 
    959 	, m_maxOutOfDateCount		(20u)
    960 	, m_outOfDateCount			(0u)
    961 {
    962 	{
    963 		const tcu::ScopedLogSection surfaceInfo (m_context.getTestContext().getLog(), "SurfaceCapabilities", "SurfaceCapabilities");
    964 		m_context.getTestContext().getLog() << TestLog::Message << m_surfaceProperties << TestLog::EndMessage;
    965 		m_context.getTestContext().getLog() << TestLog::Message << "SharedPresentSupportedUsageFlags: " << m_supportedUsageFlags << TestLog::EndMessage;
    966 
    967 	}
    968 }
    969 
    970 SharedPresentableImageTestInstance::~SharedPresentableImageTestInstance (void)
    971 {
    972 	deinitSwapchainResources();
    973 }
    974 
    975 void SharedPresentableImageTestInstance::initSwapchainResources (void)
    976 {
    977 	const size_t		fenceCount	= 6;
    978 	const deUint32		imageWidth	= m_swapchainConfigs[m_swapchainConfigNdx].imageExtent.width;
    979 	const deUint32		imageHeight	= m_swapchainConfigs[m_swapchainConfigNdx].imageExtent.height;
    980 	const vk::VkFormat	imageFormat	= m_swapchainConfigs[m_swapchainConfigNdx].imageFormat;
    981 
    982 	m_swapchain				= vk::createSwapchainKHR(m_vkd, *m_device, &m_swapchainConfigs[m_swapchainConfigNdx]);
    983 	m_swapchainImage		= vk::wsi::getSwapchainImages(m_vkd, *m_device, *m_swapchain).front();
    984 
    985 	m_renderPass			= createRenderPass(m_vkd, *m_device, imageFormat);
    986 	m_pipeline				= createPipeline(m_vkd, *m_device, *m_renderPass, *m_pipelineLayout, *m_vertexShaderModule, *m_fragmentShaderModule, imageWidth, imageHeight);
    987 
    988 	m_swapchainImageView	= createImageView(m_vkd, *m_device, m_swapchainImage, imageFormat);
    989 	m_framebuffer			= createFramebuffer(m_vkd, *m_device, *m_renderPass, *m_swapchainImageView, imageWidth, imageHeight);
    990 
    991 	m_renderSemaphores		= std::vector<vk::VkSemaphore>(fenceCount, (vk::VkSemaphore)0);
    992 	m_fences				= std::vector<vk::VkFence>(fenceCount, (vk::VkFence)0);
    993 	m_commandBuffers		= std::vector<vk::VkCommandBuffer>(m_fences.size(), (vk::VkCommandBuffer)0);
    994 
    995 	initSemaphores(m_vkd, *m_device, m_renderSemaphores);
    996 
    997 	initFences(m_vkd, *m_device, m_fences);
    998 
    999 	// Unlike a traditional swapchain, where we'd acquire a new image from the
   1000 	// PE every frame, a shared image swapchain has a single image that is
   1001 	// acquired upfront. We acquire it here, transition it to the proper layout,
   1002 	// and present it.
   1003 
   1004 	// Acquire the one image
   1005 	const deUint64				foreverNs		= 0xFFFFFFFFFFFFFFFFul;
   1006 	vk::Move<vk::VkSemaphore>	semaphore(createSemaphore(m_vkd, *m_device));
   1007 	deUint32					imageIndex		= 42;	// initialize to junk value
   1008 
   1009 	VK_CHECK(m_vkd.acquireNextImageKHR(*m_device, *m_swapchain, foreverNs, *semaphore, 0u, &imageIndex));
   1010 	TCU_CHECK(imageIndex == 0);
   1011 
   1012 	// Transition to IMAGE_LAYOUT_SHARED_PRESENT_KHR
   1013 	const vk::VkCommandBufferAllocateInfo allocateInfo =
   1014 	{
   1015 		vk::VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
   1016 		DE_NULL,
   1017 		*m_commandPool,
   1018 		vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY,
   1019 		1
   1020 	};
   1021 	const vk::VkCommandBufferBeginInfo	beginInfo		=
   1022 	{
   1023 		vk::VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
   1024 		DE_NULL,
   1025 		0u,
   1026 		DE_NULL
   1027 	};
   1028 
   1029 	const vk::Unique<vk::VkCommandBuffer>	commandBuffer	(vk::allocateCommandBuffer(m_vkd, *m_device, &allocateInfo));
   1030 	VK_CHECK(m_vkd.beginCommandBuffer(*commandBuffer, &beginInfo));
   1031 
   1032 	const vk::VkImageMemoryBarrier barrier = {
   1033 		vk::VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
   1034 		DE_NULL,
   1035 		0,
   1036 		0,
   1037 		vk::VK_IMAGE_LAYOUT_UNDEFINED,
   1038 		vk::VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR,
   1039 		VK_QUEUE_FAMILY_IGNORED,
   1040 		VK_QUEUE_FAMILY_IGNORED,
   1041 		m_swapchainImage,
   1042 		{
   1043 			vk::VK_IMAGE_ASPECT_COLOR_BIT,
   1044 			0,
   1045 			1,
   1046 			0,
   1047 			1
   1048 		},
   1049 	};
   1050 
   1051 	m_vkd.cmdPipelineBarrier(*commandBuffer,
   1052 							vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
   1053 							vk::VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
   1054 							0u,
   1055 							0, DE_NULL,
   1056 							0, DE_NULL,
   1057 							1, &barrier);
   1058 
   1059 	VK_CHECK(m_vkd.endCommandBuffer(*commandBuffer));
   1060 
   1061 	const vk::VkPipelineStageFlags waitDstStages[] = { vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT };
   1062 	const vk::VkSubmitInfo submitInfo =
   1063 	{
   1064 		vk::VK_STRUCTURE_TYPE_SUBMIT_INFO,
   1065 		DE_NULL,
   1066 		1, &*semaphore, waitDstStages,
   1067 		1, &*commandBuffer,
   1068 		0, DE_NULL,
   1069 	};
   1070 
   1071 	VK_CHECK(m_vkd.queueSubmit(m_queue, 1u, &submitInfo, (vk::VkFence)0));
   1072 	VK_CHECK(m_vkd.queueWaitIdle(m_queue));
   1073 }
   1074 
   1075 void SharedPresentableImageTestInstance::deinitSwapchainResources (void)
   1076 {
   1077 	VK_CHECK(m_vkd.queueWaitIdle(m_queue));
   1078 
   1079 	deinitSemaphores(m_vkd, *m_device, m_renderSemaphores);
   1080 	deinitFences(m_vkd, *m_device, m_fences);
   1081 	deinitCommandBuffers(m_vkd, *m_device, *m_commandPool, m_commandBuffers);
   1082 
   1083 	m_framebuffer	= vk::Move<vk::VkFramebuffer>();
   1084 	m_swapchainImageView = vk::Move<vk::VkImageView>();
   1085 	m_swapchainImage = (vk::VkImage)0;
   1086 
   1087 	m_swapchain		= vk::Move<vk::VkSwapchainKHR>();
   1088 	m_renderPass	= vk::Move<vk::VkRenderPass>();
   1089 	m_pipeline		= vk::Move<vk::VkPipeline>();
   1090 }
   1091 
   1092 void SharedPresentableImageTestInstance::render (void)
   1093 {
   1094 	const deUint64		foreverNs		= 0xFFFFFFFFFFFFFFFFul;
   1095 	const vk::VkFence	fence			= m_fences[m_frameNdx % m_fences.size()];
   1096 	const deUint32		width			= m_swapchainConfigs[m_swapchainConfigNdx].imageExtent.width;
   1097 	const deUint32		height			= m_swapchainConfigs[m_swapchainConfigNdx].imageExtent.height;
   1098 
   1099 	// Throttle execution
   1100 	if (m_frameNdx >= m_fences.size())
   1101 	{
   1102 		VK_CHECK(m_vkd.waitForFences(*m_device, 1u, &fence, VK_TRUE, foreverNs));
   1103 		VK_CHECK(m_vkd.resetFences(*m_device, 1u, &fence));
   1104 
   1105 		m_vkd.freeCommandBuffers(*m_device, *m_commandPool, 1u, &m_commandBuffers[m_frameNdx % m_commandBuffers.size()]);
   1106 		m_commandBuffers[m_frameNdx % m_commandBuffers.size()] = (vk::VkCommandBuffer)0;
   1107 	}
   1108 
   1109 	deUint32			imageIndex = 0;		// There is only one image.
   1110 	const vk::VkSemaphore currentRenderSemaphore = m_renderSemaphores[m_frameNdx % m_renderSemaphores.size()];
   1111 
   1112 	const bool willPresent = m_swapchainConfigs[m_swapchainConfigNdx].presentMode == vk::VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR || !m_frameNdx;
   1113 
   1114 	// Create command buffer
   1115 	m_commandBuffers[m_frameNdx % m_commandBuffers.size()] = createCommandBuffer(m_vkd, *m_device, *m_commandPool, *m_pipelineLayout, *m_renderPass, *m_framebuffer, *m_pipeline, m_frameNdx, m_quadCount, width, height).disown();
   1116 
   1117 	// Submit command buffer
   1118 	{
   1119 		const vk::VkSubmitInfo			submitInfo		=
   1120 		{
   1121 			vk::VK_STRUCTURE_TYPE_SUBMIT_INFO,
   1122 			DE_NULL,
   1123 			0u,
   1124 			DE_NULL,
   1125 			DE_NULL,
   1126 			1u,
   1127 			&m_commandBuffers[m_frameNdx % m_commandBuffers.size()],
   1128 			willPresent ? 1u : 0u,	  // Only signal the semaphore if we're going to call QueuePresent.
   1129 			&currentRenderSemaphore
   1130 		};
   1131 
   1132 		// With a traditional swapchain, we'd fence on completion of
   1133 		// AcquireNextImage. We never call that for a shared image swapchain, so
   1134 		// fence on completion of the rendering work instead. A real shared
   1135 		// image application would want a more substantial pacing mechanism.
   1136 		VK_CHECK(m_vkd.queueSubmit(m_queue, 1u, &submitInfo, fence));
   1137 	}
   1138 
   1139 	// DEMAND_REFRESH requires us to call QueuePresent whenever we want to be
   1140 	// assured the PE has picked up a new frame. The PE /may/ also pick up
   1141 	// changes whenever it likes.
   1142 	//
   1143 	// For CONTINUOUS_REFRESH, we need to just call QueuePresent once on the
   1144 	// first frame to kick things off.
   1145 	if (willPresent)
   1146 	{
   1147 
   1148 		// Present frame
   1149 		vk::VkResult result;
   1150 		const vk::VkPresentInfoKHR presentInfo =
   1151 		{
   1152 			vk::VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
   1153 			DE_NULL,
   1154 			1u,
   1155 			&currentRenderSemaphore,
   1156 			1u,
   1157 			&*m_swapchain,
   1158 			&imageIndex,
   1159 			&result
   1160 		};
   1161 
   1162 		VK_CHECK(m_vkd.queuePresentKHR(m_queue, &presentInfo));
   1163 		VK_CHECK(result);
   1164 
   1165 	}
   1166 
   1167 	// With either present mode, we can call GetSwapchainStatus at any time
   1168 	// to detect possible OUT_OF_DATE conditions. Let's do that every frame.
   1169 
   1170 	const vk::VkResult swapchainStatus = m_vkd.getSwapchainStatusKHR(*m_device, *m_swapchain);
   1171 	VK_CHECK(swapchainStatus);
   1172 }
   1173 
   1174 tcu::TestStatus SharedPresentableImageTestInstance::iterate (void)
   1175 {
   1176 	// Initialize swapchain specific resources
   1177 	// Render test
   1178 	try
   1179 	{
   1180 		if (m_frameNdx == 0)
   1181 		{
   1182 			if (m_outOfDateCount == 0)
   1183 				m_context.getTestContext().getLog() << tcu::TestLog::Message << "Swapchain: " << m_swapchainConfigs[m_swapchainConfigNdx] << tcu::TestLog::EndMessage;
   1184 
   1185 			initSwapchainResources();
   1186 		}
   1187 
   1188 		render();
   1189 	}
   1190 	catch (const vk::Error& error)
   1191 	{
   1192 		if (error.getError() == vk::VK_ERROR_OUT_OF_DATE_KHR)
   1193 		{
   1194 			m_swapchainConfigs = generateSwapchainConfigs(*m_surface, m_queueFamilyIndex, m_testConfig.scaling, m_surfaceProperties, m_surfaceFormats, m_presentModes, m_testConfig.presentMode, m_supportedUsageFlags);
   1195 
   1196 			if (m_outOfDateCount < m_maxOutOfDateCount)
   1197 			{
   1198 				m_context.getTestContext().getLog() << TestLog::Message << "Frame " << m_frameNdx << ": Swapchain out of date. Recreating resources." << TestLog::EndMessage;
   1199 				deinitSwapchainResources();
   1200 				m_frameNdx = 0;
   1201 				m_outOfDateCount++;
   1202 
   1203 				return tcu::TestStatus::incomplete();
   1204 			}
   1205 			else
   1206 			{
   1207 				m_context.getTestContext().getLog() << TestLog::Message << "Frame " << m_frameNdx << ": Swapchain out of date." << TestLog::EndMessage;
   1208 				m_resultCollector.fail("Received too many VK_ERROR_OUT_OF_DATE_KHR errors. Received " + de::toString(m_outOfDateCount) + ", max " + de::toString(m_maxOutOfDateCount));
   1209 			}
   1210 		}
   1211 		else
   1212 		{
   1213 			m_resultCollector.fail(error.what());
   1214 		}
   1215 
   1216 		deinitSwapchainResources();
   1217 
   1218 		m_swapchainConfigNdx++;
   1219 		m_frameNdx = 0;
   1220 		m_outOfDateCount = 0;
   1221 
   1222 		if (m_swapchainConfigNdx >= m_swapchainConfigs.size())
   1223 			return tcu::TestStatus(m_resultCollector.getResult(), m_resultCollector.getMessage());
   1224 		else
   1225 			return tcu::TestStatus::incomplete();
   1226 	}
   1227 
   1228 	m_frameNdx++;
   1229 
   1230 	if (m_frameNdx >= m_frameCount)
   1231 	{
   1232 		m_frameNdx = 0;
   1233 		m_outOfDateCount = 0;
   1234 		m_swapchainConfigNdx++;
   1235 
   1236 		deinitSwapchainResources();
   1237 
   1238 		if (m_swapchainConfigNdx >= m_swapchainConfigs.size())
   1239 			return tcu::TestStatus(m_resultCollector.getResult(), m_resultCollector.getMessage());
   1240 		else
   1241 			return tcu::TestStatus::incomplete();
   1242 	}
   1243 	else
   1244 		return tcu::TestStatus::incomplete();
   1245 }
   1246 
   1247 struct Programs
   1248 {
   1249 	static void init (vk::SourceCollections& dst, TestConfig)
   1250 	{
   1251 		dst.glslSources.add("quad-vert") << glu::VertexSource(
   1252 			"#version 450\n"
   1253 			"out gl_PerVertex {\n"
   1254 			"\tvec4 gl_Position;\n"
   1255 			"};\n"
   1256 			"layout(location = 0) out highp uint quadIndex;\n"
   1257 			"highp float;\n"
   1258 			"void main (void) {\n"
   1259 			"\tgl_Position = vec4(((gl_VertexIndex + 2) / 3) % 2 == 0 ? -1.0 : 1.0,\n"
   1260 			"\t                   ((gl_VertexIndex + 1) / 3) % 2 == 0 ? -1.0 : 1.0, 0.0, 1.0);\n"
   1261 			"\tquadIndex = gl_VertexIndex / 6;\n"
   1262 			"}\n");
   1263 		dst.glslSources.add("quad-frag") << glu::FragmentSource(
   1264 			"#version 310 es\n"
   1265 			"layout(location = 0) flat in highp uint quadIndex;\n"
   1266 			"layout(location = 0) out highp vec4 o_color;\n"
   1267 			"layout(push_constant) uniform PushConstant {\n"
   1268 			"\thighp uint frameNdx;\n"
   1269 			"} pushConstants;\n"
   1270 			"void main (void)\n"
   1271 			"{\n"
   1272 			"\thighp uint frameNdx = pushConstants.frameNdx;\n"
   1273 			"\thighp uint cellX = bitfieldExtract(uint(gl_FragCoord.x), 7, 10);\n"
   1274 			"\thighp uint cellY = bitfieldExtract(uint(gl_FragCoord.y), 7, 10);\n"
   1275 			"\thighp uint x = quadIndex ^ (frameNdx + (uint(gl_FragCoord.x) >> cellX));\n"
   1276 			"\thighp uint y = quadIndex ^ (frameNdx + (uint(gl_FragCoord.y) >> cellY));\n"
   1277 			"\thighp uint r = 128u * bitfieldExtract(x, 0, 1)\n"
   1278 			"\t             +  64u * bitfieldExtract(y, 1, 1)\n"
   1279 			"\t             +  32u * bitfieldExtract(x, 3, 1);\n"
   1280 			"\thighp uint g = 128u * bitfieldExtract(y, 0, 1)\n"
   1281 			"\t             +  64u * bitfieldExtract(x, 2, 1)\n"
   1282 			"\t             +  32u * bitfieldExtract(y, 3, 1);\n"
   1283 			"\thighp uint b = 128u * bitfieldExtract(x, 1, 1)\n"
   1284 			"\t             +  64u * bitfieldExtract(y, 2, 1)\n"
   1285 			"\t             +  32u * bitfieldExtract(x, 4, 1);\n"
   1286 			"\to_color = vec4(float(r) / 255.0, float(g) / 255.0, float(b) / 255.0, 1.0);\n"
   1287 			"}\n");
   1288 	}
   1289 };
   1290 
   1291 } // anonymous
   1292 
   1293 void createSharedPresentableImageTests (tcu::TestCaseGroup* testGroup, vk::wsi::Type wsiType)
   1294 {
   1295 	const struct
   1296 	{
   1297 		Scaling		scaling;
   1298 		const char*	name;
   1299 	} scaling [] =
   1300 	{
   1301 		{ SCALING_NONE,	"scale_none"	},
   1302 		{ SCALING_UP,	"scale_up"		},
   1303 		{ SCALING_DOWN, "scale_down"	}
   1304 	};
   1305 	const struct
   1306 	{
   1307 		vk::VkPresentModeKHR	mode;
   1308 		const char*				name;
   1309 	} presentModes[] =
   1310 	{
   1311 		{ vk::VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR,			"demand"			},
   1312 		{ vk::VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR,		"continuous"		},
   1313 	};
   1314 
   1315 	for (size_t scalingNdx = 0; scalingNdx < DE_LENGTH_OF_ARRAY(scaling); scalingNdx++)
   1316 	{
   1317 		if (scaling[scalingNdx].scaling == SCALING_NONE || wsiTypeSupportsScaling(wsiType))
   1318 		{
   1319 			de::MovePtr<tcu::TestCaseGroup>	scaleGroup	(new tcu::TestCaseGroup(testGroup->getTestContext(), scaling[scalingNdx].name, scaling[scalingNdx].name));
   1320 
   1321 			for (size_t presentModeNdx = 0; presentModeNdx < DE_LENGTH_OF_ARRAY(presentModes); presentModeNdx++)
   1322 			{
   1323 
   1324 				const char* const				name		= presentModes[presentModeNdx].name;
   1325 				TestConfig						config;
   1326 
   1327 				config.wsiType					= wsiType;
   1328 				config.useSharedPresentableImage= true;
   1329 				config.scaling					= scaling[scalingNdx].scaling;
   1330 				config.presentMode				= presentModes[presentModeNdx].mode;
   1331 
   1332 				scaleGroup->addChild(new vkt::InstanceFactory1<SharedPresentableImageTestInstance, TestConfig, Programs>(testGroup->getTestContext(), tcu::NODETYPE_SELF_VALIDATE, name, name, Programs(), config));
   1333 			}
   1334 
   1335 			testGroup->addChild(scaleGroup.release());
   1336 		}
   1337 	}
   1338 }
   1339 
   1340 } // wsi
   1341 } // vkt
   1342