1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2017-2020 The Khronos Group Inc.
6  * Copyright (c) 2020 AMD
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 Tests for VK_KHR_fragment_shading_rate
23  *//*--------------------------------------------------------------------*/
24 
25 #include "vktFragmentShadingRatePixelConsistency.hpp"
26 
27 #include "vkBufferWithMemory.hpp"
28 #include "vkImageWithMemory.hpp"
29 #include "vkQueryUtil.hpp"
30 #include "vkBuilderUtil.hpp"
31 #include "vkCmdUtil.hpp"
32 #include "vkTypeUtil.hpp"
33 #include "vkObjUtil.hpp"
34 #include "vkImageUtil.hpp"
35 #include "vkQueryUtil.hpp"
36 #include "vkDeviceUtil.hpp"
37 #include "vkPlatform.hpp"
38 
39 #include "vktTestGroupUtil.hpp"
40 #include "vktTestCase.hpp"
41 #include "vktCustomInstancesDevices.hpp"
42 
43 #include "deDefs.h"
44 #include "deMath.h"
45 #include "deRandom.h"
46 #include "deSharedPtr.hpp"
47 #include "deString.h"
48 
49 #include "tcuTestCase.hpp"
50 #include "tcuTestLog.hpp"
51 #include "tcuCommandLine.hpp"
52 
53 #include <limits>
54 #include <string>
55 #include <sstream>
56 
57 namespace vkt
58 {
59 namespace FragmentShadingRate
60 {
61 namespace
62 {
63 using namespace vk;
64 using namespace std;
65 
66 struct CaseDef
67 {
68     VkExtent2D shadingRate;
69     VkSampleCountFlagBits samples;
70     VkExtent2D framebufferExtent;
71     bool zwCoord;
72 };
73 
74 struct Vertex
75 {
76     float x;
77     float y;
78 };
79 
80 Vertex basicTriangles[6] = {
81     {-1.0f, -1.0f}, {1.0f, -1.0f}, {1.0f, 1.0f},
82 
83     {-1.0f, 1.0f},  {1.0f, -1.0f}, {1.0f, 1.0f},
84 };
85 
createImageRobustnessDevice(Context & context,const vk::VkInstance & instance,const InstanceInterface & vki)86 Move<VkDevice> createImageRobustnessDevice(Context &context, const vk::VkInstance &instance,
87                                            const InstanceInterface &vki)
88 {
89     const VkPhysicalDevice physicalDevice = chooseDevice(vki, instance, context.getTestContext().getCommandLine());
90     const float queuePriority             = 1.0f;
91 
92     // Create a universal queue
93     const VkDeviceQueueCreateInfo queueParams = {
94         VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, // VkStructureType sType;
95         DE_NULL,                                    // const void* pNext;
96         0u,                                         // VkDeviceQueueCreateFlags flags;
97         context.getUniversalQueueFamilyIndex(),     // uint32_t queueFamilyIndex;
98         1u,                                         // uint32_t queueCount;
99         &queuePriority                              // const float* pQueuePriorities;
100     };
101 
102     // Add image robustness extension if supported
103     std::vector<const char *> deviceExtensions;
104 
105     deviceExtensions.push_back("VK_KHR_fragment_shading_rate");
106 
107     if (context.isDeviceFunctionalitySupported("VK_EXT_image_robustness"))
108     {
109         deviceExtensions.push_back("VK_EXT_image_robustness");
110     }
111 
112     VkPhysicalDeviceFragmentShadingRateFeaturesKHR fsrFeatures = {
113         VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_FEATURES_KHR, // VkStructureType sType;
114         DE_NULL,                                                              // void* pNext;
115         false,                                                                // VkBool32 pipelineFragmentShadingRate;
116         false,                                                                // VkBool32 primitiveFragmentShadingRate;
117         false,                                                                // VkBool32 attachmentFragmentShadingRate;
118     };
119 
120     VkPhysicalDeviceFeatures2 enabledFeatures;
121     enabledFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
122     enabledFeatures.pNext = &fsrFeatures;
123 
124     vki.getPhysicalDeviceFeatures2(physicalDevice, &enabledFeatures);
125 
126     const VkDeviceCreateInfo deviceParams = {
127         VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,                      // VkStructureType sType;
128         &enabledFeatures,                                          // const void* pNext;
129         0u,                                                        // VkDeviceCreateFlags flags;
130         1u,                                                        // uint32_t queueCreateInfoCount;
131         &queueParams,                                              // const VkDeviceQueueCreateInfo* pQueueCreateInfos;
132         0u,                                                        // uint32_t enabledLayerCount;
133         DE_NULL,                                                   // const char* const* ppEnabledLayerNames;
134         static_cast<uint32_t>(deviceExtensions.size()),            // uint32_t enabledExtensionCount;
135         deviceExtensions.empty() ? DE_NULL : &deviceExtensions[0], // const char* const* ppEnabledExtensionNames;
136         DE_NULL,                                                   // const VkPhysicalDeviceFeatures* pEnabledFeatures;
137     };
138 
139     return createCustomDevice(context.getTestContext().getCommandLine().isValidationEnabled(),
140                               context.getPlatformInterface(), instance, vki, context.getPhysicalDevice(),
141                               &deviceParams);
142 }
143 
144 class FSRPixelConsistencyInstance : public TestInstance
145 {
146 public:
147     FSRPixelConsistencyInstance(Context &context, const CaseDef &data);
148     ~FSRPixelConsistencyInstance(void);
149     tcu::TestStatus iterate(void);
150 
151 private:
152     void clampShadingRate();
153     tcu::TestStatus verifyResult(tcu::ConstPixelBufferAccess &resultBuffer, const uint32_t index);
154 
155     CaseDef m_data;
156     vector<VkExtent2D> m_shadingRateClamped;
157 
158     uint32_t m_supportedFragmentShadingRateCount;
159     vector<VkPhysicalDeviceFragmentShadingRateKHR> m_supportedFragmentShadingRates;
160 };
161 
FSRPixelConsistencyInstance(Context & context,const CaseDef & data)162 FSRPixelConsistencyInstance::FSRPixelConsistencyInstance(Context &context, const CaseDef &data)
163     : vkt::TestInstance(context)
164     , m_data(data)
165     , m_supportedFragmentShadingRateCount(0)
166 {
167     // Fetch information about supported fragment shading rates
168     context.getInstanceInterface().getPhysicalDeviceFragmentShadingRatesKHR(
169         context.getPhysicalDevice(), &m_supportedFragmentShadingRateCount, DE_NULL);
170 
171     m_supportedFragmentShadingRates.resize(m_supportedFragmentShadingRateCount);
172     for (uint32_t i = 0; i < m_supportedFragmentShadingRateCount; ++i)
173     {
174         m_supportedFragmentShadingRates[i].sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_KHR;
175         m_supportedFragmentShadingRates[i].pNext = nullptr;
176     }
177     context.getInstanceInterface().getPhysicalDeviceFragmentShadingRatesKHR(
178         context.getPhysicalDevice(), &m_supportedFragmentShadingRateCount, &m_supportedFragmentShadingRates[0]);
179 
180     clampShadingRate();
181 }
182 
~FSRPixelConsistencyInstance(void)183 FSRPixelConsistencyInstance::~FSRPixelConsistencyInstance(void)
184 {
185 }
186 
187 class FSRPixelConsistencyTestCase : public TestCase
188 {
189 public:
190     FSRPixelConsistencyTestCase(tcu::TestContext &context, const char *name, const CaseDef data);
191     ~FSRPixelConsistencyTestCase(void);
192     virtual void initPrograms(SourceCollections &programCollection) const;
193     virtual TestInstance *createInstance(Context &context) const;
194     virtual void checkSupport(Context &context) const;
195 
196 private:
197     CaseDef m_data;
198 };
199 
FSRPixelConsistencyTestCase(tcu::TestContext & context,const char * name,const CaseDef data)200 FSRPixelConsistencyTestCase::FSRPixelConsistencyTestCase(tcu::TestContext &context, const char *name,
201                                                          const CaseDef data)
202     : vkt::TestCase(context, name)
203     , m_data(data)
204 {
205 }
206 
~FSRPixelConsistencyTestCase(void)207 FSRPixelConsistencyTestCase::~FSRPixelConsistencyTestCase(void)
208 {
209 }
210 
checkSupport(Context & context) const211 void FSRPixelConsistencyTestCase::checkSupport(Context &context) const
212 {
213     const VkImageUsageFlags cbUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT |
214                                       VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
215 
216     context.requireDeviceFunctionality("VK_KHR_fragment_shading_rate");
217 
218     if (!context.getFragmentShadingRateFeatures().pipelineFragmentShadingRate)
219         TCU_THROW(NotSupportedError, "pipelineFragmentShadingRate not supported");
220 
221     VkImageFormatProperties imageProperties;
222     VkResult result = context.getInstanceInterface().getPhysicalDeviceImageFormatProperties(
223         context.getPhysicalDevice(), VK_FORMAT_R32G32_UINT, VK_IMAGE_TYPE_2D, VK_IMAGE_TILING_OPTIMAL, cbUsage, 0,
224         &imageProperties);
225 
226     if (result == VK_ERROR_FORMAT_NOT_SUPPORTED)
227         TCU_THROW(NotSupportedError, "VK_FORMAT_R32G32_UINT not supported");
228 
229     if (!(imageProperties.sampleCounts & m_data.samples))
230         TCU_THROW(NotSupportedError, "Image sample count not supported");
231 
232     if ((imageProperties.maxExtent.width < m_data.framebufferExtent.width) ||
233         (imageProperties.maxExtent.height < m_data.framebufferExtent.height))
234         TCU_THROW(NotSupportedError, "Image max extents are smaller than required");
235 }
236 
initPrograms(SourceCollections & programCollection) const237 void FSRPixelConsistencyTestCase::initPrograms(SourceCollections &programCollection) const
238 {
239     std::stringstream vss;
240 
241     vss << "#version 450 core\n"
242            "layout(location = 0) in vec2 position;\n"
243            "out gl_PerVertex\n"
244            "{\n"
245            "   vec4 gl_Position;\n"
246            "};\n"
247            "void main()\n"
248            "{\n";
249     if (!m_data.zwCoord)
250     {
251         vss << "  gl_Position = vec4(position, 0, 1);\n";
252     }
253     else
254     {
255         vss << "  gl_Position = vec4(position, position);\n";
256     }
257     vss << "}\n";
258 
259     programCollection.glslSources.add("vert") << glu::VertexSource(vss.str());
260 
261     std::stringstream fssPass0;
262 
263     fssPass0 << "#version 450 core\n"
264                 "layout(push_constant) uniform PC {\n"
265                 "    uvec2 shadingRate[2];\n"
266                 "} pc;\n"
267                 "layout(location = 0) out uvec2 col0;\n"
268                 "void main()\n"
269                 "{\n";
270     if (!m_data.zwCoord)
271     {
272         fssPass0 << "  col0.x = (uint(gl_FragCoord.x) % pc.shadingRate[0].x) + ((uint(gl_FragCoord.y) % "
273                     "pc.shadingRate[0].y) * pc.shadingRate[0].x);\n"
274                     "  col0.y = (uint(gl_FragCoord.x) % pc.shadingRate[1].x) + ((uint(gl_FragCoord.y) % "
275                     "pc.shadingRate[1].y) * pc.shadingRate[1].x);\n";
276     }
277     else
278     {
279         fssPass0 << "  col0.x = (uint(gl_FragCoord.z) % pc.shadingRate[0].x) + ((uint(gl_FragCoord.w) % "
280                     "pc.shadingRate[0].y) * pc.shadingRate[0].x);\n"
281                     "  col0.y = (uint(gl_FragCoord.z) % pc.shadingRate[1].x) + ((uint(gl_FragCoord.w) % "
282                     "pc.shadingRate[1].y) * pc.shadingRate[1].x);\n";
283     }
284     fssPass0 << "}\n";
285 
286     programCollection.glslSources.add("frag_pass0") << glu::FragmentSource(fssPass0.str());
287 
288     std::stringstream fssPass1;
289 
290     fssPass1 << "#version 450 core\n";
291 
292     if (m_data.samples == VK_SAMPLE_COUNT_1_BIT)
293     {
294         fssPass1 << "layout(input_attachment_index=0, set=0, binding=0) uniform usubpassInput inputAttachment;\n";
295     }
296     else
297     {
298         fssPass1 << "layout(input_attachment_index=0, set=0, binding=0) uniform usubpassInputMS inputAttachment;\n";
299     }
300 
301     fssPass1 << "layout(location = 0) out uvec2 col0;\n"
302                 "void main()\n"
303                 "{\n";
304 
305     if (m_data.samples == VK_SAMPLE_COUNT_1_BIT)
306     {
307         fssPass1 << "  col0 = subpassLoad(inputAttachment).xy;\n";
308     }
309     else
310     {
311         fssPass1 << "  col0 = subpassLoad(inputAttachment, 0).xy;\n";
312     }
313 
314     fssPass1 << "}\n";
315 
316     programCollection.glslSources.add("frag_pass1") << glu::FragmentSource(fssPass1.str());
317 }
318 
createInstance(Context & context) const319 TestInstance *FSRPixelConsistencyTestCase::createInstance(Context &context) const
320 {
321     return new FSRPixelConsistencyInstance(context, m_data);
322 }
323 
compareShadingRate(VkExtent2D ext1,VkExtent2D ext2)324 bool compareShadingRate(VkExtent2D ext1, VkExtent2D ext2)
325 {
326     uint32_t ratio1 = std::max(ext1.width, ext1.height) / std::min(ext1.width, ext1.height);
327     uint32_t ratio2 = std::max(ext2.width, ext2.height) / std::min(ext2.width, ext2.height);
328 
329     return ratio1 < ratio2;
330 }
331 
clampShadingRate()332 void FSRPixelConsistencyInstance::clampShadingRate()
333 {
334     uint32_t desiredSize = m_data.shadingRate.width * m_data.shadingRate.height;
335 
336     while (desiredSize > 0)
337     {
338         // Find modes that maximize the area
339         for (uint32_t i = 0; i < m_supportedFragmentShadingRateCount; ++i)
340         {
341             const VkPhysicalDeviceFragmentShadingRateKHR &supportedRate = m_supportedFragmentShadingRates[i];
342 
343             if (supportedRate.sampleCounts & VK_SAMPLE_COUNT_1_BIT)
344             {
345                 // We found exact match
346                 if (supportedRate.fragmentSize.width == m_data.shadingRate.width &&
347                     supportedRate.fragmentSize.height == m_data.shadingRate.height)
348                 {
349                     m_shadingRateClamped.push_back(supportedRate.fragmentSize);
350 
351                     return;
352                 }
353                 else
354                 {
355                     if (supportedRate.fragmentSize.width <= m_data.shadingRate.width &&
356                         supportedRate.fragmentSize.height <= m_data.shadingRate.height &&
357                         supportedRate.fragmentSize.width * supportedRate.fragmentSize.height == desiredSize)
358                     {
359                         m_shadingRateClamped.push_back(supportedRate.fragmentSize);
360                     }
361                 }
362             }
363         }
364         if (!m_shadingRateClamped.empty())
365         {
366             // Sort the modes so that the ones with the smallest aspect ratio are in front
367             std::sort(m_shadingRateClamped.begin(), m_shadingRateClamped.end(), compareShadingRate);
368 
369             uint32_t desiredRatio = std::max(m_shadingRateClamped[0].width, m_shadingRateClamped[0].height) /
370                                     std::min(m_shadingRateClamped[0].width, m_shadingRateClamped[0].height);
371 
372             // Leave only entries with the smallest aspect ratio
373             auto it = m_shadingRateClamped.begin();
374             while (it != m_shadingRateClamped.end())
375             {
376                 uint32_t ratio = std::max(it->width, it->height) / std::min(it->width, it->height);
377 
378                 if (ratio < desiredRatio)
379                 {
380                     it = m_shadingRateClamped.erase(it, m_shadingRateClamped.end());
381                 }
382                 else
383                 {
384                     ++it;
385                 }
386             }
387 
388             return;
389         }
390         else
391         {
392             desiredSize /= 2;
393         }
394     }
395     DE_ASSERT(0);
396 
397     return;
398 }
399 
verifyResult(tcu::ConstPixelBufferAccess & resultBuffer,const uint32_t index)400 tcu::TestStatus FSRPixelConsistencyInstance::verifyResult(tcu::ConstPixelBufferAccess &resultBuffer,
401                                                           const uint32_t index)
402 {
403     uint32_t pixelIndex        = std::numeric_limits<unsigned int>::max();
404     uint32_t pixelOutsideIndex = std::numeric_limits<unsigned int>::max();
405 
406     for (int y = 0; y < resultBuffer.getHeight(); y++)
407     {
408         for (int x = 0; x < resultBuffer.getWidth(); x++)
409         {
410             uint32_t pixel = resultBuffer.getPixelUint(x, y)[index];
411 
412             // If pixel was not covered by any triangle, we skip it
413             if (pixel == std::numeric_limits<unsigned int>::max())
414             {
415                 continue;
416             }
417 
418             // We check if pixel is part of fragment area that is partially outside of framebuffer area
419             bool outsideW = (x / m_shadingRateClamped[index].width + 1) * m_shadingRateClamped[index].width >
420                             static_cast<uint32_t>(resultBuffer.getWidth());
421             bool outsideH = (y / m_shadingRateClamped[index].height + 1) * m_shadingRateClamped[index].height >
422                             static_cast<uint32_t>(resultBuffer.getHeight());
423 
424             if (outsideW || outsideH)
425             {
426                 // If image robustness is enabled such pixel can have either a value of 0 or one of the values from the area inside framebuffer
427                 if (m_context.isDeviceFunctionalitySupported("VK_EXT_image_robustness"))
428                 {
429                     if (pixelOutsideIndex == std::numeric_limits<unsigned int>::max() || pixelOutsideIndex == 0)
430                     {
431                         pixelOutsideIndex = pixel;
432                     }
433                     // If value is non-zero we make sure that all 'corner' pixels have the same value
434                     else if ((pixel != 0) && (pixelOutsideIndex != pixel))
435                     {
436                         return tcu::TestStatus(QP_TEST_RESULT_FAIL, qpGetTestResultName(QP_TEST_RESULT_FAIL));
437                     }
438                 }
439                 // If image robustness is not enabled such pixel can have an undefined value, so we skip it
440                 else
441                 {
442                     continue;
443                 }
444             }
445             else
446             {
447                 if (pixelIndex == std::numeric_limits<unsigned int>::max())
448                 {
449                     if (pixel >= m_shadingRateClamped[index].width * m_shadingRateClamped[index].height)
450                     {
451                         return tcu::TestStatus(QP_TEST_RESULT_FAIL, qpGetTestResultName(QP_TEST_RESULT_FAIL));
452                     }
453 
454                     pixelIndex = pixel;
455                 }
456                 // If pixel is not part of 'corner' pixels we make sure that is has the same value as other non-'corner' pixels
457                 else if (pixelIndex != pixel)
458                 {
459                     return tcu::TestStatus(QP_TEST_RESULT_FAIL, qpGetTestResultName(QP_TEST_RESULT_FAIL));
460                 }
461             }
462         }
463     }
464 
465     return tcu::TestStatus(QP_TEST_RESULT_PASS, qpGetTestResultName(QP_TEST_RESULT_PASS));
466 }
467 
iterate(void)468 tcu::TestStatus FSRPixelConsistencyInstance::iterate(void)
469 {
470     const VkPhysicalDeviceMemoryProperties memoryProperties =
471         vk::getPhysicalDeviceMemoryProperties(m_context.getInstanceInterface(), m_context.getPhysicalDevice());
472 
473     const VkInstance instance  = m_context.getInstance();
474     const auto &instanceDriver = m_context.getInstanceInterface();
475 
476     Move<VkDevice> vkd    = createImageRobustnessDevice(m_context, instance, instanceDriver);
477     const VkDevice device = *vkd;
478 #ifndef CTS_USES_VULKANSC
479     de::MovePtr<vk::DeviceDriver> deviceDriver = de::MovePtr<DeviceDriver>(
480         new DeviceDriver(m_context.getPlatformInterface(), m_context.getInstance(), device,
481                          m_context.getUsedApiVersion(), m_context.getTestContext().getCommandLine()));
482 #else
483     de::MovePtr<vk::DeviceDriverSC, vk::DeinitDeviceDeleter> deviceDriver =
484         de::MovePtr<DeviceDriverSC, DeinitDeviceDeleter>(
485             new DeviceDriverSC(m_context.getPlatformInterface(), m_context.getInstance(), device,
486                                m_context.getTestContext().getCommandLine(), m_context.getResourceInterface(),
487                                m_context.getDeviceVulkanSC10Properties(), m_context.getDeviceProperties(),
488                                m_context.getUsedApiVersion()),
489             vk::DeinitDeviceDeleter(m_context.getResourceInterface().get(), device));
490 #endif // CTS_USES_VULKANSC
491     const DeviceInterface &vk        = *deviceDriver;
492     const VkQueue queue              = getDeviceQueue(vk, device, m_context.getUniversalQueueFamilyIndex(), 0);
493     de::MovePtr<Allocator> allocator = de::MovePtr<Allocator>(new SimpleAllocator(vk, device, memoryProperties));
494 
495     // Create vertex buffer
496     const VkDeviceSize vertexBufferSize = sizeof(basicTriangles);
497 
498     const VkFormat imageFormat = VK_FORMAT_R32G32_UINT;
499 
500     de::MovePtr<BufferWithMemory> vertexBuffer;
501     vertexBuffer = de::MovePtr<BufferWithMemory>(new BufferWithMemory(
502         vk, device, *allocator, makeBufferCreateInfo(vertexBufferSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT),
503         MemoryRequirement::HostVisible));
504 
505     float *vbuf = (float *)vertexBuffer->getAllocation().getHostPtr();
506 
507     deMemcpy(vbuf, basicTriangles, vertexBufferSize);
508 
509     flushAlloc(vk, device, vertexBuffer->getAllocation());
510 
511     // Create color output buffer
512     const VkDeviceSize colorOutputBufferSize =
513         m_data.framebufferExtent.width * m_data.framebufferExtent.height * tcu::getPixelSize(mapVkFormat(imageFormat));
514 
515     de::MovePtr<BufferWithMemory> colorOutputBuffer;
516     colorOutputBuffer = de::MovePtr<BufferWithMemory>(new BufferWithMemory(
517         vk, device, *allocator, makeBufferCreateInfo(colorOutputBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT),
518         MemoryRequirement::HostVisible));
519 
520     // Create color attachment for subpass 0
521     de::MovePtr<ImageWithMemory> cbImagePass0;
522     Move<VkImageView> cbImagePass0View;
523     {
524         const VkImageUsageFlags cbUsage =
525             VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
526 
527         const VkImageCreateInfo imageCreateInfo = {
528             VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
529             DE_NULL,                             // const void* pNext;
530             (VkImageCreateFlags)0u,              // VkImageCreateFlags flags;
531             VK_IMAGE_TYPE_2D,                    // VkImageType imageType;
532             imageFormat,                         // VkFormat format;
533             {
534                 m_data.framebufferExtent.width,  // uint32_t width;
535                 m_data.framebufferExtent.height, // uint32_t height;
536                 1u                               // uint32_t depth;
537             },                                   // VkExtent3D extent;
538             1u,                                  // uint32_t mipLevels;
539             1u,                                  // uint32_t arrayLayers;
540             m_data.samples,                      // VkSampleCountFlagBits samples;
541             VK_IMAGE_TILING_OPTIMAL,             // VkImageTiling tiling;
542             cbUsage,                             // VkImageUsageFlags usage;
543             VK_SHARING_MODE_EXCLUSIVE,           // VkSharingMode sharingMode;
544             0u,                                  // uint32_t queueFamilyIndexCount;
545             DE_NULL,                             // const uint32_t* pQueueFamilyIndices;
546             VK_IMAGE_LAYOUT_UNDEFINED            // VkImageLayout initialLayout;
547         };
548         cbImagePass0 = de::MovePtr<ImageWithMemory>(
549             new ImageWithMemory(vk, device, *allocator, imageCreateInfo, MemoryRequirement::Any));
550 
551         VkImageViewCreateInfo imageViewCreateInfo = {
552             VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, // VkStructureType sType;
553             DE_NULL,                                  // const void* pNext;
554             (VkImageViewCreateFlags)0u,               // VkImageViewCreateFlags flags;
555             **cbImagePass0,                           // VkImage image;
556             VK_IMAGE_VIEW_TYPE_2D,                    // VkImageViewType viewType;
557             imageFormat,                              // VkFormat format;
558             {
559                 VK_COMPONENT_SWIZZLE_R, // VkComponentSwizzle r;
560                 VK_COMPONENT_SWIZZLE_G, // VkComponentSwizzle g;
561                 VK_COMPONENT_SWIZZLE_B, // VkComponentSwizzle b;
562                 VK_COMPONENT_SWIZZLE_A  // VkComponentSwizzle a;
563             },                          // VkComponentMapping  components;
564             {
565                 VK_IMAGE_ASPECT_COLOR_BIT, // VkImageAspectFlags aspectMask;
566                 0u,                        // uint32_t baseMipLevel;
567                 1u,                        // uint32_t levelCount;
568                 0u,                        // uint32_t baseArrayLayer;
569                 1u                         // uint32_t layerCount;
570             }                              // VkImageSubresourceRange subresourceRange;
571         };
572         cbImagePass0View = createImageView(vk, device, &imageViewCreateInfo, NULL);
573     }
574 
575     // Create color attachment for subpass 1
576     de::MovePtr<ImageWithMemory> cbImagePass1;
577     Move<VkImageView> cbImagePass1View;
578     {
579         const VkImageUsageFlags cbUsage =
580             VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
581 
582         const VkImageCreateInfo imageCreateInfo = {
583             VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
584             DE_NULL,                             // const void* pNext;
585             (VkImageCreateFlags)0u,              // VkImageCreateFlags flags;
586             VK_IMAGE_TYPE_2D,                    // VkImageType imageType;
587             imageFormat,                         // VkFormat format;
588             {
589                 m_data.framebufferExtent.width,  // uint32_t width;
590                 m_data.framebufferExtent.height, // uint32_t height;
591                 1u                               // uint32_t depth;
592             },                                   // VkExtent3D extent;
593             1u,                                  // uint32_t mipLevels;
594             1u,                                  // uint32_t arrayLayers;
595             VK_SAMPLE_COUNT_1_BIT,               // VkSampleCountFlagBits samples;
596             VK_IMAGE_TILING_OPTIMAL,             // VkImageTiling tiling;
597             cbUsage,                             // VkImageUsageFlags usage;
598             VK_SHARING_MODE_EXCLUSIVE,           // VkSharingMode sharingMode;
599             0u,                                  // uint32_t queueFamilyIndexCount;
600             DE_NULL,                             // const uint32_t* pQueueFamilyIndices;
601             VK_IMAGE_LAYOUT_UNDEFINED            // VkImageLayout initialLayout;
602         };
603         cbImagePass1 = de::MovePtr<ImageWithMemory>(
604             new ImageWithMemory(vk, device, *allocator, imageCreateInfo, MemoryRequirement::Any));
605 
606         VkImageViewCreateInfo imageViewCreateInfo = {
607             VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, // VkStructureType sType;
608             DE_NULL,                                  // const void* pNext;
609             (VkImageViewCreateFlags)0u,               // VkImageViewCreateFlags flags;
610             **cbImagePass1,                           // VkImage image;
611             VK_IMAGE_VIEW_TYPE_2D,                    // VkImageViewType viewType;
612             imageFormat,                              // VkFormat format;
613             {
614                 VK_COMPONENT_SWIZZLE_R, // VkComponentSwizzle r;
615                 VK_COMPONENT_SWIZZLE_G, // VkComponentSwizzle g;
616                 VK_COMPONENT_SWIZZLE_B, // VkComponentSwizzle b;
617                 VK_COMPONENT_SWIZZLE_A  // VkComponentSwizzle a;
618             },                          // VkComponentMapping  components;
619             {
620                 VK_IMAGE_ASPECT_COLOR_BIT, // VkImageAspectFlags aspectMask;
621                 0u,                        // uint32_t baseMipLevel;
622                 1u,                        // uint32_t levelCount;
623                 0u,                        // uint32_t baseArrayLayer;
624                 1u                         // uint32_t layerCount;
625             }                              // VkImageSubresourceRange subresourceRange;
626         };
627         cbImagePass1View = createImageView(vk, device, &imageViewCreateInfo, NULL);
628     }
629 
630     // Create render pass
631     Move<VkRenderPass> renderPass;
632     {
633         const vk::VkAttachmentReference colorAttachment0Reference = {
634             0,                           // attachment
635             vk::VK_IMAGE_LAYOUT_GENERAL, // layout
636         };
637 
638         const vk::VkAttachmentReference colorAttachment1Reference = {
639             1,                           // attachment
640             vk::VK_IMAGE_LAYOUT_GENERAL, // layout
641         };
642 
643         std::vector<VkAttachmentDescription> attachmentDescriptions;
644 
645         attachmentDescriptions.push_back({
646             (VkAttachmentDescriptionFlags)0u, // VkAttachmentDescriptionFlags flags;
647             imageFormat,                      // VkFormat format;
648             m_data.samples,                   // VkSampleCountFlagBits samples;
649             VK_ATTACHMENT_LOAD_OP_LOAD,       // VkAttachmentLoadOp loadOp;
650             VK_ATTACHMENT_STORE_OP_STORE,     // VkAttachmentStoreOp storeOp;
651             VK_ATTACHMENT_LOAD_OP_DONT_CARE,  // VkAttachmentLoadOp stencilLoadOp;
652             VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp;
653             VK_IMAGE_LAYOUT_GENERAL,          // VkImageLayout initialLayout;
654             VK_IMAGE_LAYOUT_GENERAL           // VkImageLayout finalLayout;
655         });
656 
657         attachmentDescriptions.push_back({
658             (VkAttachmentDescriptionFlags)0u, // VkAttachmentDescriptionFlags flags;
659             imageFormat,                      // VkFormat format;
660             VK_SAMPLE_COUNT_1_BIT,            // VkSampleCountFlagBits samples;
661             VK_ATTACHMENT_LOAD_OP_LOAD,       // VkAttachmentLoadOp loadOp;
662             VK_ATTACHMENT_STORE_OP_STORE,     // VkAttachmentStoreOp storeOp;
663             VK_ATTACHMENT_LOAD_OP_DONT_CARE,  // VkAttachmentLoadOp stencilLoadOp;
664             VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp;
665             VK_IMAGE_LAYOUT_GENERAL,          // VkImageLayout initialLayout;
666             VK_IMAGE_LAYOUT_GENERAL           // VkImageLayout finalLayout;
667         });
668 
669         const VkSubpassDescription subpassDescs[] = {
670             {
671                 (vk::VkSubpassDescriptionFlags)0,    // flags
672                 vk::VK_PIPELINE_BIND_POINT_GRAPHICS, // pipelineBindPoint
673                 0u,                                  // inputCount
674                 DE_NULL,                             // pInputAttachments
675                 1u,                                  // colorCount
676                 &colorAttachment0Reference,          // pColorAttachments
677                 DE_NULL,                             // pResolveAttachments
678                 DE_NULL,                             // depthStencilAttachment
679                 0u,                                  // preserveCount
680                 DE_NULL,                             // pPreserveAttachments
681             },
682             {
683                 (vk::VkSubpassDescriptionFlags)0,    // flags
684                 vk::VK_PIPELINE_BIND_POINT_GRAPHICS, // pipelineBindPoint
685                 1u,                                  // inputCount
686                 &colorAttachment0Reference,          // pInputAttachments
687                 1u,                                  // colorCount
688                 &colorAttachment1Reference,          // pColorAttachments
689                 DE_NULL,                             // pResolveAttachments
690                 DE_NULL,                             // depthStencilAttachment
691                 0u,                                  // preserveCount
692                 DE_NULL,                             // pPreserveAttachments
693             },
694         };
695 
696         const VkSubpassDependency subpassDependency = {
697             0u,                                            // srcSubpass;
698             1u,                                            // dstSubpass;
699             VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, // srcStageMask;
700             VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,         // dstStageMask;
701             VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,          // srcAccessMask;
702             VK_ACCESS_INPUT_ATTACHMENT_READ_BIT,           // dstAccessMask;
703             0                                              // dependencyFlags;
704         };
705 
706         const VkRenderPassCreateInfo renderPassParams = {
707             VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, // sType
708             DE_NULL,                                   // pNext
709             (vk::VkRenderPassCreateFlags)0,
710             (uint32_t)attachmentDescriptions.size(),        // attachmentCount
711             &attachmentDescriptions[0],                     // pAttachments
712             sizeof(subpassDescs) / sizeof(subpassDescs[0]), // subpassCount
713             subpassDescs,                                   // pSubpasses
714             1u,                                             // dependencyCount
715             &subpassDependency,                             // pDependencies
716         };
717 
718         renderPass = createRenderPass(vk, device, &renderPassParams);
719     }
720 
721     // Create framebuffer
722     Move<VkFramebuffer> framebuffer;
723     {
724         std::vector<VkImageView> attachments;
725         attachments.push_back(*cbImagePass0View);
726         attachments.push_back(*cbImagePass1View);
727 
728         const vk::VkFramebufferCreateInfo framebufferParams = {
729             vk::VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, // sType
730             DE_NULL,                                       // pNext
731             (vk::VkFramebufferCreateFlags)(0),             // createFlags
732             *renderPass,                                   // renderPass
733             (uint32_t)attachments.size(),                  // attachmentCount
734             &attachments[0],                               // pAttachments
735             m_data.framebufferExtent.width,                // width
736             m_data.framebufferExtent.height,               // height
737             1u,                                            // layers
738         };
739 
740         framebuffer = createFramebuffer(vk, device, &framebufferParams);
741     }
742 
743     // Create vertex attribute
744     const VkVertexInputBindingDescription vertexBinding = {
745         0u,                         // uint32_t binding;
746         sizeof(Vertex),             // uint32_t stride;
747         VK_VERTEX_INPUT_RATE_VERTEX // VkVertexInputRate inputRate;
748     };
749 
750     const VkVertexInputAttributeDescription vertexInputAttributeDescription = {
751         0u,                      // uint32_t location;
752         0u,                      // uint32_t binding;
753         VK_FORMAT_R32G32_SFLOAT, // VkFormat format;
754         0u                       // uint32_t offset;
755     };
756 
757     const VkPipelineVertexInputStateCreateInfo vertexInputStateCreateInfo = {
758         VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType sType;
759         DE_NULL,                                                   // const void* pNext;
760         (VkPipelineVertexInputStateCreateFlags)0,                  // VkPipelineVertexInputStateCreateFlags flags;
761         1u,                                                        // uint32_t vertexBindingDescriptionCount;
762         &vertexBinding,                  // const VkVertexInputBindingDescription* pVertexBindingDescriptions;
763         1u,                              // uint32_t vertexAttributeDescriptionCount;
764         &vertexInputAttributeDescription // const VkVertexInputAttributeDescription* pVertexAttributeDescriptions;
765     };
766 
767     const VkPipelineInputAssemblyStateCreateInfo inputAssemblyStateCreateInfo = {
768         VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, // VkStructureType sType;
769         DE_NULL,                                                     // const void* pNext;
770         (VkPipelineInputAssemblyStateCreateFlags)0,                  // VkPipelineInputAssemblyStateCreateFlags flags;
771         VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,                         // VkPrimitiveTopology topology;
772         VK_FALSE                                                     // VkBool32 primitiveRestartEnable;
773     };
774 
775     // Create rasterization state
776     const VkPipelineRasterizationStateCreateInfo rasterizationStateCreateInfo = {
777         VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, // VkStructureType sType;
778         DE_NULL,                                                    // const void* pNext;
779         (VkPipelineRasterizationStateCreateFlags)0,                 // VkPipelineRasterizationStateCreateFlags flags;
780         VK_FALSE,                                                   // VkBool32 depthClampEnable;
781         VK_FALSE,                                                   // VkBool32 rasterizerDiscardEnable;
782         VK_POLYGON_MODE_FILL,                                       // VkPolygonMode polygonMode;
783         VK_CULL_MODE_NONE,                                          // VkCullModeFlags cullMode;
784         VK_FRONT_FACE_CLOCKWISE,                                    // VkFrontFace frontFace;
785         VK_FALSE,                                                   // VkBool32 depthBiasEnable;
786         0.0f,                                                       // float depthBiasConstantFactor;
787         0.0f,                                                       // float depthBiasClamp;
788         0.0f,                                                       // float depthBiasSlopeFactor;
789         1.0f                                                        // float lineWidth;
790     };
791 
792     // Create scissor and viewport
793     VkViewport viewport = makeViewport(m_data.framebufferExtent.width, m_data.framebufferExtent.height);
794     VkRect2D scissor    = makeRect2D(m_data.framebufferExtent.width, m_data.framebufferExtent.height);
795 
796     const VkPipelineViewportStateCreateInfo viewportStateCreateInfo = {
797         VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, // VkStructureType                            sType
798         DE_NULL,                                               // const void*                                pNext
799         (VkPipelineViewportStateCreateFlags)0,                 // VkPipelineViewportStateCreateFlags        flags
800         1u,        // uint32_t                                    viewportCount
801         &viewport, // const VkViewport*                        pViewports
802         1u,        // uint32_t                                    scissorCount
803         &scissor   // const VkRect2D*                            pScissors
804     };
805 
806     const VkPipelineDynamicStateCreateInfo dynamicStateCreateInfo = {
807         VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, // VkStructureType   sType;
808         DE_NULL,                                              // const void*   pNext;
809         (VkPipelineDynamicStateCreateFlags)0,                 // VkPipelineDynamicStateCreateFlags flags;
810         0u,                                                   // uint32_t  dynamicStateCount;
811         DE_NULL,                                              // const VkDynamicState* pDynamicStates;
812     };
813 
814     const VkPipelineColorBlendAttachmentState colorBlendAttachmentState[] = {{
815         VK_FALSE,             // VkBool32 blendEnable;
816         VK_BLEND_FACTOR_ZERO, // VkBlendFactor srcColorBlendFactor;
817         VK_BLEND_FACTOR_ZERO, // VkBlendFactor dstColorBlendFactor;
818         VK_BLEND_OP_ADD,      // VkBlendOp colorBlendOp;
819         VK_BLEND_FACTOR_ZERO, // VkBlendFactor srcAlphaBlendFactor;
820         VK_BLEND_FACTOR_ZERO, // VkBlendFactor dstAlphaBlendFactor;
821         VK_BLEND_OP_ADD,      // VkBlendOp alphaBlendOp;
822         0xf                   // VkColorComponentFlags colorWriteMask;
823     }};
824 
825     const VkPipelineColorBlendStateCreateInfo colorBlendStateCreateInfo = {
826         VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, // VkStructureType sType;
827         DE_NULL,                                                  // const void* pNext;
828         0u,                                                       // VkPipelineColorBlendStateCreateFlags flags;
829         VK_FALSE,                                                 // VkBool32 logicOpEnable;
830         VK_LOGIC_OP_COPY,                                         // VkLogicOp logicOp;
831         sizeof(colorBlendAttachmentState) / sizeof(colorBlendAttachmentState[0]), // uint32_t attachmentCount;
832         colorBlendAttachmentState, // const VkPipelineColorBlendAttachmentState* pAttachments;
833         {1.0f, 1.0f, 1.0f, 1.0f}   // float blendConstants[4];
834     };
835 
836     VkPipelineDepthStencilStateCreateInfo depthStencilStateParams = {
837         VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, // VkStructureType sType;
838         DE_NULL,                                                    // const void* pNext;
839         0u,                                                         // VkPipelineDepthStencilStateCreateFlags flags;
840         VK_FALSE,                                                   // VkBool32 depthTestEnable;
841         VK_FALSE,                                                   // VkBool32 depthWriteEnable;
842         VK_COMPARE_OP_ALWAYS,                                       // VkCompareOp depthCompareOp;
843         VK_FALSE,                                                   // VkBool32 depthBoundsTestEnable;
844         VK_FALSE,                                                   // VkBool32 stencilTestEnable;
845         // VkStencilOpState front;
846         {
847             VK_STENCIL_OP_REPLACE, // VkStencilOp failOp;
848             VK_STENCIL_OP_REPLACE, // VkStencilOp passOp;
849             VK_STENCIL_OP_REPLACE, // VkStencilOp depthFailOp;
850             VK_COMPARE_OP_ALWAYS,  // VkCompareOp compareOp;
851             0u,                    // uint32_t compareMask;
852             0xFFu,                 // uint32_t writeMask;
853             0xFFu,                 // uint32_t reference;
854         },
855         // VkStencilOpState back;
856         {
857             VK_STENCIL_OP_REPLACE, // VkStencilOp failOp;
858             VK_STENCIL_OP_REPLACE, // VkStencilOp passOp;
859             VK_STENCIL_OP_REPLACE, // VkStencilOp depthFailOp;
860             VK_COMPARE_OP_ALWAYS,  // VkCompareOp compareOp;
861             0u,                    // uint32_t compareMask;
862             0xFFu,                 // uint32_t writeMask;
863             0xFFu,                 // uint32_t reference;
864         },
865         0.0f, // float minDepthBounds;
866         0.0f, // float maxDepthBounds;
867     };
868 
869     // Create pipeline for pass 0
870     Move<VkPipeline> pipelinePass0;
871     Move<VkPipelineLayout> pipelineLayoutPass0;
872     {
873         const VkPushConstantRange pushConstantRange = {
874             VK_SHADER_STAGE_FRAGMENT_BIT, // VkShaderStageFlags stageFlags;
875             0u,                           // uint32_t offset;
876             2 * sizeof(VkExtent2D)        // uint32_t size;
877         };
878 
879         const VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo = {
880             VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, // sType
881             DE_NULL,                                       // pNext
882             (VkPipelineLayoutCreateFlags)0,
883             0u,                 // setLayoutCount
884             DE_NULL,            // pSetLayouts
885             1u,                 // pushConstantRangeCount
886             &pushConstantRange, // pPushConstantRanges
887         };
888 
889         pipelineLayoutPass0 = createPipelineLayout(vk, device, &pipelineLayoutCreateInfo, NULL);
890 
891         const VkPipelineMultisampleStateCreateInfo multisampleStateCreateInfo = {
892             VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, // VkStructureType                            sType
893             DE_NULL,                                                  // const void*                    pNext
894             0u,                                                       // VkPipelineMultisampleStateCreateFlags    flags
895             (VkSampleCountFlagBits)m_data.samples, // VkSampleCountFlagBits                    rasterizationSamples
896             VK_FALSE,                              // VkBool32                                    sampleShadingEnable
897             1.0f,                                  // float                                    minSampleShading
898             DE_NULL,                               // const VkSampleMask*                        pSampleMask
899             VK_FALSE,                              // VkBool32                                    alphaToCoverageEnable
900             VK_FALSE                               // VkBool32                                    alphaToOneEnable
901         };
902 
903         Move<VkShaderModule> vertShader =
904             createShaderModule(vk, device, m_context.getBinaryCollection().get("vert"), 0);
905         Move<VkShaderModule> fragShader =
906             createShaderModule(vk, device, m_context.getBinaryCollection().get("frag_pass0"), 0);
907 
908         const VkPipelineShaderStageCreateInfo shaderCreateInfo[] = {
909             {
910                 VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, DE_NULL, (VkPipelineShaderStageCreateFlags)0,
911                 VK_SHADER_STAGE_VERTEX_BIT, // stage
912                 *vertShader,                // shader
913                 "main",
914                 DE_NULL, // pSpecializationInfo
915             },
916             {
917                 VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, DE_NULL, (VkPipelineShaderStageCreateFlags)0,
918                 VK_SHADER_STAGE_FRAGMENT_BIT, // stage
919                 *fragShader,                  // shader
920                 "main",
921                 DE_NULL, // pSpecializationInfo
922             }};
923 
924         const VkGraphicsPipelineCreateInfo graphicsPipelineCreateInfo = {
925             VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,        // VkStructureType sType;
926             DE_NULL,                                                // const void* pNext;
927             (VkPipelineCreateFlags)0,                               // VkPipelineCreateFlags flags;
928             sizeof(shaderCreateInfo) / sizeof(shaderCreateInfo[0]), // uint32_t stageCount;
929             &shaderCreateInfo[0],                                   // const VkPipelineShaderStageCreateInfo* pStages;
930             &vertexInputStateCreateInfo,   // const VkPipelineVertexInputStateCreateInfo* pVertexInputState;
931             &inputAssemblyStateCreateInfo, // const VkPipelineInputAssemblyStateCreateInfo* pInputAssemblyState;
932             DE_NULL,                       // const VkPipelineTessellationStateCreateInfo* pTessellationState;
933             &viewportStateCreateInfo,      // const VkPipelineViewportStateCreateInfo* pViewportState;
934             &rasterizationStateCreateInfo, // const VkPipelineRasterizationStateCreateInfo* pRasterizationState;
935             &multisampleStateCreateInfo,   // const VkPipelineMultisampleStateCreateInfo* pMultisampleState;
936             &depthStencilStateParams,      // const VkPipelineDepthStencilStateCreateInfo* pDepthStencilState;
937             &colorBlendStateCreateInfo,    // const VkPipelineColorBlendStateCreateInfo* pColorBlendState;
938             &dynamicStateCreateInfo,       // const VkPipelineDynamicStateCreateInfo* pDynamicState;
939             pipelineLayoutPass0.get(),     // VkPipelineLayout layout;
940             renderPass.get(),              // VkRenderPass renderPass;
941             0u,                            // uint32_t subpass;
942             DE_NULL,                       // VkPipeline basePipelineHandle;
943             0                              // int basePipelineIndex;
944         };
945 
946         pipelinePass0 = createGraphicsPipeline(vk, device, DE_NULL, &graphicsPipelineCreateInfo);
947     }
948 
949     // Create pipeline for pass 1
950     Move<VkPipeline> pipelinePass1;
951     Move<VkPipelineLayout> pipelineLayoutPass1;
952     Move<vk::VkDescriptorPool> descriptorPool;
953     Move<vk::VkDescriptorSetLayout> descriptorSetLayout;
954     Move<vk::VkDescriptorSet> descriptorSet;
955     {
956         const VkDescriptorSetLayoutBinding bindings[] = {{
957             0u,                                  // binding
958             VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, // descriptorType
959             1u,                                  // descriptorCount
960             VK_SHADER_STAGE_FRAGMENT_BIT,        // stageFlags
961             DE_NULL,                             // pImmutableSamplers
962         }};
963 
964         // Create a layout and allocate a descriptor set for it.
965         const VkDescriptorSetLayoutCreateInfo setLayoutCreateInfo = {
966             vk::VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, // sType
967             DE_NULL,                                                 // pNext
968             (VkDescriptorSetLayoutCreateFlags)(0),                   // flags
969             sizeof(bindings) / sizeof(bindings[0]),                  // bindingCount
970             &bindings[0]                                             // pBindings
971         };
972 
973         descriptorSetLayout = vk::createDescriptorSetLayout(vk, device, &setLayoutCreateInfo);
974 
975         vk::DescriptorPoolBuilder poolBuilder;
976 
977         for (int32_t i = 0; i < (int32_t)(sizeof(bindings) / sizeof(bindings[0])); ++i)
978         {
979             poolBuilder.addType(bindings[i].descriptorType, bindings[i].descriptorCount);
980         }
981 
982         descriptorPool = poolBuilder.build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
983         descriptorSet  = makeDescriptorSet(vk, device, *descriptorPool, *descriptorSetLayout);
984 
985         VkDescriptorImageInfo imageInfo = makeDescriptorImageInfo(DE_NULL, *cbImagePass0View, VK_IMAGE_LAYOUT_GENERAL);
986 
987         VkWriteDescriptorSet writeDescriptorSet = {
988             VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, // sType
989             DE_NULL,                                // pNext
990             *descriptorSet,                         // dstSet
991             0u,                                     // dstBinding
992             0u,                                     // dstArrayElement
993             1u,                                     // descriptorCount
994             bindings[0].descriptorType,             // descriptorType
995             &imageInfo,                             // pImageInfo
996             DE_NULL,                                // pBufferInfo
997             DE_NULL,                                // pTexelBufferView
998         };
999 
1000         vk.updateDescriptorSets(device, 1, &writeDescriptorSet, 0, NULL);
1001 
1002         const VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo = {
1003             VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, // sType
1004             DE_NULL,                                       // pNext
1005             (VkPipelineLayoutCreateFlags)0,
1006             1u,                         // setLayoutCount
1007             &descriptorSetLayout.get(), // pSetLayouts
1008             0u,                         // pushConstantRangeCount
1009             DE_NULL,                    // pPushConstantRanges
1010         };
1011 
1012         pipelineLayoutPass1 = createPipelineLayout(vk, device, &pipelineLayoutCreateInfo, NULL);
1013 
1014         const VkPipelineMultisampleStateCreateInfo multisampleStateCreateInfo = {
1015             VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, // VkStructureType                            sType
1016             DE_NULL,               // const void*                                pNext
1017             0u,                    // VkPipelineMultisampleStateCreateFlags    flags
1018             VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits                    rasterizationSamples
1019             VK_FALSE,              // VkBool32                                    sampleShadingEnable
1020             1.0f,                  // float                                    minSampleShading
1021             DE_NULL,               // const VkSampleMask*                        pSampleMask
1022             VK_FALSE,              // VkBool32                                    alphaToCoverageEnable
1023             VK_FALSE               // VkBool32                                    alphaToOneEnable
1024         };
1025 
1026         VkPipelineFragmentShadingRateStateCreateInfoKHR shadingRateStateCreateInfo = {
1027             VK_STRUCTURE_TYPE_PIPELINE_FRAGMENT_SHADING_RATE_STATE_CREATE_INFO_KHR, // VkStructureType sType;
1028             DE_NULL,                                                                // const void* pNext;
1029             m_data.shadingRate,                                                     // VkExtent2D fragmentSize;
1030             {VK_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP_KHR,
1031              VK_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP_KHR}, // VkFragmentShadingRateCombinerOpKHR combinerOps[2];
1032         };
1033 
1034         Move<VkShaderModule> vertShader =
1035             createShaderModule(vk, device, m_context.getBinaryCollection().get("vert"), 0);
1036         Move<VkShaderModule> fragShader =
1037             createShaderModule(vk, device, m_context.getBinaryCollection().get("frag_pass1"), 0);
1038 
1039         const VkPipelineShaderStageCreateInfo shaderCreateInfo[] = {
1040             {
1041                 VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, DE_NULL, (VkPipelineShaderStageCreateFlags)0,
1042                 VK_SHADER_STAGE_VERTEX_BIT, // stage
1043                 *vertShader,                // shader
1044                 "main",
1045                 DE_NULL, // pSpecializationInfo
1046             },
1047             {
1048                 VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, DE_NULL, (VkPipelineShaderStageCreateFlags)0,
1049                 VK_SHADER_STAGE_FRAGMENT_BIT, // stage
1050                 *fragShader,                  // shader
1051                 "main",
1052                 DE_NULL, // pSpecializationInfo
1053             }};
1054 
1055         const VkGraphicsPipelineCreateInfo graphicsPipelineCreateInfo = {
1056             VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,        // VkStructureType sType;
1057             &shadingRateStateCreateInfo,                            // const void* pNext;
1058             (VkPipelineCreateFlags)0,                               // VkPipelineCreateFlags flags;
1059             sizeof(shaderCreateInfo) / sizeof(shaderCreateInfo[0]), // uint32_t stageCount;
1060             &shaderCreateInfo[0],                                   // const VkPipelineShaderStageCreateInfo* pStages;
1061             &vertexInputStateCreateInfo,   // const VkPipelineVertexInputStateCreateInfo* pVertexInputState;
1062             &inputAssemblyStateCreateInfo, // const VkPipelineInputAssemblyStateCreateInfo* pInputAssemblyState;
1063             DE_NULL,                       // const VkPipelineTessellationStateCreateInfo* pTessellationState;
1064             &viewportStateCreateInfo,      // const VkPipelineViewportStateCreateInfo* pViewportState;
1065             &rasterizationStateCreateInfo, // const VkPipelineRasterizationStateCreateInfo* pRasterizationState;
1066             &multisampleStateCreateInfo,   // const VkPipelineMultisampleStateCreateInfo* pMultisampleState;
1067             &depthStencilStateParams,      // const VkPipelineDepthStencilStateCreateInfo* pDepthStencilState;
1068             &colorBlendStateCreateInfo,    // const VkPipelineColorBlendStateCreateInfo* pColorBlendState;
1069             &dynamicStateCreateInfo,       // const VkPipelineDynamicStateCreateInfo* pDynamicState;
1070             pipelineLayoutPass1.get(),     // VkPipelineLayout layout;
1071             renderPass.get(),              // VkRenderPass renderPass;
1072             1u,                            // uint32_t subpass;
1073             DE_NULL,                       // VkPipeline basePipelineHandle;
1074             0                              // int basePipelineIndex;
1075         };
1076 
1077         pipelinePass1 = createGraphicsPipeline(vk, device, DE_NULL, &graphicsPipelineCreateInfo);
1078     }
1079 
1080     // Create command buffer
1081     Move<VkCommandPool> cmdPool     = createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,
1082                                                         m_context.getUniversalQueueFamilyIndex());
1083     Move<VkCommandBuffer> cmdBuffer = allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
1084 
1085     VkImageMemoryBarrier preImageBarriers[] = {{VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType        sType
1086                                                 DE_NULL,                                // const void*            pNext
1087                                                 0u,                           // VkAccessFlags        srcAccessMask
1088                                                 VK_ACCESS_TRANSFER_WRITE_BIT, // VkAccessFlags        dstAccessMask
1089                                                 VK_IMAGE_LAYOUT_UNDEFINED,    // VkImageLayout        oldLayout
1090                                                 VK_IMAGE_LAYOUT_GENERAL,      // VkImageLayout        newLayout
1091                                                 VK_QUEUE_FAMILY_IGNORED, // uint32_t                srcQueueFamilyIndex
1092                                                 VK_QUEUE_FAMILY_IGNORED, // uint32_t                dstQueueFamilyIndex
1093                                                 **cbImagePass0,          // VkImage                image
1094                                                 {
1095                                                     VK_IMAGE_ASPECT_COLOR_BIT, // VkImageAspectFlags    aspectMask
1096                                                     0u,                        // uint32_t                baseMipLevel
1097                                                     VK_REMAINING_MIP_LEVELS,   // uint32_t                mipLevels,
1098                                                     0u,                        // uint32_t                baseArray
1099                                                     VK_REMAINING_ARRAY_LAYERS, // uint32_t                arraySize
1100                                                 }},
1101                                                {VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType        sType
1102                                                 DE_NULL,                                // const void*            pNext
1103                                                 0u,                           // VkAccessFlags        srcAccessMask
1104                                                 VK_ACCESS_TRANSFER_WRITE_BIT, // VkAccessFlags        dstAccessMask
1105                                                 VK_IMAGE_LAYOUT_UNDEFINED,    // VkImageLayout        oldLayout
1106                                                 VK_IMAGE_LAYOUT_GENERAL,      // VkImageLayout        newLayout
1107                                                 VK_QUEUE_FAMILY_IGNORED, // uint32_t                srcQueueFamilyIndex
1108                                                 VK_QUEUE_FAMILY_IGNORED, // uint32_t                dstQueueFamilyIndex
1109                                                 **cbImagePass1,          // VkImage                image
1110                                                 {
1111                                                     VK_IMAGE_ASPECT_COLOR_BIT, // VkImageAspectFlags    aspectMask
1112                                                     0u,                        // uint32_t                baseMipLevel
1113                                                     VK_REMAINING_MIP_LEVELS,   // uint32_t                mipLevels,
1114                                                     0u,                        // uint32_t                baseArray
1115                                                     VK_REMAINING_ARRAY_LAYERS, // uint32_t                arraySize
1116                                                 }}};
1117 
1118     // Record commands
1119     beginCommandBuffer(vk, *cmdBuffer, 0u);
1120 
1121     vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
1122                           (VkDependencyFlags)0, 0, (const VkMemoryBarrier *)DE_NULL, 0,
1123                           (const VkBufferMemoryBarrier *)DE_NULL,
1124                           sizeof(preImageBarriers) / sizeof(preImageBarriers[0]), preImageBarriers);
1125 
1126     // Clear both images to UINT_MAX
1127     VkImageSubresourceRange range = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
1128     VkClearValue clearColor       = makeClearValueColorU32(std::numeric_limits<unsigned int>::max(), 0, 0, 0);
1129 
1130     vk.cmdClearColorImage(*cmdBuffer, **cbImagePass0, VK_IMAGE_LAYOUT_GENERAL, &clearColor.color, 1, &range);
1131     vk.cmdClearColorImage(*cmdBuffer, **cbImagePass1, VK_IMAGE_LAYOUT_GENERAL, &clearColor.color, 1, &range);
1132 
1133     // Barrier between the clear and the rendering
1134     VkImageMemoryBarrier clearColorBarriers[] = {
1135         {VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType        sType
1136          DE_NULL,                                // const void*            pNext
1137          VK_ACCESS_TRANSFER_WRITE_BIT,           // VkAccessFlags        srcAccessMask
1138          VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,   // VkAccessFlags        dstAccessMask
1139          VK_IMAGE_LAYOUT_GENERAL,                // VkImageLayout        oldLayout
1140          VK_IMAGE_LAYOUT_GENERAL,                // VkImageLayout        newLayout
1141          VK_QUEUE_FAMILY_IGNORED,                // uint32_t                srcQueueFamilyIndex
1142          VK_QUEUE_FAMILY_IGNORED,                // uint32_t                dstQueueFamilyIndex
1143          **cbImagePass0,                         // VkImage                image
1144          {
1145              VK_IMAGE_ASPECT_COLOR_BIT, // VkImageAspectFlags    aspectMask
1146              0u,                        // uint32_t                baseMipLevel
1147              VK_REMAINING_MIP_LEVELS,   // uint32_t                mipLevels,
1148              0u,                        // uint32_t                baseArray
1149              VK_REMAINING_ARRAY_LAYERS, // uint32_t                arraySize
1150          }},
1151         {VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType        sType
1152          DE_NULL,                                // const void*            pNext
1153          VK_ACCESS_TRANSFER_WRITE_BIT,           // VkAccessFlags        srcAccessMask
1154          VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,   // VkAccessFlags        dstAccessMask
1155          VK_IMAGE_LAYOUT_GENERAL,                // VkImageLayout        oldLayout
1156          VK_IMAGE_LAYOUT_GENERAL,                // VkImageLayout        newLayout
1157          VK_QUEUE_FAMILY_IGNORED,                // uint32_t                srcQueueFamilyIndex
1158          VK_QUEUE_FAMILY_IGNORED,                // uint32_t                dstQueueFamilyIndex
1159          **cbImagePass1,                         // VkImage                image
1160          {
1161              VK_IMAGE_ASPECT_COLOR_BIT, // VkImageAspectFlags    aspectMask
1162              0u,                        // uint32_t                baseMipLevel
1163              VK_REMAINING_MIP_LEVELS,   // uint32_t                mipLevels,
1164              0u,                        // uint32_t                baseArray
1165              VK_REMAINING_ARRAY_LAYERS, // uint32_t                arraySize
1166          }}};
1167 
1168     vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
1169                           (VkDependencyFlags)0, 0, (const VkMemoryBarrier *)DE_NULL, 0,
1170                           (const VkBufferMemoryBarrier *)DE_NULL,
1171                           sizeof(clearColorBarriers) / sizeof(clearColorBarriers[0]), clearColorBarriers);
1172 
1173     beginRenderPass(vk, *cmdBuffer, *renderPass, *framebuffer,
1174                     makeRect2D(m_data.framebufferExtent.width, m_data.framebufferExtent.height), 0, DE_NULL,
1175                     VK_SUBPASS_CONTENTS_INLINE, DE_NULL);
1176 
1177     // Put primitive shading rate in a push constant
1178     if (m_shadingRateClamped.size() == 1)
1179     {
1180         vk.cmdPushConstants(*cmdBuffer, *pipelineLayoutPass0, VK_SHADER_STAGE_FRAGMENT_BIT, 0,
1181                             sizeof(m_shadingRateClamped[0]), &m_shadingRateClamped[0]);
1182         vk.cmdPushConstants(*cmdBuffer, *pipelineLayoutPass0, VK_SHADER_STAGE_FRAGMENT_BIT,
1183                             sizeof(m_shadingRateClamped[0]), sizeof(m_shadingRateClamped[0]), &m_shadingRateClamped[0]);
1184     }
1185     else
1186     {
1187         vk.cmdPushConstants(*cmdBuffer, *pipelineLayoutPass0, VK_SHADER_STAGE_FRAGMENT_BIT, 0,
1188                             static_cast<uint32_t>(m_shadingRateClamped.size() * sizeof(m_shadingRateClamped[0])),
1189                             &m_shadingRateClamped[0]);
1190     }
1191 
1192     // Bind vertex buffer
1193     const VkDeviceSize vertexBufferOffset = 0;
1194     VkBuffer vb                           = **vertexBuffer;
1195     vk.cmdBindVertexBuffers(*cmdBuffer, 0, 1, &vb, &vertexBufferOffset);
1196 
1197     // Bind pipeline
1198     vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipelinePass0);
1199 
1200     // Draw triangles
1201     vk.cmdDraw(*cmdBuffer, sizeof(basicTriangles) / sizeof(Vertex), 1u, 0u, 0u);
1202 
1203     // Start next subpass
1204     vk.cmdNextSubpass(*cmdBuffer, VK_SUBPASS_CONTENTS_INLINE);
1205 
1206     // Bind descriptors
1207     vk.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipelineLayoutPass1, 0, 1,
1208                              &descriptorSet.get(), 0, DE_NULL);
1209 
1210     // Bind vertex buffer
1211     vk.cmdBindVertexBuffers(*cmdBuffer, 0, 1, &vb, &vertexBufferOffset);
1212 
1213     // Bind pipeline
1214     vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipelinePass1);
1215 
1216     // Draw triangles
1217     vk.cmdDraw(*cmdBuffer, sizeof(basicTriangles) / sizeof(Vertex), 1u, 0u, 0u);
1218 
1219     endRenderPass(vk, *cmdBuffer);
1220 
1221     VkImageMemoryBarrier postImageBarrier = {VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType        sType
1222                                              DE_NULL,                                // const void*            pNext
1223                                              VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, // VkAccessFlags        srcAccessMask
1224                                              VK_ACCESS_TRANSFER_READ_BIT,          // VkAccessFlags        dstAccessMask
1225                                              VK_IMAGE_LAYOUT_GENERAL,              // VkImageLayout        oldLayout
1226                                              VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, // VkImageLayout        newLayout
1227                                              VK_QUEUE_FAMILY_IGNORED, // uint32_t                srcQueueFamilyIndex
1228                                              VK_QUEUE_FAMILY_IGNORED, // uint32_t                dstQueueFamilyIndex
1229                                              **cbImagePass1,          // VkImage                image
1230                                              {
1231                                                  VK_IMAGE_ASPECT_COLOR_BIT, // VkImageAspectFlags    aspectMask
1232                                                  0u,                        // uint32_t                baseMipLevel
1233                                                  VK_REMAINING_MIP_LEVELS,   // uint32_t                mipLevels,
1234                                                  0u,                        // uint32_t                baseArray
1235                                                  VK_REMAINING_ARRAY_LAYERS, // uint32_t                arraySize
1236                                              }};
1237 
1238     vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
1239                           (VkDependencyFlags)0, 0, (const VkMemoryBarrier *)DE_NULL, 0,
1240                           (const VkBufferMemoryBarrier *)DE_NULL, 1, &postImageBarrier);
1241 
1242     const VkBufferImageCopy copyRegion = {
1243         0u, // VkDeviceSize bufferOffset;
1244         0u, // uint32_t bufferRowLength;
1245         0u, // uint32_t bufferImageHeight;
1246         {
1247             VK_IMAGE_ASPECT_COLOR_BIT, // VkImageAspectFlags aspect;
1248             0u,                        // uint32_t mipLevel;
1249             0u,                        // uint32_t baseArrayLayer;
1250             1u,                        // uint32_t layerCount;
1251         },                             // VkImageSubresourceLayers imageSubresource;
1252         {0, 0, 0},                     // VkOffset3D imageOffset;
1253         {m_data.framebufferExtent.width, m_data.framebufferExtent.height, 1} // VkExtent3D imageExtent;
1254     };
1255 
1256     vk.cmdCopyImageToBuffer(*cmdBuffer, **cbImagePass1, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, **colorOutputBuffer, 1u,
1257                             &copyRegion);
1258 
1259     const VkBufferMemoryBarrier bufferBarrier = {
1260         VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, // VkStructureType sType;
1261         DE_NULL,                                 // const void* pNext;
1262         VK_ACCESS_TRANSFER_WRITE_BIT,            // VkAccessFlags srcAccessMask;
1263         VK_ACCESS_HOST_READ_BIT,                 // VkAccessFlags dstAccessMask;
1264         VK_QUEUE_FAMILY_IGNORED,                 // uint32_t srcQueueFamilyIndex;
1265         VK_QUEUE_FAMILY_IGNORED,                 // uint32_t dstQueueFamilyIndex;
1266         **colorOutputBuffer,                     // VkBuffer buffer;
1267         0ull,                                    // VkDeviceSize offset;
1268         VK_WHOLE_SIZE                            // VkDeviceSize size;
1269     };
1270 
1271     vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, (VkDependencyFlags)0,
1272                           0, (const VkMemoryBarrier *)DE_NULL, 1, &bufferBarrier, 0,
1273                           (const VkImageMemoryBarrier *)DE_NULL);
1274 
1275     endCommandBuffer(vk, *cmdBuffer);
1276 
1277     submitCommandsAndWait(vk, device, queue, cmdBuffer.get());
1278 
1279     // Read buffer data
1280     invalidateAlloc(vk, device, colorOutputBuffer->getAllocation());
1281 
1282     tcu::ConstPixelBufferAccess resultBuffer = tcu::ConstPixelBufferAccess(
1283         tcu::TextureFormat(tcu::TextureFormat::RG, tcu::TextureFormat::UNSIGNED_INT32), m_data.framebufferExtent.width,
1284         m_data.framebufferExtent.height, 1, (const void *)colorOutputBuffer->getAllocation().getHostPtr());
1285 
1286     for (uint32_t i = 0; i < m_shadingRateClamped.size(); i++)
1287     {
1288         tcu::TestStatus result = verifyResult(resultBuffer, i);
1289         if (result.getCode() == QP_TEST_RESULT_PASS)
1290         {
1291             return result;
1292         }
1293     }
1294 
1295     return tcu::TestStatus(QP_TEST_RESULT_FAIL, qpGetTestResultName(QP_TEST_RESULT_FAIL));
1296 }
1297 
1298 } // namespace
1299 
createPixelConsistencyTests(tcu::TestContext & testCtx,tcu::TestCaseGroup * parentGroup)1300 void createPixelConsistencyTests(tcu::TestContext &testCtx, tcu::TestCaseGroup *parentGroup)
1301 {
1302     typedef struct
1303     {
1304         uint32_t count;
1305         const char *name;
1306     } TestGroupCase;
1307 
1308     typedef struct
1309     {
1310         VkExtent2D count;
1311         const char *name;
1312     } TestGroupCase2D;
1313 
1314     TestGroupCase2D shadingRateCases[] = {
1315         {{1, 1}, "rate_1x1"},
1316         {{1, 2}, "rate_1x2"},
1317         {{1, 4}, "rate_1x4"},
1318         {{2, 1}, "rate_2x1"},
1319         {{2, 2}, "rate_2x2"},
1320         {
1321             {2, 4},
1322             "rate_2x4",
1323         },
1324         {
1325             {4, 1},
1326             "rate_4x1",
1327         },
1328         {
1329             {4, 2},
1330             "rate_4x2",
1331         },
1332         {
1333             {4, 4},
1334             "rate_4x4",
1335         },
1336     };
1337 
1338     TestGroupCase sampCases[] = {
1339         {VK_SAMPLE_COUNT_1_BIT, "samples_1"},   {VK_SAMPLE_COUNT_2_BIT, "samples_2"},
1340         {VK_SAMPLE_COUNT_4_BIT, "samples_4"},   {VK_SAMPLE_COUNT_8_BIT, "samples_8"},
1341         {VK_SAMPLE_COUNT_16_BIT, "samples_16"},
1342     };
1343 
1344     TestGroupCase2D extentCases[] = {
1345         {{1, 1}, "extent_1x1"},         {{4, 4}, "extent_4x4"},         {{33, 35}, "extent_33x35"},
1346         {{151, 431}, "extent_151x431"}, {{256, 256}, "extent_256x256"},
1347     };
1348 
1349     de::MovePtr<tcu::TestCaseGroup> pixelGroup(new tcu::TestCaseGroup(testCtx, "pixel_consistency"));
1350 
1351     for (int rateNdx = 0; rateNdx < DE_LENGTH_OF_ARRAY(shadingRateCases); rateNdx++)
1352     {
1353         de::MovePtr<tcu::TestCaseGroup> rateGroup(new tcu::TestCaseGroup(testCtx, shadingRateCases[rateNdx].name));
1354 
1355         for (int sampNdx = 0; sampNdx < DE_LENGTH_OF_ARRAY(sampCases); sampNdx++)
1356         {
1357             de::MovePtr<tcu::TestCaseGroup> sampleGroup(new tcu::TestCaseGroup(testCtx, sampCases[sampNdx].name));
1358             for (int extNdx = 0; extNdx < DE_LENGTH_OF_ARRAY(extentCases); extNdx++)
1359             {
1360                 VkSampleCountFlagBits samples = static_cast<VkSampleCountFlagBits>(sampCases[sampNdx].count);
1361                 VkExtent2D framebufferExtent  = extentCases[extNdx].count;
1362 
1363                 CaseDef caseParams{shadingRateCases[rateNdx].count, samples, framebufferExtent, false};
1364                 sampleGroup->addChild(new FSRPixelConsistencyTestCase(testCtx, extentCases[extNdx].name, caseParams));
1365 
1366                 // test FragCoord.zw but to avoid duplication limit tests to extent_151x431/256x256 and 1 or 4 samples
1367                 if ((framebufferExtent.width > 150) && (samples & (VK_SAMPLE_COUNT_1_BIT | VK_SAMPLE_COUNT_4_BIT)))
1368                 {
1369                     std::string caseName = std::string(extentCases[extNdx].name) + "_zw_coord";
1370                     caseParams.zwCoord   = true;
1371                     sampleGroup->addChild(new FSRPixelConsistencyTestCase(testCtx, caseName.c_str(), caseParams));
1372                 }
1373             }
1374             rateGroup->addChild(sampleGroup.release());
1375         }
1376 
1377         pixelGroup->addChild(rateGroup.release());
1378     }
1379 
1380     parentGroup->addChild(pixelGroup.release());
1381 }
1382 
1383 } // namespace FragmentShadingRate
1384 } // namespace vkt
1385