1 /*-------------------------------------------------------------------------
2  * Vulkan CTS Framework
3  * --------------------
4  *
5  * Copyright (c) 2016 Google Inc.
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  *//*!
20  * \file
21  * \brief Windowing System Integration (WSI) Utilities.
22  *//*--------------------------------------------------------------------*/
23 
24 #include "vkRefUtil.hpp"
25 #include "vkTypeUtil.hpp"
26 #include "vkObjUtil.hpp"
27 #include "vkCmdUtil.hpp"
28 #include "vkQueryUtil.hpp"
29 #include "vkWsiUtil.hpp"
30 #include "vkBarrierUtil.hpp"
31 
32 #include "deArrayUtil.hpp"
33 #include "deMemory.h"
34 
35 #include <limits>
36 #include <vector>
37 
38 using std::vector;
39 
40 #if defined (DEQP_SUPPORT_X11)
41 #	include <X11/Xlib.h>
42 #	if defined (DEQP_SUPPORT_XCB)
43 #		include <xcb/xcb.h>
44 #	endif // DEQP_SUPPORT_XCB
45 #endif // DEQP_SUPPORT_X11
46 
47 #if defined (DEQP_SUPPORT_WAYLAND)
48 #	include "tcuLnxWayland.hpp"
49 #	define WAYLAND_DISPLAY DE_NULL
50 #endif // DEQP_SUPPORT_WAYLAND
51 
52 #if ( DE_OS == DE_OS_WIN32 )
53 	#define NOMINMAX
54 	#define WIN32_LEAN_AND_MEAN
55 	#include <windows.h>
56 #endif
57 
58 namespace vk
59 {
60 namespace wsi
61 {
62 
63 //! Get canonical WSI name that should be used for example in test case and group names.
getName(Type wsiType)64 const char* getName (Type wsiType)
65 {
66 	static const char* const s_names[] =
67 	{
68 		"xlib",
69 		"xcb",
70 		"wayland",
71 		"android",
72 		"win32",
73 		"macos",
74 		"headless"
75 	};
76 	return de::getSizedArrayElement<TYPE_LAST>(s_names, wsiType);
77 }
78 
getExtensionName(Type wsiType)79 const char* getExtensionName (Type wsiType)
80 {
81 	static const char* const s_extNames[] =
82 	{
83 		"VK_KHR_xlib_surface",
84 		"VK_KHR_xcb_surface",
85 		"VK_KHR_wayland_surface",
86 		"VK_KHR_android_surface",
87 		"VK_KHR_win32_surface",
88 		"VK_MVK_macos_surface",
89 		"VK_EXT_headless_surface"
90 	};
91 	return de::getSizedArrayElement<TYPE_LAST>(s_extNames, wsiType);
92 }
93 
getPlatformProperties(Type wsiType)94 const PlatformProperties& getPlatformProperties (Type wsiType)
95 {
96 	// \note These are declared here (rather than queried through vk::Platform for example)
97 	//		 on purpose. The behavior of a platform is partly defined by the platform spec,
98 	//		 and partly by WSI extensions, and platform ports should not need to override
99 	//		 that definition.
100 
101 	const deUint32	noDisplayLimit	= std::numeric_limits<deUint32>::max();
102 	const deUint32	noWindowLimit	= std::numeric_limits<deUint32>::max();
103 
104 	static const PlatformProperties s_properties[] =
105 	{
106 		// VK_KHR_xlib_surface
107 		{
108 			PlatformProperties::FEATURE_INITIAL_WINDOW_SIZE|PlatformProperties::FEATURE_RESIZE_WINDOW,
109 			PlatformProperties::SWAPCHAIN_EXTENT_MUST_MATCH_WINDOW_SIZE,
110 			noDisplayLimit,
111 			noWindowLimit,
112 		},
113 		// VK_KHR_xcb_surface
114 		{
115 			PlatformProperties::FEATURE_INITIAL_WINDOW_SIZE|PlatformProperties::FEATURE_RESIZE_WINDOW,
116 			PlatformProperties::SWAPCHAIN_EXTENT_MUST_MATCH_WINDOW_SIZE,
117 			noDisplayLimit,
118 			noWindowLimit,
119 		},
120 		// VK_KHR_wayland_surface
121 		{
122 			0u,
123 			PlatformProperties::SWAPCHAIN_EXTENT_SETS_WINDOW_SIZE,
124 			noDisplayLimit,
125 			noWindowLimit,
126 		},
127 		// VK_KHR_android_surface
128 		{
129 			PlatformProperties::FEATURE_INITIAL_WINDOW_SIZE,
130 			PlatformProperties::SWAPCHAIN_EXTENT_SCALED_TO_WINDOW_SIZE,
131 			1u,
132 			1u, // Only one window available
133 		},
134 		// VK_KHR_win32_surface
135 		{
136 			PlatformProperties::FEATURE_INITIAL_WINDOW_SIZE|PlatformProperties::FEATURE_RESIZE_WINDOW,
137 			PlatformProperties::SWAPCHAIN_EXTENT_MUST_MATCH_WINDOW_SIZE,
138 			noDisplayLimit,
139 			noWindowLimit,
140 		},
141 		// VK_MVK_macos_surface
142 		{
143 			PlatformProperties::FEATURE_INITIAL_WINDOW_SIZE|PlatformProperties::FEATURE_RESIZE_WINDOW,
144 			PlatformProperties::SWAPCHAIN_EXTENT_MUST_MATCH_WINDOW_SIZE,
145 			noDisplayLimit,
146 			noWindowLimit,
147 		},
148 		// VK_EXT_headless_surface
149 		{
150 			0u,
151 			PlatformProperties::SWAPCHAIN_EXTENT_SETS_WINDOW_SIZE,
152 			noDisplayLimit,
153 			noWindowLimit,
154 		},
155 	};
156 
157 	return de::getSizedArrayElement<TYPE_LAST>(s_properties, wsiType);
158 }
159 
createSurface(const InstanceInterface & vki,VkInstance instance,Type wsiType,const Display & nativeDisplay,const Window & nativeWindow,const VkAllocationCallbacks * pAllocator,VkSurfaceKHR * pSurface)160 VkResult createSurface (const InstanceInterface&		vki,
161 						VkInstance						instance,
162 						Type							wsiType,
163 						const Display&					nativeDisplay,
164 						const Window&					nativeWindow,
165 						const VkAllocationCallbacks*	pAllocator,
166 						VkSurfaceKHR*					pSurface)
167 {
168 	// Update this function if you add more WSI implementations
169 	DE_STATIC_ASSERT(TYPE_LAST == 7);
170 
171 	switch (wsiType)
172 	{
173 		case TYPE_XLIB:
174 		{
175 			const XlibDisplayInterface&			xlibDisplay		= dynamic_cast<const XlibDisplayInterface&>(nativeDisplay);
176 			const XlibWindowInterface&			xlibWindow		= dynamic_cast<const XlibWindowInterface&>(nativeWindow);
177 			const VkXlibSurfaceCreateInfoKHR	createInfo		=
178 			{
179 				VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR,
180 				DE_NULL,
181 				(VkXlibSurfaceCreateFlagsKHR)0,
182 				xlibDisplay.getNative(),
183 				xlibWindow.getNative()
184 			};
185 
186 			return vki.createXlibSurfaceKHR(instance, &createInfo, pAllocator, pSurface);
187 		}
188 
189 		case TYPE_XCB:
190 		{
191 			const XcbDisplayInterface&			xcbDisplay		= dynamic_cast<const XcbDisplayInterface&>(nativeDisplay);
192 			const XcbWindowInterface&			xcbWindow		= dynamic_cast<const XcbWindowInterface&>(nativeWindow);
193 			const VkXcbSurfaceCreateInfoKHR		createInfo		=
194 			{
195 				VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR,
196 				DE_NULL,
197 				(VkXcbSurfaceCreateFlagsKHR)0,
198 				xcbDisplay.getNative(),
199 				xcbWindow.getNative()
200 			};
201 
202 			return vki.createXcbSurfaceKHR(instance, &createInfo, pAllocator, pSurface);
203 		}
204 
205 		case TYPE_WAYLAND:
206 		{
207 			const WaylandDisplayInterface&		waylandDisplay	= dynamic_cast<const WaylandDisplayInterface&>(nativeDisplay);
208 			const WaylandWindowInterface&		waylandWindow	= dynamic_cast<const WaylandWindowInterface&>(nativeWindow);
209 			const VkWaylandSurfaceCreateInfoKHR	createInfo		=
210 			{
211 				VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR,
212 				DE_NULL,
213 				(VkWaylandSurfaceCreateFlagsKHR)0,
214 				waylandDisplay.getNative(),
215 				waylandWindow.getNative()
216 			};
217 
218 			return vki.createWaylandSurfaceKHR(instance, &createInfo, pAllocator, pSurface);
219 		}
220 
221 		case TYPE_ANDROID:
222 		{
223 			const AndroidWindowInterface&		androidWindow	= dynamic_cast<const AndroidWindowInterface&>(nativeWindow);
224 			const VkAndroidSurfaceCreateInfoKHR	createInfo		=
225 			{
226 				VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR,
227 				DE_NULL,
228 				(VkAndroidSurfaceCreateFlagsKHR)0,
229 				androidWindow.getNative()
230 			};
231 
232 			return vki.createAndroidSurfaceKHR(instance, &createInfo, pAllocator, pSurface);
233 		}
234 
235 		case TYPE_WIN32:
236 		{
237 			const Win32DisplayInterface&		win32Display	= dynamic_cast<const Win32DisplayInterface&>(nativeDisplay);
238 			const Win32WindowInterface&			win32Window		= dynamic_cast<const Win32WindowInterface&>(nativeWindow);
239 			const VkWin32SurfaceCreateInfoKHR	createInfo		=
240 			{
241 				VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR,
242 				DE_NULL,
243 				(VkWin32SurfaceCreateFlagsKHR)0,
244 				win32Display.getNative(),
245 				win32Window.getNative()
246 			};
247 
248 			return vki.createWin32SurfaceKHR(instance, &createInfo, pAllocator, pSurface);
249 		}
250 
251 		case TYPE_MACOS:
252 		{
253 			const MacOSWindowInterface&			macOSWindow		= dynamic_cast<const MacOSWindowInterface&>(nativeWindow);
254 			const VkMacOSSurfaceCreateInfoMVK	createInfo		=
255 			{
256 				VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK,
257 				DE_NULL,
258 				(VkMacOSSurfaceCreateFlagsMVK)0,
259 				macOSWindow.getNative()
260 			};
261 
262 			return vki.createMacOSSurfaceMVK(instance, &createInfo, pAllocator, pSurface);
263 		}
264 
265 		case TYPE_HEADLESS:
266 		{
267 			const VkHeadlessSurfaceCreateInfoEXT	createInfo		=
268 			{
269 				VK_STRUCTURE_TYPE_HEADLESS_SURFACE_CREATE_INFO_EXT,
270 				DE_NULL,
271 				(VkHeadlessSurfaceCreateFlagsEXT)0
272 			};
273 
274 			return vki.createHeadlessSurfaceEXT(instance, &createInfo, pAllocator, pSurface);
275 		}
276 
277 		default:
278 			DE_FATAL("Unknown WSI type");
279 			return VK_ERROR_SURFACE_LOST_KHR;
280 	}
281 }
282 
createSurface(const InstanceInterface & vki,VkInstance instance,Type wsiType,const Display & nativeDisplay,const Window & nativeWindow,const VkAllocationCallbacks * pAllocator)283 Move<VkSurfaceKHR> createSurface (const InstanceInterface&		vki,
284 								  VkInstance					instance,
285 								  Type							wsiType,
286 								  const Display&				nativeDisplay,
287 								  const Window&					nativeWindow,
288 								  const VkAllocationCallbacks*	pAllocator)
289 {
290 	VkSurfaceKHR object = 0;
291 	VK_CHECK(createSurface(vki, instance, wsiType, nativeDisplay, nativeWindow, pAllocator, &object));
292 	return Move<VkSurfaceKHR>(check<VkSurfaceKHR>(object), Deleter<VkSurfaceKHR>(vki, instance, pAllocator));
293 }
294 
getPhysicalDeviceSurfaceSupport(const InstanceInterface & vki,VkPhysicalDevice physicalDevice,deUint32 queueFamilyIndex,VkSurfaceKHR surface)295 VkBool32 getPhysicalDeviceSurfaceSupport (const InstanceInterface&	vki,
296 										  VkPhysicalDevice			physicalDevice,
297 										  deUint32					queueFamilyIndex,
298 										  VkSurfaceKHR				surface)
299 {
300 	VkBool32 result = 0;
301 
302 	VK_CHECK(vki.getPhysicalDeviceSurfaceSupportKHR(physicalDevice, queueFamilyIndex, surface, &result));
303 
304 	return result;
305 }
306 
getPhysicalDevicePresentationSupport(const InstanceInterface & vki,VkPhysicalDevice physicalDevice,deUint32 queueFamilyIndex,Type wsiType,const Display & nativeDisplay)307 VkBool32 getPhysicalDevicePresentationSupport (const InstanceInterface&	vki,
308 											   VkPhysicalDevice			physicalDevice,
309 											   deUint32					queueFamilyIndex,
310 											   Type						wsiType,
311 											   const Display&			nativeDisplay)
312 {
313 	switch (wsiType)
314 	{
315 		case TYPE_XLIB:
316 		{
317 			const XlibDisplayInterface&		xlibDisplay	= dynamic_cast<const XlibDisplayInterface&>(nativeDisplay);
318 			pt::XlibVisualID				visualID	(0U);
319 #if defined (DEQP_SUPPORT_X11)
320 			::Display*						displayPtr	= (::Display*)(xlibDisplay.getNative().internal);
321 			visualID.internal							= (deUint32)(::XDefaultVisual(displayPtr,0)->visualid);
322 #endif
323 			return vki.getPhysicalDeviceXlibPresentationSupportKHR(physicalDevice, queueFamilyIndex, xlibDisplay.getNative(), visualID);
324 		}
325 		case TYPE_XCB:
326 		{
327 			const XcbDisplayInterface&		xcbDisplay	= dynamic_cast<const XcbDisplayInterface&>(nativeDisplay);
328 			pt::XcbVisualid					visualID	(0U);
329 #if defined (DEQP_SUPPORT_XCB)
330 			xcb_connection_t*				connPtr		= (xcb_connection_t*)(xcbDisplay.getNative().internal);
331 			xcb_screen_t*					screen		= xcb_setup_roots_iterator(xcb_get_setup(connPtr)).data;
332 			visualID.internal							= (deUint32)(screen->root_visual);
333 #endif
334 			return vki.getPhysicalDeviceXcbPresentationSupportKHR(physicalDevice, queueFamilyIndex, xcbDisplay.getNative(), visualID);
335 		}
336 		case TYPE_WAYLAND:
337 		{
338 			const WaylandDisplayInterface&	waylandDisplay	= dynamic_cast<const WaylandDisplayInterface&>(nativeDisplay);
339 			return vki.getPhysicalDeviceWaylandPresentationSupportKHR(physicalDevice, queueFamilyIndex, waylandDisplay.getNative());
340 		}
341 		case TYPE_WIN32:
342 		{
343 			return vki.getPhysicalDeviceWin32PresentationSupportKHR(physicalDevice, queueFamilyIndex);
344 		}
345 		case TYPE_HEADLESS:
346 		case TYPE_ANDROID:
347 		case TYPE_MACOS:
348 		{
349 			return 1;
350 		}
351 		default:
352 			DE_FATAL("Unknown WSI type");
353 			return 0;
354 	}
355 	return 1;
356 }
357 
getPhysicalDeviceSurfaceCapabilities(const InstanceInterface & vki,VkPhysicalDevice physicalDevice,VkSurfaceKHR surface)358 VkSurfaceCapabilitiesKHR getPhysicalDeviceSurfaceCapabilities (const InstanceInterface&		vki,
359 															   VkPhysicalDevice				physicalDevice,
360 															   VkSurfaceKHR					surface)
361 {
362 	VkSurfaceCapabilitiesKHR capabilities;
363 
364 	deMemset(&capabilities, 0, sizeof(capabilities));
365 
366 	VK_CHECK(vki.getPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, surface, &capabilities));
367 
368 	return capabilities;
369 }
370 
getPhysicalDeviceSurfaceCapabilities2EXT(const InstanceInterface & vki,VkPhysicalDevice physicalDevice,VkSurfaceKHR surface)371 VkSurfaceCapabilities2EXT getPhysicalDeviceSurfaceCapabilities2EXT (const InstanceInterface&		vki,
372 																	VkPhysicalDevice				physicalDevice,
373 																	VkSurfaceKHR					surface)
374 {
375 	VkSurfaceCapabilities2EXT capabilities;
376 
377 	deMemset(&capabilities, 0, sizeof(capabilities));
378 	capabilities.sType = VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_EXT;
379 
380 	VK_CHECK(vki.getPhysicalDeviceSurfaceCapabilities2EXT(physicalDevice, surface, &capabilities));
381 
382 	return capabilities;
383 }
384 
sameSurfaceCapabilities(const VkSurfaceCapabilitiesKHR & khr,const VkSurfaceCapabilities2EXT & ext)385 bool sameSurfaceCapabilities (const VkSurfaceCapabilitiesKHR&	khr,
386 							  const VkSurfaceCapabilities2EXT&	ext)
387 {
388 	return (	khr.minImageCount			== ext.minImageCount &&
389 				khr.maxImageCount			== ext.maxImageCount &&
390 				khr.currentExtent.width		== ext.currentExtent.width &&
391 				khr.currentExtent.height	== ext.currentExtent.height &&
392 				khr.minImageExtent.width	== ext.minImageExtent.width &&
393 				khr.minImageExtent.height	== ext.minImageExtent.height &&
394 				khr.maxImageExtent.width	== ext.maxImageExtent.width &&
395 				khr.maxImageExtent.height	== ext.maxImageExtent.height &&
396 				khr.maxImageArrayLayers		== ext.maxImageArrayLayers &&
397 				khr.supportedTransforms		== ext.supportedTransforms &&
398 				khr.currentTransform		== ext.currentTransform &&
399 				khr.supportedCompositeAlpha	== ext.supportedCompositeAlpha &&
400 				khr.supportedUsageFlags		== ext.supportedUsageFlags	);
401 }
402 
getPhysicalDeviceSurfaceFormats(const InstanceInterface & vki,VkPhysicalDevice physicalDevice,VkSurfaceKHR surface)403 std::vector<VkSurfaceFormatKHR> getPhysicalDeviceSurfaceFormats (const InstanceInterface&		vki,
404 																 VkPhysicalDevice				physicalDevice,
405 																 VkSurfaceKHR					surface)
406 {
407 	deUint32	numFormats	= 0;
408 
409 	VK_CHECK(vki.getPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface, &numFormats, DE_NULL));
410 
411 	if (numFormats > 0)
412 	{
413 		std::vector<VkSurfaceFormatKHR>	formats	(numFormats);
414 
415 		VK_CHECK(vki.getPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface, &numFormats, &formats[0]));
416 
417 		return formats;
418 	}
419 	else
420 		return std::vector<VkSurfaceFormatKHR>();
421 }
422 
getPhysicalDeviceSurfacePresentModes(const InstanceInterface & vki,VkPhysicalDevice physicalDevice,VkSurfaceKHR surface)423 std::vector<VkPresentModeKHR> getPhysicalDeviceSurfacePresentModes (const InstanceInterface&		vki,
424 																	VkPhysicalDevice				physicalDevice,
425 																	VkSurfaceKHR					surface)
426 {
427 	deUint32	numModes	= 0;
428 
429 	VK_CHECK(vki.getPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface, &numModes, DE_NULL));
430 
431 	if (numModes > 0)
432 	{
433 		std::vector<VkPresentModeKHR>	modes	(numModes);
434 
435 		VK_CHECK(vki.getPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface, &numModes, &modes[0]));
436 
437 		return modes;
438 	}
439 	else
440 		return std::vector<VkPresentModeKHR>();
441 }
442 
getSwapchainImages(const DeviceInterface & vkd,VkDevice device,VkSwapchainKHR swapchain)443 std::vector<VkImage> getSwapchainImages (const DeviceInterface&			vkd,
444 										 VkDevice						device,
445 										 VkSwapchainKHR					swapchain)
446 {
447 	deUint32	numImages	= 0;
448 
449 	VK_CHECK(vkd.getSwapchainImagesKHR(device, swapchain, &numImages, DE_NULL));
450 
451 	if (numImages > 0)
452 	{
453 		std::vector<VkImage>	images	(numImages);
454 
455 		VK_CHECK(vkd.getSwapchainImagesKHR(device, swapchain, &numImages, &images[0]));
456 
457 		return images;
458 	}
459 	else
460 		return std::vector<VkImage>();
461 }
462 
463 namespace
464 {
465 
getSupportedQueueFamilyIndices(const InstanceInterface & vki,VkPhysicalDevice physicalDevice,VkSurfaceKHR surface)466 std::vector<deUint32> getSupportedQueueFamilyIndices (const InstanceInterface& vki, VkPhysicalDevice physicalDevice, VkSurfaceKHR surface)
467 {
468 	deUint32 numTotalFamilyIndices;
469 	vki.getPhysicalDeviceQueueFamilyProperties(physicalDevice, &numTotalFamilyIndices, DE_NULL);
470 
471 	std::vector<VkQueueFamilyProperties> queueFamilyProperties(numTotalFamilyIndices);
472 	vki.getPhysicalDeviceQueueFamilyProperties(physicalDevice, &numTotalFamilyIndices, &queueFamilyProperties[0]);
473 
474 	std::vector<deUint32> supportedFamilyIndices;
475 	for (deUint32 queueFamilyNdx = 0; queueFamilyNdx < numTotalFamilyIndices; ++queueFamilyNdx)
476 	{
477 		if (getPhysicalDeviceSurfaceSupport(vki, physicalDevice, queueFamilyNdx, surface) != VK_FALSE)
478 			supportedFamilyIndices.push_back(queueFamilyNdx);
479 	}
480 
481 	return supportedFamilyIndices;
482 }
483 
getSortedSupportedQueueFamilyIndices(const vk::InstanceInterface & vki,vk::VkPhysicalDevice physicalDevice,vk::VkSurfaceKHR surface)484 std::vector<deUint32> getSortedSupportedQueueFamilyIndices (const vk::InstanceInterface& vki, vk::VkPhysicalDevice physicalDevice, vk::VkSurfaceKHR surface)
485 {
486 	std::vector<deUint32> indices = getSupportedQueueFamilyIndices(vki, physicalDevice, surface);
487 	std::sort(begin(indices), end(indices));
488 	return indices;
489 }
490 
491 } // anonymous
492 
chooseQueueFamilyIndex(const vk::InstanceInterface & vki,vk::VkPhysicalDevice physicalDevice,const std::vector<vk::VkSurfaceKHR> & surfaces)493 deUint32 chooseQueueFamilyIndex (const vk::InstanceInterface& vki, vk::VkPhysicalDevice physicalDevice, const std::vector<vk::VkSurfaceKHR>& surfaces)
494 {
495 	auto indices = getCompatibleQueueFamilyIndices(vki, physicalDevice, surfaces);
496 
497 	if (indices.empty())
498 		TCU_THROW(NotSupportedError, "Device does not support presentation to the given surfaces");
499 
500 	return indices[0];
501 }
502 
chooseQueueFamilyIndex(const vk::InstanceInterface & vki,vk::VkPhysicalDevice physicalDevice,vk::VkSurfaceKHR surface)503 deUint32 chooseQueueFamilyIndex (const vk::InstanceInterface& vki, vk::VkPhysicalDevice physicalDevice, vk::VkSurfaceKHR surface)
504 {
505 	return chooseQueueFamilyIndex(vki, physicalDevice, std::vector<vk::VkSurfaceKHR>(1u, surface));
506 }
507 
getCompatibleQueueFamilyIndices(const InstanceInterface & vki,VkPhysicalDevice physicalDevice,const std::vector<VkSurfaceKHR> & surfaces)508 std::vector<deUint32> getCompatibleQueueFamilyIndices (const InstanceInterface& vki, VkPhysicalDevice physicalDevice, const std::vector<VkSurfaceKHR>& surfaces)
509 {
510 	DE_ASSERT(!surfaces.empty());
511 
512 	auto indices = getSortedSupportedQueueFamilyIndices(vki, physicalDevice, surfaces[0]);
513 
514 	for (size_t i = 1; i < surfaces.size(); ++i)
515 	{
516 		auto newIndices = getSortedSupportedQueueFamilyIndices(vki, physicalDevice, surfaces[i]);
517 
518 		// Set intersection and overwrite.
519 		decltype(indices) intersection;
520 		std::set_intersection(begin(indices), end(indices), begin(newIndices), end(newIndices), std::back_inserter(intersection));
521 		indices = std::move(intersection);
522 	}
523 
524 	return indices;
525 }
526 
getFullScreenSize(const vk::wsi::Type wsiType,const vk::wsi::Display & display,const tcu::UVec2 & fallbackSize)527 tcu::UVec2 getFullScreenSize (const vk::wsi::Type wsiType, const vk::wsi::Display& display, const tcu::UVec2& fallbackSize)
528 {
529 	tcu::UVec2 result = fallbackSize;
530 
531 	switch (wsiType)
532 	{
533 		case TYPE_XLIB:
534 		{
535 #if defined (DEQP_SUPPORT_X11)
536 			const XlibDisplayInterface&			xlibDisplay		= dynamic_cast<const XlibDisplayInterface&>(display);
537 			::Display*							displayPtr		= (::Display*)(xlibDisplay.getNative().internal);
538 			const Screen*						screen			= ScreenOfDisplay(displayPtr, 0);
539 			result.x()											= deUint32(screen->width);
540 			result.y()											= deUint32(screen->height);
541 #endif
542 			break;
543 		}
544 		case TYPE_XCB:
545 		{
546 #if defined (DEQP_SUPPORT_XCB)
547 //			const XcbDisplayInterface&			xcbDisplay		= dynamic_cast<const XcbDisplayInterface&>(display);
548 //			xcb_connection_t*					connPtr			= (xcb_connection_t*)(xcbDisplay.getNative().internal);
549 //			xcb_screen_t*						screen			= xcb_setup_roots_iterator(xcb_get_setup(connPtr)).data;
550 //			result.x()											= deUint32(screen->width_in_pixels);
551 //			result.y()											= deUint32(screen->height_in_pixels);
552 #endif
553 			break;
554 		}
555 		case TYPE_WAYLAND:
556 		{
557 #if defined (DEQP_SUPPORT_WAYLAND)
558 #endif
559 			break;
560 		}
561 		case TYPE_ANDROID:
562 		{
563 #if ( DE_OS == DE_OS_ANDROID )
564 #endif
565 			break;
566 		}
567 		case TYPE_WIN32:
568 		{
569 #if ( DE_OS == DE_OS_WIN32 )
570 			de::MovePtr<Window>					nullWindow		(display.createWindow(tcu::nothing<tcu::UVec2>()));
571 			const Win32WindowInterface&			win32Window		= dynamic_cast<const Win32WindowInterface&>(*nullWindow);
572 			HMONITOR							hMonitor		= (HMONITOR)MonitorFromWindow((HWND)win32Window.getNative().internal, MONITOR_DEFAULTTONEAREST);
573 			MONITORINFO							monitorInfo;
574 			monitorInfo.cbSize									= sizeof(MONITORINFO);
575 			GetMonitorInfo(hMonitor, &monitorInfo);
576 			result.x()											= deUint32(abs(monitorInfo.rcMonitor.right - monitorInfo.rcMonitor.left));
577 			result.y()											= deUint32(abs(monitorInfo.rcMonitor.top - monitorInfo.rcMonitor.bottom));
578 #endif
579 			break;
580 		}
581 
582 		case TYPE_MACOS:
583 		{
584 #if ( DE_OS == DE_OS_OSX )
585 #endif
586 			break;
587 		}
588 
589 		default:
590 			DE_FATAL("Unknown WSI type");
591 			break;
592 	}
593 
594 	DE_UNREF(display);
595 	return result;
596 }
597 
createRenderPass(const DeviceInterface & vkd,const VkDevice device,const VkFormat colorAttachmentFormat,const bool explicitLayoutTransitions)598 Move<VkRenderPass> WsiTriangleRenderer::createRenderPass (const DeviceInterface&	vkd,
599 														  const VkDevice			device,
600 														  const VkFormat			colorAttachmentFormat,
601 														  const bool				explicitLayoutTransitions)
602 {
603 	const VkAttachmentDescription	colorAttDesc		=
604 	{
605 		(VkAttachmentDescriptionFlags)0,
606 		colorAttachmentFormat,
607 		VK_SAMPLE_COUNT_1_BIT,
608 		VK_ATTACHMENT_LOAD_OP_CLEAR,
609 		VK_ATTACHMENT_STORE_OP_STORE,
610 		VK_ATTACHMENT_LOAD_OP_DONT_CARE,
611 		VK_ATTACHMENT_STORE_OP_DONT_CARE,
612 		(explicitLayoutTransitions) ? VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
613 		(explicitLayoutTransitions) ? VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
614 	};
615 	const VkAttachmentReference		colorAttRef			=
616 	{
617 		0u,
618 		VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
619 	};
620 	const VkSubpassDescription		subpassDesc			=
621 	{
622 		(VkSubpassDescriptionFlags)0u,
623 		VK_PIPELINE_BIND_POINT_GRAPHICS,
624 		0u,							// inputAttachmentCount
625 		DE_NULL,					// pInputAttachments
626 		1u,							// colorAttachmentCount
627 		&colorAttRef,				// pColorAttachments
628 		DE_NULL,					// pResolveAttachments
629 		DE_NULL,					// depthStencilAttachment
630 		0u,							// preserveAttachmentCount
631 		DE_NULL,					// pPreserveAttachments
632 	};
633 	const VkSubpassDependency		dependencies[]		=
634 	{
635 		{
636 			VK_SUBPASS_EXTERNAL,	// srcSubpass
637 			0u,						// dstSubpass
638 			VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
639 			VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
640 			VK_ACCESS_MEMORY_READ_BIT,
641 			(VK_ACCESS_COLOR_ATTACHMENT_READ_BIT|
642 			 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT),
643 			VK_DEPENDENCY_BY_REGION_BIT
644 		},
645 		{
646 			0u,						// srcSubpass
647 			VK_SUBPASS_EXTERNAL,	// dstSubpass
648 			VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
649 			VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
650 			(VK_ACCESS_COLOR_ATTACHMENT_READ_BIT|
651 			 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT),
652 			VK_ACCESS_MEMORY_READ_BIT,
653 			VK_DEPENDENCY_BY_REGION_BIT
654 		},
655 	};
656 	const VkRenderPassCreateInfo	renderPassParams	=
657 	{
658 		VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
659 		DE_NULL,
660 		(VkRenderPassCreateFlags)0,
661 		1u,
662 		&colorAttDesc,
663 		1u,
664 		&subpassDesc,
665 		DE_LENGTH_OF_ARRAY(dependencies),
666 		dependencies,
667 	};
668 
669 	return vk::createRenderPass(vkd, device, &renderPassParams);
670 }
671 
createPipelineLayout(const DeviceInterface & vkd,const VkDevice device)672 Move<VkPipelineLayout> WsiTriangleRenderer::createPipelineLayout (const DeviceInterface&	vkd,
673 																  const VkDevice			device)
674 {
675 	const VkPushConstantRange						pushConstantRange		=
676 	{
677 		VK_SHADER_STAGE_VERTEX_BIT,
678 		0u,											// offset
679 		(deUint32)sizeof(deUint32),					// size
680 	};
681 	const VkPipelineLayoutCreateInfo				pipelineLayoutParams	=
682 	{
683 		VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
684 		DE_NULL,
685 		(vk::VkPipelineLayoutCreateFlags)0,
686 		0u,											// setLayoutCount
687 		DE_NULL,									// pSetLayouts
688 		1u,
689 		&pushConstantRange,
690 	};
691 
692 	return vk::createPipelineLayout(vkd, device, &pipelineLayoutParams);
693 }
694 
createPipeline(const DeviceInterface & vkd,const VkDevice device,const VkRenderPass renderPass,const VkPipelineLayout pipelineLayout,const BinaryCollection & binaryCollection,const tcu::UVec2 & renderSize)695 Move<VkPipeline> WsiTriangleRenderer::createPipeline (const DeviceInterface&	vkd,
696 													  const VkDevice			device,
697 													  const VkRenderPass		renderPass,
698 													  const VkPipelineLayout	pipelineLayout,
699 													  const BinaryCollection&	binaryCollection,
700 													  const tcu::UVec2&			renderSize)
701 {
702 	// \note VkShaderModules are fully consumed by vkCreateGraphicsPipelines()
703 	//		 and can be deleted immediately following that call.
704 	const Unique<VkShaderModule>					vertShaderModule		(createShaderModule(vkd, device, binaryCollection.get("tri-vert"), 0));
705 	const Unique<VkShaderModule>					fragShaderModule		(createShaderModule(vkd, device, binaryCollection.get("tri-frag"), 0));
706 	const std::vector<VkViewport>					viewports				(1, makeViewport(renderSize));
707 	const std::vector<VkRect2D>						scissors				(1, makeRect2D(renderSize));
708 
709 	return vk::makeGraphicsPipeline(vkd,				// const DeviceInterface&            vk
710 									device,				// const VkDevice                    device
711 									pipelineLayout,		// const VkPipelineLayout            pipelineLayout
712 									*vertShaderModule,	// const VkShaderModule              vertexShaderModule
713 									DE_NULL,			// const VkShaderModule              tessellationControlShaderModule
714 									DE_NULL,			// const VkShaderModule              tessellationEvalShaderModule
715 									DE_NULL,			// const VkShaderModule              geometryShaderModule
716 									*fragShaderModule,	// const VkShaderModule              fragmentShaderModule
717 									renderPass,			// const VkRenderPass                renderPass
718 									viewports,			// const std::vector<VkViewport>&    viewports
719 									scissors);			// const std::vector<VkRect2D>&      scissors
720 }
721 
createAttachmentView(const DeviceInterface & vkd,const VkDevice device,const VkImage image,const VkFormat format)722 Move<VkImageView> WsiTriangleRenderer::createAttachmentView (const DeviceInterface&	vkd,
723 															 const VkDevice			device,
724 															 const VkImage			image,
725 															 const VkFormat			format)
726 {
727 	const VkImageViewCreateInfo		viewParams	=
728 	{
729 		VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
730 		DE_NULL,
731 		(VkImageViewCreateFlags)0,
732 		image,
733 		VK_IMAGE_VIEW_TYPE_2D,
734 		format,
735 		vk::makeComponentMappingRGBA(),
736 		{
737 			VK_IMAGE_ASPECT_COLOR_BIT,
738 			0u,						// baseMipLevel
739 			1u,						// levelCount
740 			0u,						// baseArrayLayer
741 			1u,						// layerCount
742 		},
743 	};
744 
745 	return vk::createImageView(vkd, device, &viewParams);
746 }
747 
createFramebuffer(const DeviceInterface & vkd,const VkDevice device,const VkRenderPass renderPass,const VkImageView colorAttachment,const tcu::UVec2 & renderSize)748 Move<VkFramebuffer> WsiTriangleRenderer::createFramebuffer	(const DeviceInterface&		vkd,
749 															 const VkDevice				device,
750 															 const VkRenderPass			renderPass,
751 															 const VkImageView			colorAttachment,
752 															 const tcu::UVec2&			renderSize)
753 {
754 	const VkFramebufferCreateInfo	framebufferParams	=
755 	{
756 		VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
757 		DE_NULL,
758 		(VkFramebufferCreateFlags)0,
759 		renderPass,
760 		1u,
761 		&colorAttachment,
762 		renderSize.x(),
763 		renderSize.y(),
764 		1u,							// layers
765 	};
766 
767 	return vk::createFramebuffer(vkd, device, &framebufferParams);
768 }
769 
createBuffer(const DeviceInterface & vkd,VkDevice device,VkDeviceSize size,VkBufferUsageFlags usage)770 Move<VkBuffer> WsiTriangleRenderer::createBuffer (const DeviceInterface&	vkd,
771 												  VkDevice					device,
772 												  VkDeviceSize				size,
773 												  VkBufferUsageFlags		usage)
774 {
775 	const VkBufferCreateInfo	bufferParams	=
776 	{
777 		VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
778 		DE_NULL,
779 		(VkBufferCreateFlags)0,
780 		size,
781 		usage,
782 		VK_SHARING_MODE_EXCLUSIVE,
783 		0,
784 		DE_NULL
785 	};
786 
787 	return vk::createBuffer(vkd, device, &bufferParams);
788 }
789 
WsiTriangleRenderer(const DeviceInterface & vkd,const VkDevice device,Allocator & allocator,const BinaryCollection & binaryRegistry,bool explicitLayoutTransitions,const vector<VkImage> swapchainImages,const vector<VkImage> aliasImages,const VkFormat framebufferFormat,const tcu::UVec2 & renderSize)790 WsiTriangleRenderer::WsiTriangleRenderer (const DeviceInterface&	vkd,
791 										  const VkDevice			device,
792 										  Allocator&				allocator,
793 										  const BinaryCollection&	binaryRegistry,
794 										  bool						explicitLayoutTransitions,
795 										  const vector<VkImage>		swapchainImages,
796 										  const vector<VkImage>		aliasImages,
797 										  const VkFormat			framebufferFormat,
798 										  const tcu::UVec2&			renderSize)
799 	: m_vkd							(vkd)
800 	, m_explicitLayoutTransitions	(explicitLayoutTransitions)
801 	, m_swapchainImages				(swapchainImages)
802 	, m_aliasImages					(aliasImages)
803 	, m_renderSize					(renderSize)
804 	, m_renderPass					(createRenderPass(vkd, device, framebufferFormat, m_explicitLayoutTransitions))
805 	, m_pipelineLayout				(createPipelineLayout(vkd, device))
806 	, m_pipeline					(createPipeline(vkd, device, *m_renderPass, *m_pipelineLayout, binaryRegistry, renderSize))
807 	, m_vertexBuffer				(createBuffer(vkd, device, (VkDeviceSize)(sizeof(float)*4*3), VK_BUFFER_USAGE_VERTEX_BUFFER_BIT))
808 	, m_vertexBufferMemory			(allocator.allocate(getBufferMemoryRequirements(vkd, device, *m_vertexBuffer),
809 									 MemoryRequirement::HostVisible))
810 {
811 	m_attachmentViews.resize(swapchainImages.size());
812 	m_attachmentLayouts.resize(swapchainImages.size());
813 	m_framebuffers.resize(swapchainImages.size());
814 
815 	for (size_t imageNdx = 0; imageNdx < swapchainImages.size(); ++imageNdx)
816 	{
817 		m_attachmentViews[imageNdx]		= ImageViewSp(new Unique<VkImageView>(createAttachmentView(vkd, device, swapchainImages[imageNdx], framebufferFormat)));
818 		m_attachmentLayouts[imageNdx]	= VK_IMAGE_LAYOUT_UNDEFINED;
819 		m_framebuffers[imageNdx]		= FramebufferSp(new Unique<VkFramebuffer>(createFramebuffer(vkd, device, *m_renderPass, **m_attachmentViews[imageNdx], renderSize)));
820 	}
821 
822 	VK_CHECK(vkd.bindBufferMemory(device, *m_vertexBuffer, m_vertexBufferMemory->getMemory(), m_vertexBufferMemory->getOffset()));
823 
824 	{
825 		const VkMappedMemoryRange	memRange	=
826 		{
827 			VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,
828 			DE_NULL,
829 			m_vertexBufferMemory->getMemory(),
830 			m_vertexBufferMemory->getOffset(),
831 			VK_WHOLE_SIZE
832 		};
833 		const tcu::Vec4				vertices[]	=
834 		{
835 			tcu::Vec4(-0.5f, -0.5f, 0.0f, 1.0f),
836 			tcu::Vec4(+0.5f, -0.5f, 0.0f, 1.0f),
837 			tcu::Vec4( 0.0f, +0.5f, 0.0f, 1.0f)
838 		};
839 		DE_STATIC_ASSERT(sizeof(vertices) == sizeof(float)*4*3);
840 
841 		deMemcpy(m_vertexBufferMemory->getHostPtr(), &vertices[0], sizeof(vertices));
842 		VK_CHECK(vkd.flushMappedMemoryRanges(device, 1u, &memRange));
843 	}
844 }
845 
WsiTriangleRenderer(WsiTriangleRenderer && other)846 WsiTriangleRenderer::WsiTriangleRenderer (WsiTriangleRenderer&& other)
847 	: m_vkd					(other.m_vkd)
848 	, m_explicitLayoutTransitions	(other.m_explicitLayoutTransitions)
849 	, m_swapchainImages		(other.m_swapchainImages)
850 	, m_aliasImages			(other.m_aliasImages)
851 	, m_renderSize			(other.m_renderSize)
852 	, m_renderPass			(other.m_renderPass)
853 	, m_pipelineLayout		(other.m_pipelineLayout)
854 	, m_pipeline			(other.m_pipeline)
855 	, m_vertexBuffer		(other.m_vertexBuffer)
856 	, m_vertexBufferMemory	(other.m_vertexBufferMemory)
857 	, m_attachmentViews		(other.m_attachmentViews)
858 	, m_attachmentLayouts	(other.m_attachmentLayouts)
859 	, m_framebuffers		(other.m_framebuffers)
860 {
861 }
862 
~WsiTriangleRenderer(void)863 WsiTriangleRenderer::~WsiTriangleRenderer (void)
864 {
865 }
866 
recordFrame(VkCommandBuffer cmdBuffer,deUint32 imageNdx,deUint32 frameNdx) const867 void WsiTriangleRenderer::recordFrame (VkCommandBuffer	cmdBuffer,
868 									   deUint32			imageNdx,
869 									   deUint32			frameNdx) const
870 {
871 	const VkFramebuffer	curFramebuffer	= **m_framebuffers[imageNdx];
872 
873 	beginCommandBuffer(m_vkd, cmdBuffer, 0u);
874 
875 	if (m_explicitLayoutTransitions || m_attachmentLayouts[imageNdx] == VK_IMAGE_LAYOUT_UNDEFINED)
876 	{
877 		const auto range		= makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
878 		const auto newLayout	= (m_explicitLayoutTransitions ? VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
879 		const auto srcStage		= VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
880 		const auto srcMask		= 0u;
881 		const auto dstStage		= (m_explicitLayoutTransitions ? VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT : VK_PIPELINE_STAGE_ALL_COMMANDS_BIT);
882 		const auto dstMask		= (m_explicitLayoutTransitions ? VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT : 0);
883 
884 		const auto barrier = makeImageMemoryBarrier(srcMask, dstMask, m_attachmentLayouts[imageNdx], newLayout, m_aliasImages[imageNdx], range);
885 		m_vkd.cmdPipelineBarrier(cmdBuffer, srcStage, dstStage, 0u, 0u, nullptr, 0u, nullptr, 1u, &barrier);
886 
887 		m_attachmentLayouts[imageNdx] = newLayout;
888 	}
889 
890 	beginRenderPass(m_vkd, cmdBuffer, *m_renderPass, curFramebuffer, makeRect2D(0, 0, m_renderSize.x(), m_renderSize.y()), tcu::Vec4(0.125f, 0.25f, 0.75f, 1.0f));
891 
892 	m_vkd.cmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
893 
894 	{
895 		const VkDeviceSize bindingOffset = 0;
896 		m_vkd.cmdBindVertexBuffers(cmdBuffer, 0u, 1u, &m_vertexBuffer.get(), &bindingOffset);
897 	}
898 
899 	m_vkd.cmdPushConstants(cmdBuffer, *m_pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 0u, (deUint32)sizeof(deUint32), &frameNdx);
900 	m_vkd.cmdDraw(cmdBuffer, 3u, 1u, 0u, 0u);
901 	endRenderPass(m_vkd, cmdBuffer);
902 
903 	if (m_explicitLayoutTransitions)
904 	{
905 		VkImageSubresourceRange range = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 };
906 		const VkImageMemoryBarrier	barrier	= makeImageMemoryBarrier	(VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, 0,
907 																		 m_attachmentLayouts[imageNdx], VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
908 																		 m_aliasImages[imageNdx], range);
909 		m_vkd.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0u, 0u, DE_NULL, 0u, DE_NULL, 1u, &barrier);
910 		m_attachmentLayouts[imageNdx] = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
911 	}
912 
913 	endCommandBuffer(m_vkd, cmdBuffer);
914 }
915 
recordDeviceGroupFrame(VkCommandBuffer cmdBuffer,deUint32 firstDeviceID,deUint32 secondDeviceID,deUint32 devicesCount,deUint32 imageNdx,deUint32 frameNdx) const916 void WsiTriangleRenderer::recordDeviceGroupFrame (VkCommandBuffer	cmdBuffer,
917 												  deUint32			firstDeviceID,
918 												  deUint32			secondDeviceID,
919 												  deUint32			devicesCount,
920 												  deUint32			imageNdx,
921 												  deUint32			frameNdx) const
922 {
923 	const VkFramebuffer	curFramebuffer	= **m_framebuffers[imageNdx];
924 
925 	beginCommandBuffer(m_vkd, cmdBuffer, 0u);
926 
927 	if (m_explicitLayoutTransitions || m_attachmentLayouts[imageNdx] == VK_IMAGE_LAYOUT_UNDEFINED)
928 	{
929 		const auto range		= makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
930 		const auto newLayout	= (m_explicitLayoutTransitions ? VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
931 		const auto srcStage		= VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
932 		const auto srcMask		= 0u;
933 		const auto dstStage		= (m_explicitLayoutTransitions ? VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT : VK_PIPELINE_STAGE_ALL_COMMANDS_BIT);
934 		const auto dstMask		= (m_explicitLayoutTransitions ? VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT : 0);
935 
936 		const auto barrier = makeImageMemoryBarrier(srcMask, dstMask, m_attachmentLayouts[imageNdx], newLayout, m_aliasImages[imageNdx], range);
937 		m_vkd.cmdPipelineBarrier(cmdBuffer, srcStage, dstStage, 0u, 0u, nullptr, 0u, nullptr, 1u, &barrier);
938 
939 		m_attachmentLayouts[imageNdx] = newLayout;
940 	}
941 
942 	// begin renderpass
943 	{
944 		const VkClearValue clearValue = makeClearValueColorF32(0.125f, 0.25f, 0.75f, 1.0f);
945 
946 		VkRect2D zeroRect = { { 0, 0, },{ 0, 0, } };
947 		vector<VkRect2D> renderAreas;
948 		for (deUint32 i = 0; i < devicesCount; i++)
949 			renderAreas.push_back(zeroRect);
950 
951 		// Render completely if there is only 1 device
952 		if (devicesCount == 1u)
953 		{
954 			renderAreas[0].extent.width = (deInt32)m_renderSize.x();
955 			renderAreas[0].extent.height = (deInt32)m_renderSize.y();
956 		}
957 		else
958 		{
959 			// Split into 2 vertical halves
960 			renderAreas[firstDeviceID].extent.width		= (deInt32)m_renderSize.x() / 2;
961 			renderAreas[firstDeviceID].extent.height	= (deInt32)m_renderSize.y();
962 			renderAreas[secondDeviceID]					= renderAreas[firstDeviceID];
963 			renderAreas[secondDeviceID].offset.x		= (deInt32)m_renderSize.x() / 2;
964 		}
965 
966 		const VkDeviceGroupRenderPassBeginInfo deviceGroupRPBeginInfo =
967 		{
968 			VK_STRUCTURE_TYPE_DEVICE_GROUP_RENDER_PASS_BEGIN_INFO,
969 			DE_NULL,
970 			(deUint32)((1 << devicesCount) - 1),
971 			devicesCount,
972 			&renderAreas[0]
973 		};
974 
975 		const VkRenderPassBeginInfo passBeginParams =
976 		{
977 			VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,						// sType
978 			&deviceGroupRPBeginInfo,										// pNext
979 			*m_renderPass,													// renderPass
980 			curFramebuffer,													// framebuffer
981 			{
982 				{ 0, 0 },
983 				{ m_renderSize.x(), m_renderSize.y() }
984 			},																// renderArea
985 			1u,																// clearValueCount
986 			&clearValue,													// pClearValues
987 		};
988 		m_vkd.cmdBeginRenderPass(cmdBuffer, &passBeginParams, VK_SUBPASS_CONTENTS_INLINE);
989 	}
990 
991 	m_vkd.cmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
992 
993 	{
994 		const VkDeviceSize bindingOffset = 0;
995 		m_vkd.cmdBindVertexBuffers(cmdBuffer, 0u, 1u, &m_vertexBuffer.get(), &bindingOffset);
996 	}
997 
998 	m_vkd.cmdPushConstants(cmdBuffer, *m_pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 0u, (deUint32)sizeof(deUint32), &frameNdx);
999 	m_vkd.cmdDraw(cmdBuffer, 3u, 1u, 0u, 0u);
1000 	endRenderPass(m_vkd, cmdBuffer);
1001 
1002 	if (m_explicitLayoutTransitions)
1003 	{
1004 		VkImageSubresourceRange range = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 };
1005 		const VkImageMemoryBarrier	barrier	= makeImageMemoryBarrier	(VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, 0,
1006 																		 m_attachmentLayouts[imageNdx], VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
1007 																		 m_aliasImages[imageNdx], range);
1008 		m_vkd.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0u, 0u, DE_NULL, 0u, DE_NULL, 1u, &barrier);
1009 		m_attachmentLayouts[imageNdx] = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
1010 	}
1011 
1012 	endCommandBuffer(m_vkd, cmdBuffer);
1013 }
1014 
getPrograms(SourceCollections & dst)1015 void WsiTriangleRenderer::getPrograms (SourceCollections& dst)
1016 {
1017 	dst.glslSources.add("tri-vert") << glu::VertexSource(
1018 		"#version 310 es\n"
1019 		"layout(location = 0) in highp vec4 a_position;\n"
1020 		"layout(push_constant) uniform FrameData\n"
1021 		"{\n"
1022 		"    highp uint frameNdx;\n"
1023 		"} frameData;\n"
1024 		"void main (void)\n"
1025 		"{\n"
1026 		"    highp float angle = float(frameData.frameNdx) / 100.0;\n"
1027 		"    highp float c     = cos(angle);\n"
1028 		"    highp float s     = sin(angle);\n"
1029 		"    highp mat4  t     = mat4( c, -s,  0,  0,\n"
1030 		"                              s,  c,  0,  0,\n"
1031 		"                              0,  0,  1,  0,\n"
1032 		"                              0,  0,  0,  1);\n"
1033 		"    gl_Position = t * a_position;\n"
1034 		"}\n");
1035 	dst.glslSources.add("tri-frag") << glu::FragmentSource(
1036 		"#version 310 es\n"
1037 		"layout(location = 0) out lowp vec4 o_color;\n"
1038 		"void main (void) { o_color = vec4(1.0, 0.0, 1.0, 1.0); }\n");
1039 }
1040 
1041 } // wsi
1042 } // vk
1043