• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2017 The Khronos Group Inc.
6 * Copyright (c) 2017 Nvidia Corporation
7 *
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 *		http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 *
20 *//*!
21 * \file
22 * \brief Device Group Tests
23 *//*--------------------------------------------------------------------*/
24 
25 #include "vktDeviceGroupTests.hpp"
26 #include "vktCustomInstancesDevices.hpp"
27 
28 #include "vkDefs.hpp"
29 #include "vkDeviceUtil.hpp"
30 #include "vkImageUtil.hpp"
31 #include "vkMemUtil.hpp"
32 #include "vkPlatform.hpp"
33 #include "vkPrograms.hpp"
34 #include "vkQueryUtil.hpp"
35 #include "vkRef.hpp"
36 #include "vkRefUtil.hpp"
37 #include "vkStrUtil.hpp"
38 #include "vkTypeUtil.hpp"
39 #include "vkCmdUtil.hpp"
40 #include "vkObjUtil.hpp"
41 #include "vkSafetyCriticalUtil.hpp"
42 #include "vktTestCase.hpp"
43 #include "vktTestCaseUtil.hpp"
44 #include "vktTestGroupUtil.hpp"
45 
46 #include "tcuDefs.hpp"
47 #include "tcuFormatUtil.hpp"
48 #include "tcuImageCompare.hpp"
49 #include "tcuResource.hpp"
50 #include "tcuTestCase.hpp"
51 #include "tcuTestLog.hpp"
52 #include "tcuCommandLine.hpp"
53 #include "tcuTextureUtil.hpp"
54 #include "tcuImageIO.hpp"
55 
56 #include "rrRenderer.hpp"
57 
58 #include <sstream>
59 
60 namespace vkt
61 {
62 namespace DeviceGroup
63 {
64 namespace
65 {
66 
67 using namespace vk;
68 using std::string;
69 using std::vector;
70 using tcu::TestLog;
71 using de::UniquePtr;
72 
73 //Device group test modes
74 enum TestModeType
75 {
76 	TEST_MODE_SFR			= 1 << 0,			//!< Split frame rendering
77 	TEST_MODE_AFR			= 1 << 1,			//!< Alternate frame rendering
78 	TEST_MODE_HOSTMEMORY	= 1 << 2,			//!< Use host memory for rendertarget
79 	TEST_MODE_DEDICATED		= 1 << 3,			//!< Use dedicated allocations
80 	TEST_MODE_PEER_FETCH	= 1 << 4,			//!< Peer vertex attributes from peer memory
81 	TEST_MODE_TESSELLATION	= 1 << 5,			//!< Generate a tessellated sphere instead of triangle
82 	TEST_MODE_LINEFILL		= 1 << 6,			//!< Draw polygon edges as line segments
83 };
84 
85 class RefVertexShader : public rr::VertexShader
86 {
87 public:
RefVertexShader(void)88 	RefVertexShader (void)
89 		: rr::VertexShader(1, 0)
90 	{
91 		m_inputs[0].type = rr::GENERICVECTYPE_FLOAT;
92 	}
~RefVertexShader(void)93 	virtual	~RefVertexShader(void) {}
94 
shadeVertices(const rr::VertexAttrib * inputs,rr::VertexPacket * const * packets,const int numPackets) const95 	void shadeVertices (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const
96 	{
97 		for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
98 		{
99 			packets[packetNdx]->position = rr::readVertexAttribFloat(inputs[0],
100 				packets[packetNdx]->instanceNdx,
101 				packets[packetNdx]->vertexNdx);
102 		}
103 	}
104 };
105 
106 class RefFragmentShader : public rr::FragmentShader
107 {
108 public:
RefFragmentShader(void)109 	RefFragmentShader (void)
110 		: rr::FragmentShader(0, 1)
111 	{
112 		m_outputs[0].type = rr::GENERICVECTYPE_FLOAT;
113 	}
114 
~RefFragmentShader(void)115 	virtual	~RefFragmentShader(void) {}
116 
shadeFragments(rr::FragmentPacket *,const int numPackets,const rr::FragmentShadingContext & context) const117 	void shadeFragments (rr::FragmentPacket*, const int numPackets, const rr::FragmentShadingContext& context) const
118 	{
119 		for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
120 		{
121 			for (int fragNdx = 0; fragNdx < rr::NUM_FRAGMENTS_PER_PACKET; ++fragNdx)
122 			{
123 				rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, tcu::Vec4(1.0f, 1.0f, 0.0f, 1.0f));
124 			}
125 		}
126 	}
127 };
128 
renderReferenceTriangle(const tcu::PixelBufferAccess & dst,const tcu::Vec4 (& vertices)[3],const int subpixelBits)129 void renderReferenceTriangle (const tcu::PixelBufferAccess& dst, const tcu::Vec4(&vertices)[3], const int subpixelBits)
130 {
131 	const RefVertexShader					vertShader;
132 	const RefFragmentShader					fragShader;
133 	const rr::Program						program(&vertShader, &fragShader);
134 	const rr::MultisamplePixelBufferAccess	colorBuffer = rr::MultisamplePixelBufferAccess::fromSinglesampleAccess(dst);
135 	const rr::RenderTarget					renderTarget(colorBuffer);
136 	const rr::RenderState					renderState((rr::ViewportState(colorBuffer)), subpixelBits);
137 	const rr::Renderer						renderer;
138 	const rr::VertexAttrib					vertexAttribs[] =
139 	{
140 		rr::VertexAttrib(rr::VERTEXATTRIBTYPE_FLOAT, 4, sizeof(tcu::Vec4), 0, vertices[0].getPtr())
141 	};
142 	renderer.draw(rr::DrawCommand(renderState,
143 		renderTarget,
144 		program,
145 		DE_LENGTH_OF_ARRAY(vertexAttribs),
146 		&vertexAttribs[0],
147 		rr::PrimitiveList(rr::PRIMITIVETYPE_TRIANGLES, DE_LENGTH_OF_ARRAY(vertices), 0)));
148 }
149 
150 class DeviceGroupTestInstance : public TestInstance
151 {
152 public:
153 	DeviceGroupTestInstance(Context& context, deUint32 mode);
154 	~DeviceGroupTestInstance(void);
155 private:
156 			void						init						(void);
157 			deUint32					getMemoryIndex				(deUint32 memoryTypeBits, deUint32 memoryPropertyFlag);
158 			bool						isPeerFetchAllowed			(deUint32 memoryTypeIndex, deUint32 firstdeviceID, deUint32 seconddeviceID);
159 			void						submitBufferAndWaitForIdle	(const vk::DeviceInterface& vk, VkCommandBuffer cmdBuf, deUint32 deviceMask);
160 	virtual	tcu::TestStatus				iterate						(void);
161 
162 			std::shared_ptr<CustomInstanceWrapper>	m_instanceWrapper;
163 			Move<VkDevice>				m_deviceGroup;
164 #ifndef CTS_USES_VULKANSC
165 			de::MovePtr<vk::DeviceDriver>	m_deviceDriver;
166 #else
167 			de::MovePtr<vk::DeviceDriverSC, vk::DeinitDeviceDeleter>	m_deviceDriver;
168 #endif // CTS_USES_VULKANSC
169 			deUint32					m_physicalDeviceCount;
170 			VkQueue						m_deviceGroupQueue;
171 			vector<VkPhysicalDevice>	m_physicalDevices;
172 
173 			deUint32					m_testMode;
174 			bool						m_useHostMemory;
175 			bool						m_useDedicated;
176 			bool						m_usePeerFetch;
177 			bool						m_subsetAllocation;
178 			bool						m_fillModeNonSolid;
179 			bool						m_drawTessellatedSphere;
180 };
181 
DeviceGroupTestInstance(Context & context,const deUint32 mode)182 DeviceGroupTestInstance::DeviceGroupTestInstance (Context& context, const deUint32 mode)
183 	: TestInstance				(context)
184 	, m_instanceWrapper			(new CustomInstanceWrapper(context))
185 	, m_physicalDeviceCount		(0)
186 	, m_deviceGroupQueue		(DE_NULL)
187 	, m_testMode				(mode)
188 	, m_useHostMemory			(m_testMode & TEST_MODE_HOSTMEMORY)
189 	, m_useDedicated			(m_testMode & TEST_MODE_DEDICATED)
190 	, m_usePeerFetch			(m_testMode & TEST_MODE_PEER_FETCH)
191 	, m_subsetAllocation		(true)
192 	, m_fillModeNonSolid		(m_testMode & TEST_MODE_LINEFILL)
193 	, m_drawTessellatedSphere	(m_testMode & TEST_MODE_TESSELLATION)
194 {
195 	init();
196 }
197 
~DeviceGroupTestInstance()198 DeviceGroupTestInstance::~DeviceGroupTestInstance()
199 {
200 }
201 
getMemoryIndex(const deUint32 memoryTypeBits,const deUint32 memoryPropertyFlag)202 deUint32 DeviceGroupTestInstance::getMemoryIndex (const deUint32 memoryTypeBits, const deUint32 memoryPropertyFlag)
203 {
204 	const VkPhysicalDeviceMemoryProperties deviceMemProps = getPhysicalDeviceMemoryProperties(m_instanceWrapper->instance.getDriver(), m_context.getPhysicalDevice());
205 	for (deUint32 memoryTypeNdx = 0; memoryTypeNdx < deviceMemProps.memoryTypeCount; memoryTypeNdx++)
206 	{
207 		if ((memoryTypeBits & (1u << memoryTypeNdx)) != 0 &&
208 			(deviceMemProps.memoryTypes[memoryTypeNdx].propertyFlags & memoryPropertyFlag) == memoryPropertyFlag)
209 			return memoryTypeNdx;
210 	}
211 	TCU_THROW(NotSupportedError, "No compatible memory type found");
212 }
213 
isPeerFetchAllowed(deUint32 memoryTypeIndex,deUint32 firstdeviceID,deUint32 seconddeviceID)214 bool DeviceGroupTestInstance::isPeerFetchAllowed (deUint32 memoryTypeIndex, deUint32 firstdeviceID, deUint32 seconddeviceID)
215 {
216 	VkPeerMemoryFeatureFlags				peerMemFeatures1;
217 	VkPeerMemoryFeatureFlags				peerMemFeatures2;
218 	const DeviceDriver						vk						(m_context.getPlatformInterface(), m_instanceWrapper->instance, *m_deviceGroup);
219 	const VkPhysicalDeviceMemoryProperties	deviceMemProps1			= getPhysicalDeviceMemoryProperties(m_instanceWrapper->instance.getDriver(), m_physicalDevices[firstdeviceID]);
220 	const VkPhysicalDeviceMemoryProperties	deviceMemProps2			= getPhysicalDeviceMemoryProperties(m_instanceWrapper->instance.getDriver(), m_physicalDevices[seconddeviceID]);
221 	vk.getDeviceGroupPeerMemoryFeatures(*m_deviceGroup, deviceMemProps2.memoryTypes[memoryTypeIndex].heapIndex, firstdeviceID, seconddeviceID, &peerMemFeatures1);
222 	vk.getDeviceGroupPeerMemoryFeatures(*m_deviceGroup, deviceMemProps1.memoryTypes[memoryTypeIndex].heapIndex, seconddeviceID, firstdeviceID, &peerMemFeatures2);
223 	return (peerMemFeatures1 & VK_PEER_MEMORY_FEATURE_GENERIC_SRC_BIT) && (peerMemFeatures2 & VK_PEER_MEMORY_FEATURE_GENERIC_SRC_BIT);
224 }
225 
init(void)226 void DeviceGroupTestInstance::init (void)
227 {
228 	if (!m_context.isInstanceFunctionalitySupported("VK_KHR_device_group_creation"))
229 		TCU_THROW(NotSupportedError, "Device Group tests are not supported, no device group extension present.");
230 
231 	if (!m_context.isDeviceFunctionalitySupported("VK_KHR_device_group"))
232 		TCU_THROW(NotSupportedError, "Missing extension: VK_KHR_device_group");
233 
234 	vector<string>					deviceExtensions;
235 
236 	if (!isCoreDeviceExtension(m_context.getUsedApiVersion(), "VK_KHR_device_group"))
237 		deviceExtensions.push_back("VK_KHR_device_group");
238 
239 	if(m_useDedicated)
240 	{
241 		if (!m_context.isDeviceFunctionalitySupported("VK_KHR_dedicated_allocation"))
242 			TCU_THROW(NotSupportedError, "Missing extension: VK_KHR_dedicated_allocation");
243 
244 		if (!isCoreDeviceExtension(m_context.getUsedApiVersion(), "VK_KHR_dedicated_allocation"))
245 			deviceExtensions.push_back("VK_KHR_dedicated_allocation");
246 	}
247 
248 	const InstanceInterface&		instanceDriver		= m_instanceWrapper->instance.getDriver();
249 	const deUint32					queueFamilyIndex	= m_context.getUniversalQueueFamilyIndex();
250 	const deUint32					queueIndex			= 0;
251 	const float						queuePriority		= 1.0f;
252 	vector<const char*>				extensionPtrs;
253 	vector<const char*>				layerPtrs;
254 	vector<string>					enabledLayers;
255 
256 	{
257 		const tcu::CommandLine&								cmdLine		= m_context.getTestContext().getCommandLine();
258 		const vector<vk::VkPhysicalDeviceGroupProperties>	properties	= enumeratePhysicalDeviceGroups(instanceDriver, m_instanceWrapper->instance);
259 		const int											kGroupId	= cmdLine.getVKDeviceGroupId();
260 		const int											kGroupIndex	= kGroupId - 1;
261 		const int											kDevId		= cmdLine.getVKDeviceId();
262 		const int											kDevIndex	= kDevId - 1;
263 
264 		if (kGroupId < 1 || static_cast<size_t>(kGroupId) > properties.size())
265 		{
266 			std::ostringstream msg;
267 			msg << "Invalid device group id " << kGroupId << " (only " << properties.size() << " device groups found)";
268 			TCU_THROW(NotSupportedError, msg.str());
269 		}
270 
271 		m_physicalDeviceCount = properties[kGroupIndex].physicalDeviceCount;
272 		for (deUint32 idx = 0; idx < m_physicalDeviceCount; idx++)
273 		{
274 			m_physicalDevices.push_back(properties[kGroupIndex].physicalDevices[idx]);
275 		}
276 
277 		if (m_usePeerFetch && m_physicalDeviceCount < 2)
278 			TCU_THROW(NotSupportedError, "Peer fetching needs more than 1 physical device.");
279 
280 		if (!(m_testMode & TEST_MODE_AFR) || (m_physicalDeviceCount > 1))
281 		{
282 			if (!de::contains(m_context.getDeviceExtensions().begin(), m_context.getDeviceExtensions().end(), std::string("VK_KHR_bind_memory2")))
283 				TCU_THROW(NotSupportedError, "Missing extension: VK_KHR_bind_memory2");
284 			if (!isCoreDeviceExtension(m_context.getUsedApiVersion(), "VK_KHR_bind_memory2"))
285 				deviceExtensions.push_back("VK_KHR_bind_memory2");
286 		}
287 
288 		const VkDeviceQueueCreateInfo						deviceQueueCreateInfo =
289 		{
290 			VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,	//type
291 			DE_NULL,									//pNext
292 			(VkDeviceQueueCreateFlags)0u,				//flags
293 			queueFamilyIndex,							//queueFamilyIndex;
294 			1u,											//queueCount;
295 			&queuePriority,								//pQueuePriorities;
296 		};
297 		VkDeviceGroupDeviceCreateInfo				deviceGroupInfo =
298 		{
299 			VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO,					//stype
300 			DE_NULL,															//pNext
301 			properties[kGroupIndex].physicalDeviceCount,	//physicalDeviceCount
302 			properties[kGroupIndex].physicalDevices		//physicalDevices
303 		};
304 
305 		if (kDevId < 1 || static_cast<deUint32>(kDevId) > m_physicalDeviceCount)
306 		{
307 			std::ostringstream msg;
308 			msg << "Device id " << kDevId << " invalid for group " << kGroupId << " (group " << kGroupId << " has " << m_physicalDeviceCount << " devices)";
309 			TCU_THROW(NotSupportedError, msg.str());
310 		}
311 
312 		VkPhysicalDevice			physicalDevice			= properties[kGroupIndex].physicalDevices[kDevIndex];
313 		VkPhysicalDeviceFeatures	enabledDeviceFeatures	= getPhysicalDeviceFeatures(instanceDriver, physicalDevice);
314 		m_subsetAllocation									= properties[kGroupIndex].subsetAllocation;
315 
316 		if (m_drawTessellatedSphere & static_cast<bool>(!enabledDeviceFeatures.tessellationShader))
317 			TCU_THROW(NotSupportedError, "Tessellation is not supported.");
318 
319 		if (m_fillModeNonSolid & static_cast<bool>(!enabledDeviceFeatures.fillModeNonSolid))
320 			TCU_THROW(NotSupportedError, "Line polygon mode is not supported.");
321 
322 		extensionPtrs.resize(deviceExtensions.size());
323 		for (size_t ndx = 0; ndx < deviceExtensions.size(); ++ndx)
324 			extensionPtrs[ndx] = deviceExtensions[ndx].c_str();
325 
326 		void* pNext												= &deviceGroupInfo;
327 #ifdef CTS_USES_VULKANSC
328 		VkDeviceObjectReservationCreateInfo memReservationInfo	= cmdLine.isSubProcess() ? m_context.getResourceInterface()->getStatMax() : resetDeviceObjectReservationCreateInfo();
329 		memReservationInfo.pNext								= pNext;
330 		pNext													= &memReservationInfo;
331 
332 		VkPhysicalDeviceVulkanSC10Features sc10Features			= createDefaultSC10Features();
333 		sc10Features.pNext										= pNext;
334 		pNext													= &sc10Features;
335 		VkPipelineCacheCreateInfo			pcCI;
336 		std::vector<VkPipelinePoolSize>		poolSizes;
337 		if (m_context.getTestContext().getCommandLine().isSubProcess())
338 		{
339 			if (m_context.getResourceInterface()->getCacheDataSize() > 0)
340 			{
341 				pcCI =
342 				{
343 					VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO,		// VkStructureType				sType;
344 					DE_NULL,											// const void*					pNext;
345 					VK_PIPELINE_CACHE_CREATE_READ_ONLY_BIT |
346 						VK_PIPELINE_CACHE_CREATE_USE_APPLICATION_STORAGE_BIT,	// VkPipelineCacheCreateFlags	flags;
347 					m_context.getResourceInterface()->getCacheDataSize(),	// deUintptr					initialDataSize;
348 					m_context.getResourceInterface()->getCacheData()		// const void*					pInitialData;
349 				};
350 				memReservationInfo.pipelineCacheCreateInfoCount		= 1;
351 				memReservationInfo.pPipelineCacheCreateInfos		= &pcCI;
352 			}
353 
354 			poolSizes							= m_context.getResourceInterface()->getPipelinePoolSizes();
355 			if (!poolSizes.empty())
356 			{
357 				memReservationInfo.pipelinePoolSizeCount		= deUint32(poolSizes.size());
358 				memReservationInfo.pPipelinePoolSizes			= poolSizes.data();
359 			}
360 		}
361 #endif // CTS_USES_VULKANSC
362 
363 		const VkDeviceCreateInfo	deviceCreateInfo =
364 		{
365 			VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,					//sType;
366 			pNext,													//pNext;
367 			(VkDeviceCreateFlags)0u,								//flags
368 			1,														//queueRecordCount;
369 			&deviceQueueCreateInfo,									//pRequestedQueues;
370 			0u,														//layerCount;
371 			DE_NULL,												//ppEnabledLayerNames;
372 			(deUint32)extensionPtrs.size(),							//extensionCount;
373 			(extensionPtrs.empty() ? DE_NULL : &extensionPtrs[0]),	//ppEnabledExtensionNames;
374 			&enabledDeviceFeatures,									//pEnabledFeatures;
375 		};
376 		m_deviceGroup = createCustomDevice(m_context.getTestContext().getCommandLine().isValidationEnabled(), m_context.getPlatformInterface(), m_instanceWrapper->instance, instanceDriver, physicalDevice, &deviceCreateInfo);
377 #ifndef CTS_USES_VULKANSC
378 		m_deviceDriver = de::MovePtr<DeviceDriver>(new DeviceDriver(m_context.getPlatformInterface(), m_instanceWrapper->instance, *m_deviceGroup));
379 #else
380 		m_deviceDriver = de::MovePtr<DeviceDriverSC, DeinitDeviceDeleter>(new DeviceDriverSC(m_context.getPlatformInterface(), m_instanceWrapper->instance, *m_deviceGroup, m_context.getTestContext().getCommandLine(), m_context.getResourceInterface(), m_context.getDeviceVulkanSC10Properties(), m_context.getDeviceProperties()), vk::DeinitDeviceDeleter(m_context.getResourceInterface().get(), *m_deviceGroup));
381 #endif // CTS_USES_VULKANSC
382 	}
383 
384 	m_deviceGroupQueue = getDeviceQueue(*m_deviceDriver, *m_deviceGroup, queueFamilyIndex, queueIndex);
385 }
386 
submitBufferAndWaitForIdle(const vk::DeviceInterface & vk,VkCommandBuffer cmdBuf,deUint32 deviceMask)387 void DeviceGroupTestInstance::submitBufferAndWaitForIdle(const vk::DeviceInterface& vk, VkCommandBuffer cmdBuf, deUint32 deviceMask)
388 {
389 	submitCommandsAndWait(vk, *m_deviceGroup, m_deviceGroupQueue, cmdBuf, true, deviceMask);
390 	VK_CHECK(vk.deviceWaitIdle(*m_deviceGroup));
391 }
392 
iterate(void)393 tcu::TestStatus DeviceGroupTestInstance::iterate (void)
394 {
395 	const InstanceInterface&	vki						= m_instanceWrapper->instance.getDriver();
396 	const vk::DeviceInterface&	vk						= m_context.getDeviceInterface();
397 	const deUint32				queueFamilyIndex		= m_context.getUniversalQueueFamilyIndex();
398 	const tcu::UVec2			renderSize				(256, 256);
399 	const VkFormat				colorFormat				= VK_FORMAT_R8G8B8A8_UNORM;
400 	const tcu::Vec4				clearColor				(0.125f, 0.25f, 0.75f, 1.0f);
401 	const tcu::Vec4				drawColor				(1.0f, 1.0f, 0.0f, 1.0f);
402 	const float					tessLevel				= 16.0f;
403 	SimpleAllocator				memAlloc				(vk, *m_deviceGroup, getPhysicalDeviceMemoryProperties(vki, m_context.getPhysicalDevice()));
404 	bool						iterateResultSuccess	= false;
405 	const tcu::Vec4				sphereVertices[]		=
406 	{
407 		tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f),
408 		tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f),
409 		tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f),
410 		tcu::Vec4(0.0f, 0.0f, -1.0f, 1.0f),
411 		tcu::Vec4(0.0f, -1.0f, 0.0f, 1.0f),
412 		tcu::Vec4(-1.0f, 0.0f, 0.0f, 1.0f),
413 	};
414 	const deUint32				sphereIndices[]			= {0, 1, 2, 2, 1, 3, 3, 1, 5, 5, 1, 0, 0, 2, 4, 2, 3, 4, 3, 5, 4, 5, 0, 4};
415 	const tcu::Vec4				triVertices[]			=
416 	{
417 		tcu::Vec4(-0.5f, -0.5f, 0.0f, 1.0f),
418 		tcu::Vec4(+0.5f, -0.5f, 0.0f, 1.0f),
419 		tcu::Vec4(0.0f, +0.5f, 0.0f, 1.0f)
420 	};
421 	const deUint32				triIndices[]			= {0, 1, 2};
422 	const tcu::Vec4 *			vertices				= m_drawTessellatedSphere ? &sphereVertices[0] : &triVertices[0];
423 	const deUint32 *			indices					= m_drawTessellatedSphere ? &sphereIndices[0] : &triIndices[0];
424 	const deUint32				verticesSize			= m_drawTessellatedSphere ? deUint32(sizeof(sphereVertices)) : deUint32(sizeof(triVertices));
425 	const deUint32				numIndices				= m_drawTessellatedSphere ? deUint32(sizeof(sphereIndices)/sizeof(sphereIndices[0])) : deUint32(sizeof(triIndices)/sizeof(triIndices[0]));
426 	const deUint32				indicesSize				= m_drawTessellatedSphere ? deUint32(sizeof(sphereIndices)) : deUint32(sizeof(triIndices));
427 
428 	// Loop through all physical devices in the device group
429 	for (deUint32 physDevID = 0; physDevID < m_physicalDeviceCount; physDevID++)
430 	{
431 		const deUint32			firstDeviceID				= physDevID;
432 		const deUint32			secondDeviceID				= (firstDeviceID + 1 ) % m_physicalDeviceCount;
433 		vector<deUint32>		deviceIndices				(m_physicalDeviceCount);
434 		bool					isPeerMemAsCopySrcAllowed	= true;
435 		// Set broadcast on memory allocation
436 		const deUint32			allocDeviceMask				= m_subsetAllocation ? (1 << firstDeviceID) | (1 << secondDeviceID) : (1 << m_physicalDeviceCount) - 1;
437 
438 		for (deUint32 i = 0; i < m_physicalDeviceCount; i++)
439 			deviceIndices[i] = i;
440 		deviceIndices[firstDeviceID] = secondDeviceID;
441 		deviceIndices[secondDeviceID] = firstDeviceID;
442 
443 		VkMemoryRequirements			memReqs				=
444 		{
445 			0,							// VkDeviceSize		size
446 			0,							// VkDeviceSize		alignment
447 			0,							// uint32_t			memoryTypeBits
448 		};
449 		deUint32						memoryTypeNdx		= 0;
450 		de::MovePtr<Allocation>			stagingVertexBufferMemory;
451 		de::MovePtr<Allocation>			stagingIndexBufferMemory;
452 		de::MovePtr<Allocation>			stagingUniformBufferMemory;
453 		de::MovePtr<Allocation>			stagingSboBufferMemory;
454 
455 		vk::Move<vk::VkDeviceMemory>	vertexBufferMemory;
456 		vk::Move<vk::VkDeviceMemory>	indexBufferMemory;
457 		vk::Move<vk::VkDeviceMemory>	uniformBufferMemory;
458 		vk::Move<vk::VkDeviceMemory>	sboBufferMemory;
459 		vk::Move<vk::VkDeviceMemory>	renderImageMemory;
460 		vk::Move<vk::VkDeviceMemory>	readImageMemory;
461 
462 		Move<VkRenderPass>				renderPass;
463 		Move<VkImage>					renderImage;
464 		Move<VkImage>					readImage;
465 
466 		Move<VkDescriptorSetLayout>		descriptorSetLayout;
467 		Move<VkDescriptorPool>			descriptorPool;
468 		Move<VkDescriptorSet>			descriptorSet;
469 
470 		Move<VkBuffer>					stagingVertexBuffer;
471 		Move<VkBuffer>					stagingUniformBuffer;
472 		Move<VkBuffer>					stagingIndexBuffer;
473 		Move<VkBuffer>					stagingSboBuffer;
474 
475 		Move<VkBuffer>					vertexBuffer;
476 		Move<VkBuffer>					indexBuffer;
477 		Move<VkBuffer>					uniformBuffer;
478 		Move<VkBuffer>					sboBuffer;
479 
480 		Move<VkPipeline>				pipeline;
481 		Move<VkPipelineLayout>			pipelineLayout;
482 
483 		Move<VkImageView>				colorAttView;
484 		Move<VkFramebuffer>				framebuffer;
485 		Move<VkCommandPool>				cmdPool;
486 		Move<VkCommandBuffer>			cmdBuffer;
487 
488 		VkMemoryDedicatedAllocateInfo	dedicatedAllocInfo =
489 		{
490 				VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO,		// sType
491 				DE_NULL,												// pNext
492 				DE_NULL,												// image
493 				DE_NULL													// buffer
494 		};
495 
496 		VkMemoryAllocateFlagsInfo		allocDeviceMaskInfo =
497 		{
498 			VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO,		// sType
499 			m_useDedicated ? &dedicatedAllocInfo : DE_NULL,		// pNext
500 			VK_MEMORY_ALLOCATE_DEVICE_MASK_BIT,					// flags
501 			allocDeviceMask,									// deviceMask
502 		};
503 
504 		VkMemoryAllocateInfo		allocInfo =
505 		{
506 			VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,			// sType
507 			&allocDeviceMaskInfo,							// pNext
508 			0u,												// allocationSize
509 			0u,												// memoryTypeIndex
510 		};
511 
512 		// create vertex buffers
513 		{
514 			const VkBufferCreateInfo	stagingVertexBufferParams =
515 			{
516 				VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,									// sType
517 				DE_NULL,																// pNext
518 				0u,																		// flags
519 				(VkDeviceSize)verticesSize,												// size
520 				VK_BUFFER_USAGE_TRANSFER_SRC_BIT,										// usage
521 				VK_SHARING_MODE_EXCLUSIVE,												// sharingMode
522 				1u,																		// queueFamilyIndexCount
523 				&queueFamilyIndex,														// pQueueFamilyIndices
524 			};
525 			stagingVertexBuffer = createBuffer(vk, *m_deviceGroup, &stagingVertexBufferParams);
526 			stagingVertexBufferMemory = memAlloc.allocate(getBufferMemoryRequirements(vk, *m_deviceGroup, *stagingVertexBuffer), MemoryRequirement::HostVisible);
527 			VK_CHECK(vk.bindBufferMemory(*m_deviceGroup, *stagingVertexBuffer, stagingVertexBufferMemory->getMemory(), stagingVertexBufferMemory->getOffset()));
528 
529 			void*	vertexBufPtr	= stagingVertexBufferMemory->getHostPtr();
530 			deMemcpy(vertexBufPtr, &vertices[0], verticesSize);
531 			flushAlloc(vk, *m_deviceGroup, *stagingVertexBufferMemory);
532 		}
533 
534 		{
535 			const VkBufferCreateInfo	vertexBufferParams =
536 			{
537 				VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,									// sType
538 				DE_NULL,																// pNext
539 				0u,																		// flags
540 				(VkDeviceSize)verticesSize,												// size
541 				VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,	// usage
542 				VK_SHARING_MODE_EXCLUSIVE,												// sharingMode
543 				1u,																		// queueFamilyIndexCount
544 				&queueFamilyIndex,														// pQueueFamilyIndices
545 			};
546 			vertexBuffer = createBuffer(vk, *m_deviceGroup, &vertexBufferParams);
547 
548 			memReqs = getBufferMemoryRequirements(vk, *m_deviceGroup, vertexBuffer.get());
549 			memoryTypeNdx = getMemoryIndex(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
550 
551 			dedicatedAllocInfo.buffer = vertexBuffer.get();
552 			allocInfo.allocationSize = memReqs.size;
553 			allocInfo.memoryTypeIndex = memoryTypeNdx;
554 			vertexBufferMemory = allocateMemory(vk, *m_deviceGroup, &allocInfo);
555 
556 			if (m_usePeerFetch && !isPeerFetchAllowed(memoryTypeNdx, firstDeviceID, secondDeviceID))
557 				TCU_THROW(NotSupportedError, "Peer fetch is not supported.");
558 
559 			// Bind vertex buffer
560 			if (m_usePeerFetch)
561 			{
562 				VkBindBufferMemoryDeviceGroupInfo	devGroupBindInfo =
563 				{
564 					VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_DEVICE_GROUP_INFO,		// sType
565 					DE_NULL,													// pNext
566 					m_physicalDeviceCount,										// deviceIndexCount
567 					&deviceIndices[0],											// pDeviceIndices
568 				};
569 
570 				VkBindBufferMemoryInfo				bindInfo =
571 				{
572 					VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_INFO,					// sType
573 					&devGroupBindInfo,											// pNext
574 					vertexBuffer.get(),											// buffer
575 					vertexBufferMemory.get(),									// memory
576 					0u,															// memoryOffset
577 				};
578 				VK_CHECK(vk.bindBufferMemory2(*m_deviceGroup, 1, &bindInfo));
579 			}
580 			else
581 				VK_CHECK(vk.bindBufferMemory(*m_deviceGroup, *vertexBuffer, vertexBufferMemory.get(), 0));
582 		}
583 
584 		// create index buffers
585 		{
586 			const VkBufferCreateInfo	stagingIndexBufferParams =
587 			{
588 				VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,									// sType
589 				DE_NULL,																// pNext
590 				0u,																		// flags
591 				(VkDeviceSize)indicesSize,												// size
592 				VK_BUFFER_USAGE_TRANSFER_SRC_BIT,										// usage
593 				VK_SHARING_MODE_EXCLUSIVE,												// sharingMode
594 				1u,																		// queueFamilyIndexCount
595 				&queueFamilyIndex,														// pQueueFamilyIndices
596 			};
597 			stagingIndexBuffer = createBuffer(vk, *m_deviceGroup, &stagingIndexBufferParams);
598 			stagingIndexBufferMemory = memAlloc.allocate(getBufferMemoryRequirements(vk, *m_deviceGroup, *stagingIndexBuffer), MemoryRequirement::HostVisible);
599 			VK_CHECK(vk.bindBufferMemory(*m_deviceGroup, *stagingIndexBuffer, stagingIndexBufferMemory->getMemory(), stagingIndexBufferMemory->getOffset()));
600 
601 			void*	indexBufPtr	= stagingIndexBufferMemory->getHostPtr();
602 			deMemcpy(indexBufPtr, &indices[0], indicesSize);
603 			flushAlloc(vk, *m_deviceGroup, *stagingIndexBufferMemory);
604 		}
605 
606 		{
607 			const VkBufferCreateInfo	indexBufferParams =
608 			{
609 				VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,									// sType
610 				DE_NULL,																// pNext
611 				0u,																		// flags
612 				(VkDeviceSize)indicesSize,												// size
613 				VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,	// usage
614 				VK_SHARING_MODE_EXCLUSIVE,												// sharingMode
615 				1u,																		// queueFamilyIndexCount
616 				&queueFamilyIndex,														// pQueueFamilyIndices
617 			};
618 			indexBuffer = createBuffer(vk, *m_deviceGroup, &indexBufferParams);
619 
620 			memReqs = getBufferMemoryRequirements(vk, *m_deviceGroup, indexBuffer.get());
621 			memoryTypeNdx = getMemoryIndex(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
622 
623 			dedicatedAllocInfo.buffer = indexBuffer.get();
624 			allocInfo.allocationSize = memReqs.size;
625 			allocInfo.memoryTypeIndex = memoryTypeNdx;
626 			indexBufferMemory = allocateMemory(vk, *m_deviceGroup, &allocInfo);
627 
628 			if (m_usePeerFetch && !isPeerFetchAllowed(memoryTypeNdx, firstDeviceID, secondDeviceID))
629 				TCU_THROW(NotSupportedError, "Peer fetch is not supported.");
630 
631 			// Bind index buffer
632 			if (m_usePeerFetch)
633 			{
634 				VkBindBufferMemoryDeviceGroupInfo	devGroupBindInfo =
635 				{
636 					VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_DEVICE_GROUP_INFO,		// sType
637 					DE_NULL,													// pNext
638 					m_physicalDeviceCount,										// deviceIndexCount
639 					&deviceIndices[0],											// pDeviceIndices
640 				};
641 
642 				VkBindBufferMemoryInfo				bindInfo =
643 				{
644 					VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_INFO,					// sType
645 					&devGroupBindInfo,											// pNext
646 					indexBuffer.get(),											// buffer
647 					indexBufferMemory.get(),									// memory
648 					0u,															// memoryOffset
649 				};
650 				VK_CHECK(vk.bindBufferMemory2(*m_deviceGroup, 1, &bindInfo));
651 			}
652 			else
653 				VK_CHECK(vk.bindBufferMemory(*m_deviceGroup, *indexBuffer, indexBufferMemory.get(), 0));
654 		}
655 
656 		// create uniform buffers
657 		{
658 			const VkBufferCreateInfo	stagingUniformBufferParams =
659 			{
660 				VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,									// sType
661 				DE_NULL,																// pNext
662 				0u,																		// flags
663 				(VkDeviceSize)sizeof(drawColor),												// size
664 				VK_BUFFER_USAGE_TRANSFER_SRC_BIT,										// usage
665 				VK_SHARING_MODE_EXCLUSIVE,												// sharingMode
666 				1u,																		// queueFamilyIndexCount
667 				&queueFamilyIndex,														// pQueueFamilyIndices
668 			};
669 			stagingUniformBuffer = createBuffer(vk, *m_deviceGroup, &stagingUniformBufferParams);
670 			stagingUniformBufferMemory = memAlloc.allocate(getBufferMemoryRequirements(vk, *m_deviceGroup, *stagingUniformBuffer), MemoryRequirement::HostVisible);
671 			VK_CHECK(vk.bindBufferMemory(*m_deviceGroup, *stagingUniformBuffer, stagingUniformBufferMemory->getMemory(), stagingUniformBufferMemory->getOffset()));
672 
673 			void*	uniformBufPtr	= stagingUniformBufferMemory->getHostPtr();
674 			deMemcpy(uniformBufPtr, &drawColor[0], sizeof(drawColor));
675 			flushAlloc(vk, *m_deviceGroup, *stagingUniformBufferMemory);
676 		}
677 
678 		{
679 			const VkBufferCreateInfo	uniformBufferParams =
680 			{
681 				VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,									// sType
682 				DE_NULL,																// pNext
683 				0u,																		// flags
684 				(VkDeviceSize)sizeof(drawColor),										// size
685 				VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,	// usage
686 				VK_SHARING_MODE_EXCLUSIVE,												// sharingMode
687 				1u,																		// queueFamilyIndexCount
688 				&queueFamilyIndex,														// pQueueFamilyIndices
689 			};
690 			uniformBuffer = createBuffer(vk, *m_deviceGroup, &uniformBufferParams);
691 
692 			memReqs = getBufferMemoryRequirements(vk, *m_deviceGroup, uniformBuffer.get());
693 			memoryTypeNdx = getMemoryIndex(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
694 
695 			dedicatedAllocInfo.buffer = uniformBuffer.get();
696 			allocInfo.allocationSize = memReqs.size;
697 			allocInfo.memoryTypeIndex = memoryTypeNdx;
698 			uniformBufferMemory = allocateMemory(vk, *m_deviceGroup, &allocInfo);
699 
700 			if (m_usePeerFetch && !isPeerFetchAllowed(memoryTypeNdx, firstDeviceID, secondDeviceID))
701 				TCU_THROW(NotSupportedError, "Peer fetch is not supported.");
702 
703 			if (m_usePeerFetch)
704 			{
705 				VkBindBufferMemoryDeviceGroupInfo	devGroupBindInfo =
706 				{
707 					VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_DEVICE_GROUP_INFO,		// sType
708 					DE_NULL,													// pNext
709 					m_physicalDeviceCount,										// deviceIndexCount
710 					&deviceIndices[0],											// pDeviceIndices
711 				};
712 
713 				VkBindBufferMemoryInfo				bindInfo =
714 				{
715 					VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_INFO,					// sType
716 					&devGroupBindInfo,											// pNext
717 					uniformBuffer.get(),										// buffer
718 					uniformBufferMemory.get(),									// memory
719 					0u,															// memoryOffset
720 				};
721 				VK_CHECK(vk.bindBufferMemory2(*m_deviceGroup, 1, &bindInfo));
722 			}
723 			else
724 				VK_CHECK(vk.bindBufferMemory(*m_deviceGroup, uniformBuffer.get(), uniformBufferMemory.get(), 0));
725 		}
726 
727 		// create SBO buffers
728 		{
729 			const VkBufferCreateInfo	stagingSboBufferParams =
730 			{
731 				VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,									// sType
732 				DE_NULL,																// pNext
733 				0u,																		// flags
734 				(VkDeviceSize)sizeof(tessLevel),										// size
735 				VK_BUFFER_USAGE_TRANSFER_SRC_BIT,										// usage
736 				VK_SHARING_MODE_EXCLUSIVE,												// sharingMode
737 				1u,																		// queueFamilyIndexCount
738 				&queueFamilyIndex,														// pQueueFamilyIndices
739 			};
740 			stagingSboBuffer = createBuffer(vk, *m_deviceGroup, &stagingSboBufferParams);
741 			stagingSboBufferMemory = memAlloc.allocate(getBufferMemoryRequirements(vk, *m_deviceGroup, *stagingSboBuffer), MemoryRequirement::HostVisible);
742 			VK_CHECK(vk.bindBufferMemory(*m_deviceGroup, *stagingSboBuffer, stagingSboBufferMemory->getMemory(), stagingSboBufferMemory->getOffset()));
743 
744 			void*	sboBufPtr	= stagingSboBufferMemory->getHostPtr();
745 			deMemcpy(sboBufPtr, &tessLevel, sizeof(tessLevel));
746 			flushAlloc(vk, *m_deviceGroup, *stagingSboBufferMemory);
747 		}
748 
749 		{
750 			const VkBufferCreateInfo	sboBufferParams =
751 			{
752 				VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,									// sType
753 				DE_NULL,																// pNext
754 				0u,																		// flags
755 				(VkDeviceSize)sizeof(tessLevel),										// size
756 				VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,	// usage
757 				VK_SHARING_MODE_EXCLUSIVE,												// sharingMode
758 				1u,																		// queueFamilyIndexCount
759 				&queueFamilyIndex,														// pQueueFamilyIndices
760 			};
761 			sboBuffer = createBuffer(vk, *m_deviceGroup, &sboBufferParams);
762 
763 			memReqs = getBufferMemoryRequirements(vk, *m_deviceGroup, sboBuffer.get());
764 			memoryTypeNdx = getMemoryIndex(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
765 
766 			dedicatedAllocInfo.buffer = sboBuffer.get();
767 			allocInfo.allocationSize = memReqs.size;
768 			allocInfo.memoryTypeIndex = memoryTypeNdx;
769 			sboBufferMemory = allocateMemory(vk, *m_deviceGroup, &allocInfo);
770 
771 			if (m_usePeerFetch && !isPeerFetchAllowed(memoryTypeNdx, firstDeviceID, secondDeviceID))
772 				TCU_THROW(NotSupportedError, "Peer fetch is not supported.");
773 
774 			if (m_usePeerFetch)
775 			{
776 				VkBindBufferMemoryDeviceGroupInfo	devGroupBindInfo =
777 				{
778 					VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_DEVICE_GROUP_INFO,		// sType
779 					DE_NULL,													// pNext
780 					m_physicalDeviceCount,										// deviceIndexCount
781 					&deviceIndices[0],											// pDeviceIndices
782 				};
783 
784 				VkBindBufferMemoryInfo				bindInfo =
785 				{
786 					VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_INFO,					// sType
787 					&devGroupBindInfo,											// pNext
788 					sboBuffer.get(),											// buffer
789 					sboBufferMemory.get(),										// memory
790 					0u,															// memoryOffset
791 				};
792 				VK_CHECK(vk.bindBufferMemory2(*m_deviceGroup, 1, &bindInfo));
793 			}
794 			else
795 				VK_CHECK(vk.bindBufferMemory(*m_deviceGroup, sboBuffer.get(), sboBufferMemory.get(), 0));
796 		}
797 
798 		// Create image resources
799 		// Use a consistent usage flag because of memory aliasing
800 		VkImageUsageFlags imageUsageFlag = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
801 		{
802 			// Check for SFR support
803 			VkImageFormatProperties properties;
804 			if ((m_testMode & TEST_MODE_SFR) && vki.getPhysicalDeviceImageFormatProperties(m_context.getPhysicalDevice(),
805 				colorFormat,															// format
806 				VK_IMAGE_TYPE_2D,														// type
807 				VK_IMAGE_TILING_OPTIMAL,												// tiling
808 				VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT,	// usage
809 				VK_IMAGE_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT,						// flags
810 				&properties) != VK_SUCCESS)												// properties
811 			{
812 				TCU_THROW(NotSupportedError, "Format not supported for SFR");
813 			}
814 
815 			VkImageCreateFlags	imageCreateFlags = VK_IMAGE_CREATE_ALIAS_BIT;	// The image objects alias same memory
816 			if ((m_testMode & TEST_MODE_SFR) && (m_physicalDeviceCount > 1))
817 			{
818 				imageCreateFlags |= VK_IMAGE_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT;
819 			}
820 
821 			const VkImageCreateInfo		imageParams =
822 			{
823 				VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,									// sType
824 				DE_NULL,																// pNext
825 				imageCreateFlags,														// flags
826 				VK_IMAGE_TYPE_2D,														// imageType
827 				colorFormat,															// format
828 				{ renderSize.x(), renderSize.y(), 1 },									// extent
829 				1u,																		// mipLevels
830 				1u,																		// arraySize
831 				VK_SAMPLE_COUNT_1_BIT,													// samples
832 				VK_IMAGE_TILING_OPTIMAL,												// tiling
833 				imageUsageFlag,															// usage
834 				VK_SHARING_MODE_EXCLUSIVE,												// sharingMode
835 				1u,																		// queueFamilyIndexCount
836 				&queueFamilyIndex,														// pQueueFamilyIndices
837 				VK_IMAGE_LAYOUT_UNDEFINED,												// initialLayout
838 			};
839 
840 			renderImage = createImage(vk, *m_deviceGroup, &imageParams);
841 			readImage = createImage(vk, *m_deviceGroup, &imageParams);
842 
843 			dedicatedAllocInfo.image = *renderImage;
844 			dedicatedAllocInfo.buffer = DE_NULL;
845 			memReqs = getImageMemoryRequirements(vk, *m_deviceGroup, renderImage.get());
846 			memoryTypeNdx = getMemoryIndex(memReqs.memoryTypeBits, m_useHostMemory ? 0 : VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
847 			allocInfo.allocationSize = memReqs.size;
848 			allocInfo.memoryTypeIndex = memoryTypeNdx;
849 			renderImageMemory = allocateMemory(vk, *m_deviceGroup, &allocInfo);
850 
851 			dedicatedAllocInfo.image = *readImage;
852 			dedicatedAllocInfo.buffer = DE_NULL;
853 			memReqs = getImageMemoryRequirements(vk, *m_deviceGroup, readImage.get());
854 			memoryTypeNdx = getMemoryIndex(memReqs.memoryTypeBits, m_useHostMemory ? 0 : VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
855 			allocInfo.allocationSize = memReqs.size;
856 			allocInfo.memoryTypeIndex = memoryTypeNdx;
857 			readImageMemory = allocateMemory(vk, *m_deviceGroup, &allocInfo);
858 		}
859 
860 		VK_CHECK(vk.bindImageMemory(*m_deviceGroup, *renderImage, renderImageMemory.get(), 0));
861 		VK_CHECK(vk.bindImageMemory(*m_deviceGroup, *readImage, readImageMemory.get(), 0));
862 
863 		// Create renderpass
864 		{
865 			const VkAttachmentDescription			colorAttachmentDescription			=
866 			{
867 				(VkAttachmentDescriptionFlags)0,				// VkAttachmentDescriptionFlags    flags
868 				colorFormat,									// VkFormat                        format
869 				VK_SAMPLE_COUNT_1_BIT,							// VkSampleCountFlagBits           samples
870 				VK_ATTACHMENT_LOAD_OP_CLEAR,					// VkAttachmentLoadOp              loadOp
871 				VK_ATTACHMENT_STORE_OP_STORE,					// VkAttachmentStoreOp             storeOp
872 				VK_ATTACHMENT_LOAD_OP_DONT_CARE,				// VkAttachmentLoadOp              stencilLoadOp
873 				VK_ATTACHMENT_STORE_OP_DONT_CARE,				// VkAttachmentStoreOp             stencilStoreOp
874 				VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,		// VkImageLayout                   initialLayout
875 				VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,		// VkImageLayout                   finalLayout
876 			};
877 
878 			const VkAttachmentReference				colorAttachmentRef					=
879 			{
880 				0u,											// deUint32         attachment
881 				VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL	// VkImageLayout    layout
882 			};
883 
884 			const VkSubpassDescription				subpassDescription					=
885 			{
886 				(VkSubpassDescriptionFlags)0,							// VkSubpassDescriptionFlags       flags
887 				VK_PIPELINE_BIND_POINT_GRAPHICS,						// VkPipelineBindPoint             pipelineBindPoint
888 				0u,														// deUint32                        inputAttachmentCount
889 				DE_NULL,												// const VkAttachmentReference*    pInputAttachments
890 				1u,														// deUint32                        colorAttachmentCount
891 				&colorAttachmentRef,									// const VkAttachmentReference*    pColorAttachments
892 				DE_NULL,												// const VkAttachmentReference*    pResolveAttachments
893 				DE_NULL,												// const VkAttachmentReference*    pDepthStencilAttachment
894 				0u,														// deUint32                        preserveAttachmentCount
895 				DE_NULL													// const deUint32*                 pPreserveAttachments
896 			};
897 
898 			const VkRenderPassCreateInfo			renderPassInfo						=
899 			{
900 				VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,									// VkStructureType                   sType
901 				DE_NULL,																	// const void*                       pNext
902 				(VkRenderPassCreateFlags)0,													// VkRenderPassCreateFlags           flags
903 				1,																			// deUint32                          attachmentCount
904 				&colorAttachmentDescription,												// const VkAttachmentDescription*    pAttachments
905 				1u,																			// deUint32                          subpassCount
906 				&subpassDescription,														// const VkSubpassDescription*       pSubpasses
907 				0u,																			// deUint32                          dependencyCount
908 				DE_NULL																		// const VkSubpassDependency*        pDependencies
909 			};
910 
911 			renderPass = createRenderPass(vk, *m_deviceGroup, &renderPassInfo, DE_NULL);
912 		}
913 
914 		// Create descriptors
915 		{
916 			vector<VkDescriptorSetLayoutBinding>	layoutBindings;
917 			vector<VkDescriptorPoolSize>			descriptorTypes;
918 			vector<VkWriteDescriptorSet>			writeDescritporSets;
919 
920 			const VkDescriptorSetLayoutBinding layoutBindingUBO =
921 			{
922 				0u,											// deUint32				binding;
923 				VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,			// VkDescriptorType		descriptorType;
924 				1u,											// deUint32				descriptorCount;
925 				VK_SHADER_STAGE_FRAGMENT_BIT,				// VkShaderStageFlags	stageFlags;
926 				DE_NULL										// const VkSampler*		pImmutableSamplers;
927 			};
928 			const VkDescriptorSetLayoutBinding layoutBindingSBO =
929 			{
930 				1u,											// deUint32				binding;
931 				VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,			// VkDescriptorType		descriptorType;
932 				1u,											// deUint32				descriptorCount;
933 				VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT,	// VkShaderStageFlags	stageFlags;
934 				DE_NULL										// const VkSampler*		pImmutableSamplers;
935 			};
936 
937 			layoutBindings.push_back(layoutBindingUBO);
938 			if (m_drawTessellatedSphere)
939 				layoutBindings.push_back(layoutBindingSBO);
940 
941 			const VkDescriptorSetLayoutCreateInfo	descriptorLayoutParams =
942 			{
943 				VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,	// VkStructureType						sType;
944 				DE_NULL,												// cost void*							pNext;
945 				(VkDescriptorSetLayoutCreateFlags)0,					// VkDescriptorSetLayoutCreateFlags		flags
946 				deUint32(layoutBindings.size()),						// deUint32								count;
947 				layoutBindings.data()									// const VkDescriptorSetLayoutBinding	pBinding;
948 			};
949 			descriptorSetLayout = createDescriptorSetLayout(vk, *m_deviceGroup, &descriptorLayoutParams);
950 
951 			const VkDescriptorPoolSize descriptorTypeUBO =
952 			{
953 				VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,		// VkDescriptorType		type;
954 				1										// deUint32				count;
955 			};
956 			const VkDescriptorPoolSize descriptorTypeSBO =
957 			{
958 				VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,		// VkDescriptorType		type;
959 				1										// deUint32				count;
960 			};
961 			descriptorTypes.push_back(descriptorTypeUBO);
962 			if (m_drawTessellatedSphere)
963 				descriptorTypes.push_back(descriptorTypeSBO);
964 
965 			const VkDescriptorPoolCreateInfo descriptorPoolParams =
966 			{
967 				VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,		// VkStructureType					sType;
968 				DE_NULL,											// void*							pNext;
969 				VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT,	// VkDescriptorPoolCreateFlags		flags;
970 				1u,													// deUint32							maxSets;
971 				deUint32(descriptorTypes.size()),					// deUint32							count;
972 				descriptorTypes.data()								// const VkDescriptorTypeCount*		pTypeCount
973 			};
974 			descriptorPool = createDescriptorPool(vk, *m_deviceGroup, &descriptorPoolParams);
975 
976 			const VkDescriptorSetAllocateInfo descriptorSetParams =
977 			{
978 				VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
979 				DE_NULL,
980 				*descriptorPool,
981 				1u,
982 				&descriptorSetLayout.get(),
983 			};
984 			descriptorSet = allocateDescriptorSet(vk, *m_deviceGroup, &descriptorSetParams);
985 
986 			const VkDescriptorBufferInfo uboDescriptorInfo =
987 			{
988 				uniformBuffer.get(),
989 				0,
990 				(VkDeviceSize)sizeof(drawColor)
991 			};
992 			const VkDescriptorBufferInfo sboDescriptorInfo =
993 			{
994 				sboBuffer.get(),
995 				0,
996 				(VkDeviceSize)sizeof(tessLevel)
997 			};
998 			const VkWriteDescriptorSet writeDescritporSetUBO =
999 			{
1000 				VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,		// VkStructureType			sType;
1001 				DE_NULL,									// const void*				pNext;
1002 				*descriptorSet,								// VkDescriptorSet			destSet;
1003 				0,											// deUint32					destBinding;
1004 				0,											// deUint32					destArrayElement;
1005 				1u,											// deUint32					count;
1006 				VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,			// VkDescriptorType			descriptorType;
1007 				(const VkDescriptorImageInfo*)DE_NULL,		// VkDescriptorImageInfo*	pImageInfo;
1008 				&uboDescriptorInfo,							// VkDescriptorBufferInfo*	pBufferInfo;
1009 				(const VkBufferView*)DE_NULL				// VkBufferView*			pTexelBufferView;
1010 			};
1011 
1012 			const VkWriteDescriptorSet writeDescritporSetSBO =
1013 			{
1014 				VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,		// VkStructureType			sType;
1015 				DE_NULL,									// const void*				pNext;
1016 				*descriptorSet,								// VkDescriptorSet			destSet;
1017 				1,											// deUint32					destBinding;
1018 				0,											// deUint32					destArrayElement;
1019 				1u,											// deUint32					count;
1020 				VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,			// VkDescriptorType			descriptorType;
1021 				(const VkDescriptorImageInfo*)DE_NULL,		// VkDescriptorImageInfo*	pImageInfo;
1022 				&sboDescriptorInfo,							// VkDescriptorBufferInfo*	pBufferInfo;
1023 				(const VkBufferView*)DE_NULL				// VkBufferView*			pTexelBufferView;
1024 			};
1025 			writeDescritporSets.push_back(writeDescritporSetUBO);
1026 			if (m_drawTessellatedSphere)
1027 				writeDescritporSets.push_back(writeDescritporSetSBO);
1028 
1029 			vk.updateDescriptorSets(*m_deviceGroup, deUint32(writeDescritporSets.size()), writeDescritporSets.data(), 0u, DE_NULL);
1030 		}
1031 
1032 		// Create Pipeline
1033 		{
1034 			Move<VkShaderModule>							vertShaderModule;
1035 			Move<VkShaderModule>							tcssShaderModule;
1036 			Move<VkShaderModule>							tessShaderModule;
1037 			Move<VkShaderModule>							fragShaderModule;
1038 
1039 			const VkDescriptorSetLayout						descset					= descriptorSetLayout.get();
1040 			const VkPipelineLayoutCreateInfo				pipelineLayoutParams	=
1041 			{
1042 				VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,			// sType
1043 				DE_NULL,												// pNext
1044 				(vk::VkPipelineLayoutCreateFlags)0,						// flags
1045 				1u,														// setLayoutCount
1046 				&descset,												// pSetLayouts
1047 				0u,														// pushConstantRangeCount
1048 				DE_NULL,												// pPushConstantRanges
1049 			};
1050 			pipelineLayout = createPipelineLayout(vk, *m_deviceGroup, &pipelineLayoutParams);
1051 
1052 			// Shaders
1053 			vertShaderModule = createShaderModule(vk, *m_deviceGroup, m_context.getBinaryCollection().get("vert"), 0);
1054 			fragShaderModule = createShaderModule(vk, *m_deviceGroup, m_context.getBinaryCollection().get("frag"), 0);
1055 
1056 			if (m_drawTessellatedSphere)
1057 			{
1058 				tcssShaderModule = createShaderModule(vk, *m_deviceGroup, m_context.getBinaryCollection().get("tesc"), 0);
1059 				tessShaderModule = createShaderModule(vk, *m_deviceGroup, m_context.getBinaryCollection().get("tese"), 0);
1060 			}
1061 
1062 			const std::vector<VkViewport>					viewports				(1, makeViewport(renderSize));
1063 			const std::vector<VkRect2D>						scissors				(1, makeRect2D(renderSize));
1064 
1065 			const VkPipelineRasterizationStateCreateInfo	rasterParams			=
1066 			{
1067 				VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,			// sType
1068 				DE_NULL,															// pNext
1069 				0u,																	// flags
1070 				VK_FALSE,															// depthClampEnable
1071 				VK_FALSE,															// rasterizerDiscardEnable
1072 				m_fillModeNonSolid ? VK_POLYGON_MODE_LINE : VK_POLYGON_MODE_FILL,	// polygonMode
1073 				VK_CULL_MODE_NONE,													// cullMode
1074 				VK_FRONT_FACE_COUNTER_CLOCKWISE,									// frontFace
1075 				VK_FALSE,															// depthBiasEnable
1076 				0.0f,																// depthBiasConstantFactor
1077 				0.0f,																// depthBiasClamp
1078 				0.0f,																// depthBiasSlopeFactor
1079 				1.0f,																// lineWidth
1080 			};
1081 
1082 			const VkPrimitiveTopology						topology				= m_drawTessellatedSphere ? VK_PRIMITIVE_TOPOLOGY_PATCH_LIST : VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
1083 
1084 			pipeline = makeGraphicsPipeline(vk,														// const DeviceInterface&                        vk
1085 											*m_deviceGroup,											// const VkDevice                                device
1086 											*pipelineLayout,										// const VkPipelineLayout                        pipelineLayout
1087 											*vertShaderModule,										// const VkShaderModule                          vertexShaderModule
1088 											m_drawTessellatedSphere ? *tcssShaderModule : DE_NULL,	// const VkShaderModule                          tessellationControlModule,
1089 											m_drawTessellatedSphere ? *tessShaderModule : DE_NULL,	// const VkShaderModule                          tessellationEvalModule,
1090 											DE_NULL,												// const VkShaderModule                          geometryShaderModule
1091 											*fragShaderModule,										// const VkShaderModule                          fragmentShaderModule
1092 											*renderPass,											// const VkRenderPass                            renderPass
1093 											viewports,												// const std::vector<VkViewport>&                viewports
1094 											scissors,												// const std::vector<VkRect2D>&                  scissors
1095 											topology,												// const VkPrimitiveTopology                     topology
1096 											0u,														// const deUint32                                subpass
1097 											3u,														// const deUint32                                patchControlPoints
1098 											DE_NULL,												// const VkPipelineVertexInputStateCreateInfo*   vertexInputStateCreateInfo
1099 											&rasterParams);											// const VkPipelineRasterizationStateCreateInfo* rasterizationStateCreateInfo
1100 		}
1101 
1102 		// Create Framebuffer
1103 		{
1104 			const VkImageViewCreateInfo				colorAttViewParams =
1105 			{
1106 				VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,		// sType
1107 				DE_NULL,										// pNext
1108 				0u,												// flags
1109 				*renderImage,									// image
1110 				VK_IMAGE_VIEW_TYPE_2D,							// viewType
1111 				colorFormat,									// format
1112 				{
1113 					VK_COMPONENT_SWIZZLE_R,
1114 					VK_COMPONENT_SWIZZLE_G,
1115 					VK_COMPONENT_SWIZZLE_B,
1116 					VK_COMPONENT_SWIZZLE_A
1117 				},												// components
1118 				{
1119 					VK_IMAGE_ASPECT_COLOR_BIT,					// aspectMask
1120 					0u,											// baseMipLevel
1121 					1u,											// levelCount
1122 					0u,											// baseArrayLayer
1123 					1u,											// layerCount
1124 				},												// subresourceRange
1125 			};
1126 			colorAttView = createImageView(vk, *m_deviceGroup, &colorAttViewParams);
1127 
1128 			const VkFramebufferCreateInfo			framebufferParams =
1129 			{
1130 				VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,				// sType
1131 				DE_NULL,												// pNext
1132 				0u,														// flags
1133 				*renderPass,											// renderPass
1134 				1u,														// attachmentCount
1135 				&*colorAttView,											// pAttachments
1136 				renderSize.x(),											// width
1137 				renderSize.y(),											// height
1138 				1u,														// layers
1139 			};
1140 			framebuffer = createFramebuffer(vk, *m_deviceGroup, &framebufferParams);
1141 		}
1142 
1143 		// Create Command buffer
1144 		{
1145 			const VkCommandPoolCreateInfo			cmdPoolParams =
1146 			{
1147 				VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,					// sType
1148 				DE_NULL,													// pNext
1149 				VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,			// flags
1150 				queueFamilyIndex,											// queueFamilyIndex
1151 			};
1152 			cmdPool = createCommandPool(vk, *m_deviceGroup, &cmdPoolParams);
1153 
1154 			const VkCommandBufferAllocateInfo		cmdBufParams =
1155 			{
1156 				VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,			// sType
1157 				DE_NULL,												// pNext
1158 				*cmdPool,												// pool
1159 				VK_COMMAND_BUFFER_LEVEL_PRIMARY,						// level
1160 				1u,														// bufferCount
1161 			};
1162 			cmdBuffer = allocateCommandBuffer(vk, *m_deviceGroup, &cmdBufParams);
1163 		}
1164 
1165 		// Do a layout transition for renderImage
1166 		{
1167 			beginCommandBuffer(vk, *cmdBuffer);
1168 			const VkImageMemoryBarrier	colorAttBarrier =
1169 			{
1170 				VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,		// sType
1171 				DE_NULL,									// pNext
1172 				0u,											// srcAccessMask
1173 				(VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
1174 				VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT),		// dstAccessMask
1175 				VK_IMAGE_LAYOUT_UNDEFINED,					// oldLayout
1176 				VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,	// newLayout
1177 				queueFamilyIndex,							// srcQueueFamilyIndex
1178 				queueFamilyIndex,							// dstQueueFamilyIndex
1179 				*renderImage,								// image
1180 				{
1181 					VK_IMAGE_ASPECT_COLOR_BIT,				// aspectMask
1182 					0u,										// baseMipLevel
1183 					1u,										// levelCount
1184 					0u,										// baseArrayLayer
1185 					1u,										// layerCount
1186 				}											// subresourceRange
1187 			};
1188 			vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, (VkDependencyFlags)0, 0, (const VkMemoryBarrier*)DE_NULL, 0, (const VkBufferMemoryBarrier*)DE_NULL, 1, &colorAttBarrier);
1189 
1190 			endCommandBuffer(vk, *cmdBuffer);
1191 			const deUint32 deviceMask = (1 << firstDeviceID) | (1 << secondDeviceID);
1192 			submitBufferAndWaitForIdle(vk, cmdBuffer.get(), deviceMask);
1193 			m_context.resetCommandPoolForVKSC(*m_deviceGroup, *cmdPool);
1194 		}
1195 
1196 		// Bind renderImage across devices for SFR
1197 		if ((m_testMode & TEST_MODE_SFR) && (m_physicalDeviceCount > 1))
1198 		{
1199 			if (m_usePeerFetch && !isPeerFetchAllowed(memoryTypeNdx, firstDeviceID, secondDeviceID))
1200 				TCU_THROW(NotSupportedError, "Peer texture reads is not supported.");
1201 
1202 			// Check if peer memory can be used as source of a copy command in case of SFR bindings, always allowed in case of 1 device
1203 			VkPeerMemoryFeatureFlags				peerMemFeatures;
1204 			const VkPhysicalDeviceMemoryProperties	deviceMemProps = getPhysicalDeviceMemoryProperties(vki, m_physicalDevices[secondDeviceID]);
1205 			vk.getDeviceGroupPeerMemoryFeatures(*m_deviceGroup, deviceMemProps.memoryTypes[memoryTypeNdx].heapIndex, firstDeviceID, secondDeviceID, &peerMemFeatures);
1206 			isPeerMemAsCopySrcAllowed = (peerMemFeatures & VK_PEER_MEMORY_FEATURE_COPY_SRC_BIT);
1207 
1208 			VkRect2D zeroRect = {
1209 				{
1210 					0,	//	VkOffset2D.x
1211 					0,	//	VkOffset2D.x
1212 				},
1213 				{
1214 					0,	//	VkExtent2D.x
1215 					0,	//	VkExtent2D.x
1216 				}
1217 			};
1218 			vector<VkRect2D> sfrRects;
1219 			for (deUint32 i = 0; i < m_physicalDeviceCount*m_physicalDeviceCount; i++)
1220 				sfrRects.push_back(zeroRect);
1221 
1222 			if (m_physicalDeviceCount == 1u)
1223 			{
1224 				sfrRects[0].extent.width	= (deInt32)renderSize.x();
1225 				sfrRects[0].extent.height	= (deInt32)renderSize.y();
1226 			}
1227 			else
1228 			{
1229 				// Split into 2 vertical halves
1230 				sfrRects[firstDeviceID * m_physicalDeviceCount + firstDeviceID].extent.width	= (deInt32)renderSize.x() / 2;
1231 				sfrRects[firstDeviceID * m_physicalDeviceCount + firstDeviceID].extent.height	= (deInt32)renderSize.y();
1232 				sfrRects[firstDeviceID * m_physicalDeviceCount + secondDeviceID]				= sfrRects[firstDeviceID * m_physicalDeviceCount + firstDeviceID];
1233 				sfrRects[firstDeviceID * m_physicalDeviceCount + secondDeviceID].offset.x		= (deInt32)renderSize.x() / 2;
1234 				sfrRects[secondDeviceID * m_physicalDeviceCount + firstDeviceID]				= sfrRects[firstDeviceID * m_physicalDeviceCount + firstDeviceID];
1235 				sfrRects[secondDeviceID * m_physicalDeviceCount + secondDeviceID]				= sfrRects[firstDeviceID * m_physicalDeviceCount + secondDeviceID];
1236 			}
1237 
1238 			VkBindImageMemoryDeviceGroupInfo	devGroupBindInfo =
1239 			{
1240 				VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_DEVICE_GROUP_INFO,		// sType
1241 				DE_NULL,													// pNext
1242 				0u,															// deviceIndexCount
1243 				DE_NULL,													// pDeviceIndices
1244 				m_physicalDeviceCount*m_physicalDeviceCount,				// SFRRectCount
1245 				&sfrRects[0],												// pSFRRects
1246 			};
1247 
1248 			VkBindImageMemoryInfo				bindInfo =
1249 			{
1250 				VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO,					// sType
1251 				&devGroupBindInfo,											// pNext
1252 				*renderImage,												// image
1253 				renderImageMemory.get(),									// memory
1254 				0u,															// memoryOffset
1255 			};
1256 			VK_CHECK(vk.bindImageMemory2(*m_deviceGroup, 1, &bindInfo));
1257 		}
1258 
1259 		// Begin recording
1260 		beginCommandBuffer(vk, *cmdBuffer);
1261 
1262 		// Update buffers
1263 		{
1264 			const VkBufferMemoryBarrier		stagingVertexBufferUpdateBarrier =
1265 			{
1266 				VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,	// VkStructureType	sType;
1267 				DE_NULL,									// const void*		pNext;
1268 				VK_ACCESS_HOST_WRITE_BIT,					// VkAccessFlags	srcAccessMask;
1269 				VK_ACCESS_TRANSFER_READ_BIT,				// VkAccessFlags	dstAccessMask;
1270 				VK_QUEUE_FAMILY_IGNORED,					// deUint32			srcQueueFamilyIndex;
1271 				VK_QUEUE_FAMILY_IGNORED,					// deUint32			dstQueueFamilyIndex;
1272 				stagingVertexBuffer.get(),					// VkBuffer			buffer;
1273 				0u,											// VkDeviceSize		offset;
1274 				verticesSize								// VkDeviceSize		size;
1275 			};
1276 
1277 			const VkBufferMemoryBarrier		vertexBufferUpdateBarrier =
1278 			{
1279 				VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,	// VkStructureType	sType;
1280 				DE_NULL,									// const void*		pNext;
1281 				VK_ACCESS_TRANSFER_WRITE_BIT,				// VkAccessFlags	srcAccessMask;
1282 				VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT,		// VkAccessFlags	dstAccessMask;
1283 				VK_QUEUE_FAMILY_IGNORED,					// deUint32			srcQueueFamilyIndex;
1284 				VK_QUEUE_FAMILY_IGNORED,					// deUint32			dstQueueFamilyIndex;
1285 				vertexBuffer.get(),							// VkBuffer			buffer;
1286 				0u,											// VkDeviceSize		offset;
1287 				verticesSize								// VkDeviceSize		size;
1288 			};
1289 
1290 			const VkBufferMemoryBarrier		stagingIndexBufferUpdateBarrier =
1291 			{
1292 				VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,	// VkStructureType	sType;
1293 				DE_NULL,									// const void*		pNext;
1294 				VK_ACCESS_HOST_WRITE_BIT,					// VkAccessFlags	srcAccessMask;
1295 				VK_ACCESS_TRANSFER_READ_BIT,				// VkAccessFlags	dstAccessMask;
1296 				VK_QUEUE_FAMILY_IGNORED,					// deUint32			srcQueueFamilyIndex;
1297 				VK_QUEUE_FAMILY_IGNORED,					// deUint32			dstQueueFamilyIndex;
1298 				stagingIndexBuffer.get(),					// VkBuffer			buffer;
1299 				0u,											// VkDeviceSize		offset;
1300 				indicesSize									// VkDeviceSize		size;
1301 			};
1302 
1303 			const VkBufferMemoryBarrier		indexBufferUpdateBarrier =
1304 			{
1305 				VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,	// VkStructureType	sType;
1306 				DE_NULL,									// const void*		pNext;
1307 				VK_ACCESS_TRANSFER_WRITE_BIT,				// VkAccessFlags	srcAccessMask;
1308 				VK_ACCESS_INDEX_READ_BIT,					// VkAccessFlags	dstAccessMask;
1309 				VK_QUEUE_FAMILY_IGNORED,					// deUint32			srcQueueFamilyIndex;
1310 				VK_QUEUE_FAMILY_IGNORED,					// deUint32			dstQueueFamilyIndex;
1311 				indexBuffer.get(),							// VkBuffer			buffer;
1312 				0u,											// VkDeviceSize		offset;
1313 				indicesSize									// VkDeviceSize		size;
1314 			};
1315 
1316 			const VkBufferMemoryBarrier		stagingUboBufferUpdateBarrier =
1317 			{
1318 				VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,	// VkStructureType	sType;
1319 				DE_NULL,									// const void*		pNext;
1320 				VK_ACCESS_HOST_WRITE_BIT,					// VkAccessFlags	srcAccessMask;
1321 				VK_ACCESS_TRANSFER_READ_BIT,				// VkAccessFlags	dstAccessMask;
1322 				VK_QUEUE_FAMILY_IGNORED,					// deUint32			srcQueueFamilyIndex;
1323 				VK_QUEUE_FAMILY_IGNORED,					// deUint32			dstQueueFamilyIndex;
1324 				stagingUniformBuffer.get(),					// VkBuffer			buffer;
1325 				0u,											// VkDeviceSize		offset;
1326 				indicesSize									// VkDeviceSize		size;
1327 			};
1328 
1329 			const VkBufferMemoryBarrier		uboUpdateBarrier =
1330 			{
1331 				VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,	// VkStructureType	sType;
1332 				DE_NULL,									// const void*		pNext;
1333 				VK_ACCESS_TRANSFER_WRITE_BIT,				// VkAccessFlags	srcAccessMask;
1334 				VK_ACCESS_UNIFORM_READ_BIT,					// VkAccessFlags	dstAccessMask;
1335 				VK_QUEUE_FAMILY_IGNORED,					// deUint32			srcQueueFamilyIndex;
1336 				VK_QUEUE_FAMILY_IGNORED,					// deUint32			dstQueueFamilyIndex;
1337 				uniformBuffer.get(),						// VkBuffer			buffer;
1338 				0u,											// VkDeviceSize		offset;
1339 				sizeof(drawColor)							// VkDeviceSize		size;
1340 			};
1341 
1342 
1343 			vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, (VkDependencyFlags)0, 0, (const VkMemoryBarrier*)DE_NULL, 1, &stagingVertexBufferUpdateBarrier, 0, (const VkImageMemoryBarrier*)DE_NULL);
1344 			VkBufferCopy	vertexBufferCopy	= { 0u, 0u, verticesSize };
1345 			vk.cmdCopyBuffer(*cmdBuffer, stagingVertexBuffer.get(), vertexBuffer.get(), 1u, &vertexBufferCopy);
1346 			vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, (VkDependencyFlags)0, 0, (const VkMemoryBarrier*)DE_NULL, 1, &vertexBufferUpdateBarrier, 0, (const VkImageMemoryBarrier*)DE_NULL);
1347 
1348 			vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, (VkDependencyFlags)0, 0, (const VkMemoryBarrier*)DE_NULL, 1, &stagingIndexBufferUpdateBarrier, 0, (const VkImageMemoryBarrier*)DE_NULL);
1349 			VkBufferCopy	indexBufferCopy	= { 0u, 0u, indicesSize };
1350 			vk.cmdCopyBuffer(*cmdBuffer, stagingIndexBuffer.get(), indexBuffer.get(), 1u, &indexBufferCopy);
1351 			vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, (VkDependencyFlags)0, 0, (const VkMemoryBarrier*)DE_NULL, 1, &indexBufferUpdateBarrier, 0, (const VkImageMemoryBarrier*)DE_NULL);
1352 
1353 			vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, (VkDependencyFlags)0, 0, (const VkMemoryBarrier*)DE_NULL, 1, &stagingUboBufferUpdateBarrier, 0, (const VkImageMemoryBarrier*)DE_NULL);
1354 			VkBufferCopy	uboBufferCopy	= { 0u, 0u, sizeof(drawColor) };
1355 			vk.cmdCopyBuffer(*cmdBuffer, stagingUniformBuffer.get(), uniformBuffer.get(), 1u, &uboBufferCopy);
1356 			vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, (VkDependencyFlags)0, 0, (const VkMemoryBarrier*)DE_NULL, 1, &uboUpdateBarrier, 0, (const VkImageMemoryBarrier*)DE_NULL);
1357 
1358 			if (m_drawTessellatedSphere)
1359 			{
1360 				const VkBufferMemoryBarrier		stagingsboUpdateBarrier =
1361 				{
1362 					VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,	// VkStructureType	sType;
1363 					DE_NULL,									// const void*		pNext;
1364 					VK_ACCESS_HOST_WRITE_BIT,					// VkAccessFlags	srcAccessMask;
1365 					VK_ACCESS_TRANSFER_READ_BIT,				// VkAccessFlags	dstAccessMask;
1366 					VK_QUEUE_FAMILY_IGNORED,					// deUint32			srcQueueFamilyIndex;
1367 					VK_QUEUE_FAMILY_IGNORED,					// deUint32			dstQueueFamilyIndex;
1368 					stagingSboBuffer.get(),						// VkBuffer			buffer;
1369 					0u,											// VkDeviceSize		offset;
1370 					sizeof(tessLevel)							// VkDeviceSize		size;
1371 				};
1372 
1373 				const VkBufferMemoryBarrier		sboUpdateBarrier =
1374 				{
1375 					VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,	// VkStructureType	sType;
1376 					DE_NULL,									// const void*		pNext;
1377 					VK_ACCESS_TRANSFER_WRITE_BIT,				// VkAccessFlags	srcAccessMask;
1378 					VK_ACCESS_SHADER_READ_BIT,					// VkAccessFlags	dstAccessMask;
1379 					VK_QUEUE_FAMILY_IGNORED,					// deUint32			srcQueueFamilyIndex;
1380 					VK_QUEUE_FAMILY_IGNORED,					// deUint32			dstQueueFamilyIndex;
1381 					sboBuffer.get(),							// VkBuffer			buffer;
1382 					0u,											// VkDeviceSize		offset;
1383 					sizeof(tessLevel)							// VkDeviceSize		size;
1384 				};
1385 
1386 				vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, (VkDependencyFlags)0, 0, (const VkMemoryBarrier*)DE_NULL, 1, &stagingsboUpdateBarrier, 0, (const VkImageMemoryBarrier*)DE_NULL);
1387 				VkBufferCopy	sboBufferCopy	= { 0u, 0u, sizeof(tessLevel) };
1388 				vk.cmdCopyBuffer(*cmdBuffer, stagingSboBuffer.get(), sboBuffer.get(), 1u, &sboBufferCopy);
1389 				vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT, (VkDependencyFlags)0, 0, (const VkMemoryBarrier*)DE_NULL, 1, &sboUpdateBarrier, 0, (const VkImageMemoryBarrier*)DE_NULL);
1390 			}
1391 
1392 			vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline);
1393 			vk.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipelineLayout, 0u, 1, &*descriptorSet, 0u, DE_NULL);
1394 			{
1395 				const VkDeviceSize bindingOffset = 0;
1396 				vk.cmdBindVertexBuffers(*cmdBuffer, 0u, 1u, &vertexBuffer.get(), &bindingOffset);
1397 				vk.cmdBindIndexBuffer(*cmdBuffer, *indexBuffer, 0, VK_INDEX_TYPE_UINT32);
1398 			}
1399 		}
1400 
1401 		// Begin renderpass
1402 		{
1403 			const VkClearValue clearValue = makeClearValueColorF32(
1404 				clearColor[0],
1405 				clearColor[1],
1406 				clearColor[2],
1407 				clearColor[3]);
1408 
1409 			VkRect2D zeroRect = { { 0, 0, },{ 0, 0, } };
1410 			vector<VkRect2D> renderAreas;
1411 			for (deUint32 i = 0; i < m_physicalDeviceCount; i++)
1412 				renderAreas.push_back(zeroRect);
1413 
1414 			// Render completely if there is only 1 device
1415 			if (m_physicalDeviceCount == 1u)
1416 			{
1417 				renderAreas[0].extent.width = (deInt32)renderSize.x();
1418 				renderAreas[0].extent.height = (deInt32)renderSize.y();
1419 			}
1420 			else
1421 			{
1422 				// Split into 2 vertical halves
1423 				renderAreas[firstDeviceID].extent.width		= (deInt32)renderSize.x() / 2;
1424 				renderAreas[firstDeviceID].extent.height	= (deInt32)renderSize.y();
1425 				renderAreas[secondDeviceID]					= renderAreas[firstDeviceID];
1426 				renderAreas[secondDeviceID].offset.x		= (deInt32)renderSize.x() / 2;
1427 			}
1428 
1429 			const VkDeviceGroupRenderPassBeginInfo deviceGroupRPBeginInfo =
1430 			{
1431 				VK_STRUCTURE_TYPE_DEVICE_GROUP_RENDER_PASS_BEGIN_INFO,
1432 				DE_NULL,
1433 				(deUint32)((1 << m_physicalDeviceCount) - 1),
1434 				m_physicalDeviceCount,
1435 				&renderAreas[0]
1436 			};
1437 
1438 			const VkRenderPassBeginInfo	passBeginParams =
1439 			{
1440 				VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,							// sType
1441 				(m_testMode & TEST_MODE_SFR) ? &deviceGroupRPBeginInfo : DE_NULL,	// pNext
1442 				*renderPass,														// renderPass
1443 				*framebuffer,														// framebuffer
1444 				{
1445 					{ 0, 0 },
1446 					{ renderSize.x(), renderSize.y() }
1447 				},																// renderArea
1448 				1u,																// clearValueCount
1449 				&clearValue,													// pClearValues
1450 			};
1451 			vk.cmdBeginRenderPass(*cmdBuffer, &passBeginParams, VK_SUBPASS_CONTENTS_INLINE);
1452 		}
1453 
1454 		// Draw
1455 		if (m_testMode & TEST_MODE_AFR)
1456 		{
1457 			vk.cmdSetDeviceMask(*cmdBuffer, 1 << secondDeviceID);
1458 			vk.cmdDrawIndexed(*cmdBuffer, numIndices, 1u, 0, 0, 0);
1459 
1460 		}
1461 		else
1462 		{
1463 			vk.cmdSetDeviceMask(*cmdBuffer, ((1 << firstDeviceID) | (1 << secondDeviceID)));
1464 			vk.cmdDrawIndexed(*cmdBuffer, numIndices, 1u, 0, 0, 0);
1465 		}
1466 		endRenderPass(vk, *cmdBuffer);
1467 
1468 		// Change image layout for copy
1469 		{
1470 			const VkImageMemoryBarrier	renderFinishBarrier =
1471 			{
1472 				VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,		// sType
1473 				DE_NULL,									// pNext
1474 				VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,		// outputMask
1475 				VK_ACCESS_TRANSFER_READ_BIT,				// inputMask
1476 				VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,	// oldLayout
1477 				VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,		// newLayout
1478 				queueFamilyIndex,							// srcQueueFamilyIndex
1479 				queueFamilyIndex,							// dstQueueFamilyIndex
1480 				*renderImage,								// image
1481 				{
1482 					VK_IMAGE_ASPECT_COLOR_BIT,				// aspectMask
1483 					0u,										// baseMipLevel
1484 					1u,										// mipLevels
1485 					0u,										// baseArraySlice
1486 					1u,										// arraySize
1487 				}											// subresourceRange
1488 			};
1489 			vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, (VkDependencyFlags)0, 0, (const VkMemoryBarrier*)DE_NULL, 0, (const VkBufferMemoryBarrier*)DE_NULL, 1, &renderFinishBarrier);
1490 		}
1491 
1492 		endCommandBuffer(vk, *cmdBuffer);
1493 
1494 		// Submit & wait for completion
1495 		{
1496 			const deUint32 deviceMask = (1 << firstDeviceID) | (1 << secondDeviceID);
1497 			submitBufferAndWaitForIdle(vk, cmdBuffer.get(), deviceMask);
1498 			m_context.resetCommandPoolForVKSC(*m_deviceGroup, *cmdPool);
1499 		}
1500 
1501 		// Copy image from secondDeviceID in case of AFR and SFR(only if Peer memory as copy source is not allowed)
1502 		if ((m_physicalDeviceCount > 1) && ((m_testMode & TEST_MODE_AFR) || (!isPeerMemAsCopySrcAllowed)))
1503 		{
1504 			Move<VkImage>			peerImage;
1505 
1506 			// Create and bind peer image
1507 			{
1508 				const VkImageCreateInfo					peerImageParams =
1509 				{
1510 					VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,									// sType
1511 					DE_NULL,																// pNext
1512 					VK_IMAGE_CREATE_ALIAS_BIT,												// flags
1513 					VK_IMAGE_TYPE_2D,														// imageType
1514 					colorFormat,															// format
1515 					{ renderSize.x(), renderSize.y(), 1 },									// extent
1516 					1u,																		// mipLevels
1517 					1u,																		// arraySize
1518 					VK_SAMPLE_COUNT_1_BIT,													// samples
1519 					VK_IMAGE_TILING_OPTIMAL,												// tiling
1520 					imageUsageFlag,															// usage
1521 					VK_SHARING_MODE_EXCLUSIVE,												// sharingMode
1522 					1u,																		// queueFamilyIndexCount
1523 					&queueFamilyIndex,														// pQueueFamilyIndices
1524 					VK_IMAGE_LAYOUT_UNDEFINED,												// initialLayout
1525 				};
1526 				peerImage = createImage(vk, *m_deviceGroup, &peerImageParams);
1527 
1528 				VkBindImageMemoryDeviceGroupInfo	devGroupBindInfo =
1529 				{
1530 					VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_DEVICE_GROUP_INFO,		// sType
1531 					DE_NULL,													// pNext
1532 					m_physicalDeviceCount,										// deviceIndexCount
1533 					&deviceIndices[0],											// pDeviceIndices
1534 					0u,															// SFRRectCount
1535 					DE_NULL,													// pSFRRects
1536 				};
1537 
1538 				VkBindImageMemoryInfo				bindInfo =
1539 				{
1540 					VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO,					// sType
1541 					&devGroupBindInfo,											// pNext
1542 					peerImage.get(),											// image
1543 					renderImageMemory.get(),									// memory
1544 					0u,															// memoryOffset
1545 				};
1546 				VK_CHECK(vk.bindImageMemory2(*m_deviceGroup, 1, &bindInfo));
1547 			}
1548 
1549 			// Copy peer image (only needed in SFR case when peer memory as copy source is not allowed)
1550 			{
1551 				// Change layout on firstDeviceID
1552 				{
1553 					const VkImageMemoryBarrier	preCopyBarrier =
1554 					{
1555 						VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,		// VkStructureType		 sType;
1556 						DE_NULL,									// const void*			 pNext;
1557 						0,											// VkAccessFlags		 srcAccessMask;
1558 						VK_ACCESS_TRANSFER_WRITE_BIT,				// VkAccessFlags		 dstAccessMask;
1559 						VK_IMAGE_LAYOUT_UNDEFINED,					// VkImageLayout		 oldLayout;
1560 						VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,		// VkImageLayout		 newLayout;
1561 						VK_QUEUE_FAMILY_IGNORED,					// deUint32				 srcQueueFamilyIndex;
1562 						VK_QUEUE_FAMILY_IGNORED,					// deUint32				 dstQueueFamilyIndex;
1563 						*renderImage,								// VkImage				 image;
1564 						{											// VkImageSubresourceRange subresourceRange;
1565 							VK_IMAGE_ASPECT_COLOR_BIT,				// VkImageAspectFlags	 aspectMask;
1566 							0u,										// deUint32				 baseMipLevel;
1567 							1u,										// deUint32				 mipLevels;
1568 							0u,										// deUint32				 baseArraySlice;
1569 							1u										// deUint32				 arraySize;
1570 						}
1571 					};
1572 
1573 					beginCommandBuffer(vk, *cmdBuffer);
1574 					vk.cmdSetDeviceMask(*cmdBuffer, 1 << firstDeviceID);
1575 					vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, (VkDependencyFlags)0, 0, (const VkMemoryBarrier*)DE_NULL, 0, (const VkBufferMemoryBarrier*)DE_NULL, 1u, &preCopyBarrier);
1576 					endCommandBuffer(vk, *cmdBuffer);
1577 
1578 					const deUint32 deviceMask = 1 << firstDeviceID;
1579 					submitBufferAndWaitForIdle(vk, cmdBuffer.get(), deviceMask);
1580 					m_context.resetCommandPoolForVKSC(*m_deviceGroup, *cmdPool);
1581 				}
1582 
1583 				// Copy Image from secondDeviceID to firstDeviceID
1584 				{
1585 					// AFR: Copy entire image from secondDeviceID
1586 					// SFR: Copy the right half of image from secondDeviceID to firstDeviceID, so that the copy
1587 					// to a buffer below (for checking) does not require VK_PEER_MEMORY_FEATURE_COPY_SRC_BIT
1588 					deInt32 imageOffsetX = (m_testMode & TEST_MODE_AFR) ? 0 : renderSize.x() / 2;
1589 					deUint32 imageExtentX = (m_testMode & TEST_MODE_AFR) ? (deUint32)renderSize.x() : (deUint32)renderSize.x() / 2;
1590 
1591 					const VkImageCopy	imageCopy =
1592 					{
1593 						{
1594 							VK_IMAGE_ASPECT_COLOR_BIT,
1595 							0, // mipLevel
1596 							0, // arrayLayer
1597 							1  // layerCount
1598 						},
1599 						{ imageOffsetX, 0, 0 },
1600 						{
1601 							VK_IMAGE_ASPECT_COLOR_BIT,
1602 							0, // mipLevel
1603 							0, // arrayLayer
1604 							1  // layerCount
1605 						},
1606 						{ imageOffsetX, 0, 0 },
1607 						{
1608 							imageExtentX,
1609 							(deUint32)renderSize.y(),
1610 							1u
1611 						}
1612 					};
1613 
1614 					beginCommandBuffer(vk, *cmdBuffer);
1615 					vk.cmdSetDeviceMask(*cmdBuffer, 1 << secondDeviceID);
1616 					vk.cmdCopyImage(*cmdBuffer, *renderImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, *peerImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &imageCopy);
1617 					endCommandBuffer(vk, *cmdBuffer);
1618 
1619 					const deUint32 deviceMask = 1 << secondDeviceID;
1620 					submitBufferAndWaitForIdle(vk, cmdBuffer.get(), deviceMask);
1621 					m_context.resetCommandPoolForVKSC(*m_deviceGroup, *cmdPool);
1622 				}
1623 
1624 				// Change layout back on firstDeviceID
1625 				{
1626 					const VkImageMemoryBarrier	postCopyBarrier =
1627 					{
1628 						VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,		// VkStructureType			sType;
1629 						DE_NULL,									// const void*				pNext;
1630 						VK_ACCESS_TRANSFER_WRITE_BIT,				// VkAccessFlags			srcAccessMask;
1631 						VK_ACCESS_TRANSFER_READ_BIT,				// VkAccessFlags			dstAccessMask;
1632 						VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,		// VkImageLayout			oldLayout;
1633 						VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,		// VkImageLayout			newLayout;
1634 						VK_QUEUE_FAMILY_IGNORED,					// deUint32					srcQueueFamilyIndex;
1635 						VK_QUEUE_FAMILY_IGNORED,					// deUint32					dstQueueFamilyIndex;
1636 						*renderImage,								// VkImage					image;
1637 						{											// VkImageSubresourceRange	subresourceRange;
1638 							VK_IMAGE_ASPECT_COLOR_BIT,				// VkImageAspectFlags		aspectMask;
1639 							0u,										// deUint32					baseMipLevel;
1640 							1u,										// deUint32					mipLevels;
1641 							0u,										// deUint32					baseArraySlice;
1642 							1u										// deUint32					arraySize;
1643 						}
1644 					};
1645 
1646 					beginCommandBuffer(vk, *cmdBuffer);
1647 					vk.cmdSetDeviceMask(*cmdBuffer, 1 << firstDeviceID);
1648 					vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, (VkDependencyFlags)0, 0, (const VkMemoryBarrier*)DE_NULL, 0, (const VkBufferMemoryBarrier*)DE_NULL, 1u, &postCopyBarrier);
1649 					endCommandBuffer(vk, *cmdBuffer);
1650 
1651 					const deUint32 deviceMask = 1 << firstDeviceID;
1652 					submitBufferAndWaitForIdle(vk, cmdBuffer.get(), deviceMask);
1653 					m_context.resetCommandPoolForVKSC(*m_deviceGroup, *cmdPool);
1654 				}
1655 			}
1656 		}
1657 
1658 		// copy image to read buffer for checking
1659 		{
1660 			const VkDeviceSize			imageSizeBytes = (VkDeviceSize)(sizeof(deUint32) * renderSize.x() * renderSize.y());
1661 			const VkBufferCreateInfo	readImageBufferParams =
1662 			{
1663 				VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,		// sType
1664 				DE_NULL,									// pNext
1665 				(VkBufferCreateFlags)0u,					// flags
1666 				imageSizeBytes,								// size
1667 				VK_BUFFER_USAGE_TRANSFER_DST_BIT,			// usage
1668 				VK_SHARING_MODE_EXCLUSIVE,					// sharingMode
1669 				1u,											// queueFamilyIndexCount
1670 				&queueFamilyIndex,							// pQueueFamilyIndices
1671 			};
1672 			const Unique<VkBuffer>		readImageBuffer(createBuffer(vk, *m_deviceGroup, &readImageBufferParams));
1673 			const UniquePtr<Allocation>	readImageBufferMemory(memAlloc.allocate(getBufferMemoryRequirements(vk, *m_deviceGroup, *readImageBuffer), MemoryRequirement::HostVisible));
1674 			VK_CHECK(vk.bindBufferMemory(*m_deviceGroup, *readImageBuffer, readImageBufferMemory->getMemory(), readImageBufferMemory->getOffset()));
1675 
1676 			beginCommandBuffer(vk, *cmdBuffer);
1677 
1678 			// Copy image to buffer
1679 			{
1680 				const VkBufferImageCopy	copyParams =
1681 				{
1682 					(VkDeviceSize)0u,						// bufferOffset
1683 					renderSize.x(),							// bufferRowLength
1684 					renderSize.y(),							// bufferImageHeight
1685 					{
1686 						VK_IMAGE_ASPECT_COLOR_BIT,			// aspectMask
1687 						0u,									// mipLevel
1688 						0u,									// baseArrayLayer
1689 						1u,									// layerCount
1690 					},										// imageSubresource
1691 					{ 0, 0, 0 },							// imageOffset
1692 					{
1693 						renderSize.x(),
1694 						renderSize.y(),
1695 						1u
1696 					}										// imageExtent
1697 				};
1698 
1699 				// Use a diffferent binding in SFR when peer memory as copy source is not allowed
1700 				vk.cmdCopyImageToBuffer(*cmdBuffer, isPeerMemAsCopySrcAllowed ? *renderImage : *readImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, *readImageBuffer, 1u, &copyParams);
1701 
1702 				const VkBufferMemoryBarrier	copyFinishBarrier =
1703 				{
1704 					VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,	// sType
1705 					DE_NULL,									// pNext
1706 					VK_ACCESS_TRANSFER_WRITE_BIT,				// srcAccessMask
1707 					VK_ACCESS_HOST_READ_BIT,					// dstAccessMask
1708 					queueFamilyIndex,							// srcQueueFamilyIndex
1709 					queueFamilyIndex,							// dstQueueFamilyIndex
1710 					*readImageBuffer,							// buffer
1711 					0u,											// offset
1712 					imageSizeBytes								// size
1713 				};
1714 				vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, (VkDependencyFlags)0, 0, (const VkMemoryBarrier*)DE_NULL, 1, &copyFinishBarrier, 0, (const VkImageMemoryBarrier*)DE_NULL);
1715 			}
1716 			endCommandBuffer(vk, *cmdBuffer);
1717 
1718 			// Submit & wait for completion
1719 			{
1720 				const deUint32 deviceMask = 1 << firstDeviceID;
1721 				submitBufferAndWaitForIdle(vk, cmdBuffer.get(), deviceMask);
1722 				m_context.resetCommandPoolForVKSC(*m_deviceGroup, *cmdPool);
1723 			}
1724 
1725 			// Read results and check against reference image
1726 			if (m_drawTessellatedSphere)
1727 			{
1728 				const tcu::TextureFormat			tcuFormat = vk::mapVkFormat(colorFormat);
1729 				const tcu::ConstPixelBufferAccess	resultAccess(tcuFormat, renderSize.x(), renderSize.y(), 1, readImageBufferMemory->getHostPtr());
1730 				invalidateAlloc(vk, *m_deviceGroup, *readImageBufferMemory);
1731 
1732 				tcu::TextureLevel referenceImage;
1733 				string refImage = m_fillModeNonSolid ? "vulkan/data/device_group/sphere.png" : "vulkan/data/device_group/spherefilled.png";
1734 				tcu::ImageIO::loadPNG(referenceImage, m_context.getTestContext().getArchive(),  refImage.c_str());
1735 				iterateResultSuccess = tcu::fuzzyCompare(m_context.getTestContext().getLog(), "ImageComparison", "Image Comparison",
1736 										referenceImage.getAccess(), resultAccess, 0.001f, tcu::COMPARE_LOG_RESULT);
1737 			}
1738 			else
1739 			{
1740 				const tcu::TextureFormat			tcuFormat = vk::mapVkFormat(colorFormat);
1741 				const tcu::ConstPixelBufferAccess	resultAccess(tcuFormat, renderSize.x(), renderSize.y(), 1, readImageBufferMemory->getHostPtr());
1742 				invalidateAlloc(vk, *m_deviceGroup, *readImageBufferMemory);
1743 
1744 				// Render reference and compare
1745 				{
1746 					tcu::TextureLevel	refImage(tcuFormat, (deInt32)renderSize.x(), (deInt32)renderSize.y());
1747 					const tcu::UVec4	threshold(0u);
1748 					const tcu::IVec3	posDeviation(1, 1, 0);
1749 
1750 					tcu::clear(refImage.getAccess(), clearColor);
1751 					renderReferenceTriangle(refImage.getAccess(), triVertices, m_context.getDeviceProperties().limits.subPixelPrecisionBits);
1752 
1753 					iterateResultSuccess = tcu::intThresholdPositionDeviationCompare(m_context.getTestContext().getLog(),
1754 						"ComparisonResult",
1755 						"Image comparison result",
1756 						refImage.getAccess(),
1757 						resultAccess,
1758 						threshold,
1759 						posDeviation,
1760 						false,
1761 						tcu::COMPARE_LOG_RESULT);
1762 				}
1763 			}
1764 		}
1765 
1766 		if (!iterateResultSuccess)
1767 			return tcu::TestStatus::fail("Image comparison failed");
1768 	}
1769 
1770 	return tcu::TestStatus(QP_TEST_RESULT_PASS, "Device group verification passed");
1771 }
1772 
1773 template<class Instance>
1774 class DeviceGroupTestCase : public TestCase
1775 {
1776 public:
DeviceGroupTestCase(tcu::TestContext & context,const char * name,const char * description,deUint32 mode)1777 	DeviceGroupTestCase (tcu::TestContext& context,
1778 						const char*	name,
1779 						const char*	description,
1780 						deUint32 mode)
1781 	: TestCase(context, name, description)
1782 	, m_testMode		(mode)
1783 	{}
1784 
1785 private:
1786 
1787 	deUint32			m_testMode;
1788 
createInstance(Context & context) const1789 	TestInstance*		createInstance	(Context& context) const
1790 	{
1791 		return new Instance(context, m_testMode);
1792 	}
1793 
initPrograms(vk::SourceCollections & programCollection) const1794 	void				initPrograms	(vk::SourceCollections& programCollection) const
1795 	{
1796 		programCollection.glslSources.add("vert") << glu::VertexSource("#version 430\n"
1797 			"layout(location = 0) in vec4 in_Position;\n"
1798 			"out gl_PerVertex { vec4 gl_Position; float gl_PointSize; };\n"
1799 			"void main() {\n"
1800 			"	gl_Position	= in_Position;\n"
1801 			"	gl_PointSize = 1.0;\n"
1802 			"}\n");
1803 
1804 		if (m_testMode & TEST_MODE_TESSELLATION)
1805 		{
1806 			programCollection.glslSources.add("tesc") << glu::TessellationControlSource("#version 450\n"
1807 				"#extension GL_EXT_tessellation_shader : require\n"
1808 				"layout(vertices=3) out;\n"
1809 				"layout(set=0, binding=1) buffer tessLevel { \n"
1810 				"  float tessLvl;\n"
1811 				"};\n"
1812 				"void main()\n"
1813 				"{\n"
1814 				"  gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
1815 				"  if (gl_InvocationID == 0) {\n"
1816 				"    for (int i = 0; i < 4; i++)\n"
1817 				"      gl_TessLevelOuter[i] = tessLvl;\n"
1818 				"    for (int i = 0; i < 2; i++)\n"
1819 				"      gl_TessLevelInner[i] = tessLvl;\n"
1820 				"  }\n"
1821 				"}\n");
1822 
1823 			programCollection.glslSources.add("tese") << glu::TessellationEvaluationSource("#version 450\n"
1824 				"#extension GL_EXT_tessellation_shader : require\n"
1825 				"layout(triangles) in;\n"
1826 				"layout(equal_spacing) in;\n"
1827 				"layout(ccw) in;\n"
1828 				"void main()\n"
1829 				"{\n"
1830 				"  vec4 pos = vec4(0, 0, 0, 0);\n"
1831 				"  vec3 tessCoord = gl_TessCoord.xyz;\n"
1832 				"  pos += tessCoord.z * gl_in[0].gl_Position;\n"
1833 				"  pos += tessCoord.x * gl_in[1].gl_Position;\n"
1834 				"  pos += tessCoord.y * gl_in[2].gl_Position;\n"
1835 				"  vec3 sign = sign(pos.xyz);\n"
1836 				"  pos.xyz = 0.785398 - abs(pos.xyz) * 1.5707963;\n"
1837 				"  pos.xyz = (1 - tan(pos.xyz))/2.0;\n"
1838 				"  pos.xyz = (sign * pos.xyz) / length(pos.xyz);\n"
1839 				"  gl_Position = pos;\n"
1840 				"}\n");
1841 		}
1842 
1843 		programCollection.glslSources.add("frag") << glu::FragmentSource("#version 430\n"
1844 			"layout(location = 0) out vec4 out_FragColor;\n"
1845 			"layout(std140, set=0, binding=0) uniform bufferData { \n"
1846 			"	vec4 color;\n"
1847 			"};\n"
1848 			"void main()\n"
1849 			"{\n"
1850 			"	out_FragColor = color;\n"
1851 			"}\n");
1852 	}
1853 };
1854 
1855 } //anonymous
1856 
1857 class DeviceGroupTestRendering : public tcu::TestCaseGroup
1858 {
1859 public:
1860 								DeviceGroupTestRendering	(tcu::TestContext& testCtx);
~DeviceGroupTestRendering(void)1861 								~DeviceGroupTestRendering	(void) {}
1862 	void						init(void);
1863 
1864 private:
1865 								DeviceGroupTestRendering	(const DeviceGroupTestRendering& other);
1866 	DeviceGroupTestRendering&	operator=					(const DeviceGroupTestRendering& other);
1867 };
1868 
DeviceGroupTestRendering(tcu::TestContext & testCtx)1869 DeviceGroupTestRendering::DeviceGroupTestRendering (tcu::TestContext& testCtx)
1870 	: TestCaseGroup (testCtx, "device_group", "Testing device group test cases")
1871 {
1872 	// Left blank on purpose
1873 }
1874 
init(void)1875 void DeviceGroupTestRendering::init (void)
1876 {
1877 #ifndef CTS_USES_VULKANSC
1878 	addChild(new DeviceGroupTestCase<DeviceGroupTestInstance>(m_testCtx, "sfr",							"Test split frame rendering",														TEST_MODE_SFR));
1879 	addChild(new DeviceGroupTestCase<DeviceGroupTestInstance>(m_testCtx, "sfr_sys",						"Test split frame rendering with render target in host memory",						TEST_MODE_SFR | TEST_MODE_HOSTMEMORY));
1880 	addChild(new DeviceGroupTestCase<DeviceGroupTestInstance>(m_testCtx, "sfr_dedicated",				"Test split frame rendering with dedicated memory allocations",						TEST_MODE_SFR | TEST_MODE_DEDICATED));
1881 	addChild(new DeviceGroupTestCase<DeviceGroupTestInstance>(m_testCtx, "sfr_dedicated_peer",			"Test split frame rendering with dedicated memory allocations and peer fetching",	TEST_MODE_SFR | TEST_MODE_DEDICATED | TEST_MODE_PEER_FETCH));
1882 #endif // CTS_USES_VULKANSC
1883 
1884 	addChild(new DeviceGroupTestCase<DeviceGroupTestInstance>(m_testCtx, "afr",							"Test alternate frame rendering",													TEST_MODE_AFR));
1885 	addChild(new DeviceGroupTestCase<DeviceGroupTestInstance>(m_testCtx, "afr_sys",						"Test split frame rendering with render target in host memory",						TEST_MODE_AFR | TEST_MODE_HOSTMEMORY));
1886 	addChild(new DeviceGroupTestCase<DeviceGroupTestInstance>(m_testCtx, "afr_dedicated",				"Test split frame rendering with dedicated memory allocations",						TEST_MODE_AFR | TEST_MODE_DEDICATED));
1887 	addChild(new DeviceGroupTestCase<DeviceGroupTestInstance>(m_testCtx, "afr_dedicated_peer",			"Test split frame rendering with dedicated memory allocations and peer fetching",	TEST_MODE_AFR | TEST_MODE_DEDICATED | TEST_MODE_PEER_FETCH));
1888 
1889 #ifndef CTS_USES_VULKANSC
1890 	addChild(new DeviceGroupTestCase<DeviceGroupTestInstance>(m_testCtx, "sfr_tessellated",				"Test split frame rendering with tessellated sphere",								TEST_MODE_SFR | TEST_MODE_TESSELLATION | TEST_MODE_DEDICATED | TEST_MODE_PEER_FETCH));
1891 	addChild(new DeviceGroupTestCase<DeviceGroupTestInstance>(m_testCtx, "sfr_tessellated_linefill",	"Test split frame rendering with tessellated sphere with line segments",			TEST_MODE_SFR | TEST_MODE_TESSELLATION | TEST_MODE_LINEFILL  | TEST_MODE_DEDICATED | TEST_MODE_PEER_FETCH));
1892 #endif // CTS_USES_VULKANSC
1893 	addChild(new DeviceGroupTestCase<DeviceGroupTestInstance>(m_testCtx, "afr_tessellated",				"Test alternate frame rendering with tesselated sphere",							TEST_MODE_AFR | TEST_MODE_TESSELLATION | TEST_MODE_DEDICATED | TEST_MODE_PEER_FETCH));
1894 	addChild(new DeviceGroupTestCase<DeviceGroupTestInstance>(m_testCtx, "afr_tessellated_linefill",	"Test alternate frame rendering with tesselated sphere with line segments",			TEST_MODE_AFR | TEST_MODE_TESSELLATION | TEST_MODE_LINEFILL  | TEST_MODE_DEDICATED | TEST_MODE_PEER_FETCH));
1895 }
1896 
createTests(tcu::TestContext & testCtx)1897 tcu::TestCaseGroup* createTests(tcu::TestContext& testCtx)
1898 {
1899 	return new DeviceGroupTestRendering(testCtx);
1900 }
1901 }	// DeviceGroup
1902 }	// vkt
1903