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