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