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