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