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