1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2017 Advanced Micro Devices, Inc.
6  * Copyright (c) 2017 The Khronos Group Inc.
7  * Copyright (c) 2023 LunarG, Inc.
8  * Copyright (c) 2023 Nintendo
9  *
10  * Licensed under the Apache License, Version 2.0 (the "License");
11  * you may not use this file except in compliance with the License.
12  * You may obtain a copy of the License at
13  *
14  *      http://www.apache.org/licenses/LICENSE-2.0
15  *
16  * Unless required by applicable law or agreed to in writing, software
17  * distributed under the License is distributed on an "AS IS" BASIS,
18  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19  * See the License for the specific language governing permissions and
20  * limitations under the License.
21  *
22  *//*!
23  * \file
24  * \brief Tests for VK_EXT_sample_locations
25  *//*--------------------------------------------------------------------*/
26 
27 #include "vktPipelineMultisampleSampleLocationsExtTests.hpp"
28 #include "vktPipelineSampleLocationsUtil.hpp"
29 #include "vktPipelineMakeUtil.hpp"
30 #include "vktTestCase.hpp"
31 #include "vktTestGroupUtil.hpp"
32 #include "vktTestCaseUtil.hpp"
33 
34 #include "vkPlatform.hpp"
35 #include "vkMemUtil.hpp"
36 #include "vkQueryUtil.hpp"
37 #include "vkTypeUtil.hpp"
38 #include "vkRefUtil.hpp"
39 #include "vkBuilderUtil.hpp"
40 #include "vkPrograms.hpp"
41 #include "vkImageUtil.hpp"
42 #include "vkCmdUtil.hpp"
43 #include "vkObjUtil.hpp"
44 
45 #include "deUniquePtr.hpp"
46 #include "deRandom.hpp"
47 #include "deMath.h"
48 
49 #include "tcuTestLog.hpp"
50 #include "tcuImageCompare.hpp"
51 #include "tcuTextureUtil.hpp"
52 #include "tcuRGBA.hpp"
53 #include "tcuVectorUtil.hpp"
54 
55 #include <string>
56 #include <vector>
57 #include <set>
58 #include <algorithm>
59 
60 namespace vkt
61 {
62 namespace pipeline
63 {
64 namespace
65 {
66 using namespace vk;
67 using de::MovePtr;
68 using de::UniquePtr;
69 using tcu::RGBA;
70 using tcu::UVec2;
71 using tcu::UVec4;
72 using tcu::Vec2;
73 using tcu::Vec4;
74 
75 static const uint32_t STENCIL_REFERENCE = 1u;
76 static const float DEPTH_CLEAR          = 1.0f;
77 static const float DEPTH_REFERENCE      = 0.5f;
78 static const Vec4 CLEAR_COLOR_0         = Vec4(0.0f, 0.0f, 0.0f, 1.0f);
79 static const Vec4 CLEAR_COLOR_1         = Vec4(0.5f, 0.25f, 0.75f, 1.0f);
80 static const VkDeviceSize ZERO          = 0u;
81 
82 template <typename T>
dataOrNullPtr(const std::vector<T> & v)83 inline const T *dataOrNullPtr(const std::vector<T> &v)
84 {
85     return (v.empty() ? DE_NULL : &v[0]);
86 }
87 
88 template <typename T>
dataOrNullPtr(std::vector<T> & v)89 inline T *dataOrNullPtr(std::vector<T> &v)
90 {
91     return (v.empty() ? DE_NULL : &v[0]);
92 }
93 
94 template <typename T>
append(std::vector<T> & first,const std::vector<T> & second)95 inline void append(std::vector<T> &first, const std::vector<T> &second)
96 {
97     first.insert(first.end(), second.begin(), second.end());
98 }
99 
100 //! Order a Vector by X, Y, Z, and W
101 template <typename VectorT>
102 struct LessThan
103 {
operator ()vkt::pipeline::__anonf162cbe40111::LessThan104     bool operator()(const VectorT &v1, const VectorT &v2) const
105     {
106         for (int i = 0; i < VectorT::SIZE; ++i)
107         {
108             if (v1[i] == v2[i])
109                 continue;
110             else
111                 return v1[i] < v2[i];
112         }
113 
114         return false;
115     }
116 };
117 
118 //! Similar to the class in vktTestCaseUtil.hpp, but uses Arg0 directly rather than through a InstanceFunction1
119 template <typename Arg0>
120 class FunctionProgramsSimple1
121 {
122 public:
123     typedef void (*Function)(vk::SourceCollections &dst, Arg0 arg0);
FunctionProgramsSimple1(Function func)124     FunctionProgramsSimple1(Function func) : m_func(func)
125     {
126     }
init(vk::SourceCollections & dst,const Arg0 & arg0) const127     void init(vk::SourceCollections &dst, const Arg0 &arg0) const
128     {
129         m_func(dst, arg0);
130     }
131 
132 private:
133     const Function m_func;
134 };
135 
136 //! Convenience function to create a TestCase based on a freestanding initPrograms and a TestInstance implementation
137 template <typename Instance, typename Arg0>
addInstanceTestCaseWithPrograms(tcu::TestCaseGroup * group,const std::string & name,typename FunctionSupport1<Arg0>::Function checkSupport,typename FunctionProgramsSimple1<Arg0>::Function initPrograms,Arg0 arg0)138 void addInstanceTestCaseWithPrograms(tcu::TestCaseGroup *group, const std::string &name,
139                                      typename FunctionSupport1<Arg0>::Function checkSupport,
140                                      typename FunctionProgramsSimple1<Arg0>::Function initPrograms, Arg0 arg0)
141 {
142     group->addChild(
143         new InstanceFactory1WithSupport<Instance, Arg0, FunctionSupport1<Arg0>, FunctionProgramsSimple1<Arg0>>(
144             group->getTestContext(), name, FunctionProgramsSimple1<Arg0>(initPrograms), arg0,
145             typename FunctionSupport1<Arg0>::Args(checkSupport, arg0)));
146 }
147 
checkSupportSampleLocations(Context & context)148 void checkSupportSampleLocations(Context &context)
149 {
150     context.requireDeviceFunctionality("VK_EXT_sample_locations");
151 }
152 
getString(const VkSampleCountFlagBits sampleCount)153 std::string getString(const VkSampleCountFlagBits sampleCount)
154 {
155     std::ostringstream str;
156     str << "samples_" << static_cast<uint32_t>(sampleCount);
157     return str.str();
158 }
159 
isSupportedDepthStencilFormat(const InstanceInterface & vki,const VkPhysicalDevice physDevice,const VkFormat format)160 bool isSupportedDepthStencilFormat(const InstanceInterface &vki, const VkPhysicalDevice physDevice,
161                                    const VkFormat format)
162 {
163     VkFormatProperties formatProps;
164     vki.getPhysicalDeviceFormatProperties(physDevice, format, &formatProps);
165     return (formatProps.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) != 0;
166 }
167 
findSupportedDepthStencilFormat(Context & context,const bool useDepth,const bool useStencil)168 VkFormat findSupportedDepthStencilFormat(Context &context, const bool useDepth, const bool useStencil)
169 {
170     const InstanceInterface &vki      = context.getInstanceInterface();
171     const VkPhysicalDevice physDevice = context.getPhysicalDevice();
172 
173     if (useDepth && !useStencil)
174         return VK_FORMAT_D16_UNORM; // must be supported
175 
176     // One of these formats must be supported.
177 
178     if (isSupportedDepthStencilFormat(vki, physDevice, VK_FORMAT_D24_UNORM_S8_UINT))
179         return VK_FORMAT_D24_UNORM_S8_UINT;
180 
181     if (isSupportedDepthStencilFormat(vki, physDevice, VK_FORMAT_D32_SFLOAT_S8_UINT))
182         return VK_FORMAT_D32_SFLOAT_S8_UINT;
183 
184     return VK_FORMAT_UNDEFINED;
185 }
186 
checkFragmentShadingRateRequirements(Context & context,uint32_t sampleCount)187 void checkFragmentShadingRateRequirements(Context &context, uint32_t sampleCount)
188 {
189     const auto &vki           = context.getInstanceInterface();
190     const auto physicalDevice = context.getPhysicalDevice();
191 
192     context.requireDeviceFunctionality("VK_KHR_fragment_shading_rate");
193 
194     if (!context.getFragmentShadingRateFeatures().pipelineFragmentShadingRate)
195         TCU_THROW(NotSupportedError, "pipelineFragmentShadingRate not supported");
196 
197     // Fetch information about supported fragment shading rates
198     uint32_t supportedFragmentShadingRateCount = 0;
199     vki.getPhysicalDeviceFragmentShadingRatesKHR(physicalDevice, &supportedFragmentShadingRateCount, DE_NULL);
200 
201     std::vector<vk::VkPhysicalDeviceFragmentShadingRateKHR> supportedFragmentShadingRates(
202         supportedFragmentShadingRateCount,
203         {vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_KHR, DE_NULL, vk::VK_SAMPLE_COUNT_1_BIT, {1, 1}});
204     vki.getPhysicalDeviceFragmentShadingRatesKHR(physicalDevice, &supportedFragmentShadingRateCount,
205                                                  supportedFragmentShadingRates.data());
206 
207     bool requiredRateFound = false;
208     for (const auto &rate : supportedFragmentShadingRates)
209     {
210         if ((rate.fragmentSize.width == 2u) && (rate.fragmentSize.height == 2u) && (rate.sampleCounts & sampleCount))
211         {
212             requiredRateFound = true;
213             break;
214         }
215     }
216 
217     if (!requiredRateFound)
218         TCU_THROW(NotSupportedError, "Required FragmentShadingRate not supported");
219 }
220 
getImageAspectFlags(const VkFormat format)221 VkImageAspectFlags getImageAspectFlags(const VkFormat format)
222 {
223     const tcu::TextureFormat tcuFormat = mapVkFormat(format);
224 
225     if (tcuFormat.order == tcu::TextureFormat::DS)
226         return VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
227     else if (tcuFormat.order == tcu::TextureFormat::D)
228         return VK_IMAGE_ASPECT_DEPTH_BIT;
229     else if (tcuFormat.order == tcu::TextureFormat::S)
230         return VK_IMAGE_ASPECT_STENCIL_BIT;
231 
232     DE_FATAL("Format not handled");
233     return 0u;
234 }
235 
getSampleLocationsPropertiesEXT(Context & context)236 VkPhysicalDeviceSampleLocationsPropertiesEXT getSampleLocationsPropertiesEXT(Context &context)
237 {
238     const InstanceInterface &vki          = context.getInstanceInterface();
239     const VkPhysicalDevice physicalDevice = context.getPhysicalDevice();
240 
241     VkPhysicalDeviceSampleLocationsPropertiesEXT sampleLocationsProperties;
242     deMemset(&sampleLocationsProperties, 0, sizeof(sampleLocationsProperties));
243 
244     sampleLocationsProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLE_LOCATIONS_PROPERTIES_EXT;
245     sampleLocationsProperties.pNext = DE_NULL;
246 
247     VkPhysicalDeviceProperties2 properties = {
248         VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2, // VkStructureType               sType;
249         &sampleLocationsProperties,                     // void*                         pNext;
250         VkPhysicalDeviceProperties(),                   // VkPhysicalDeviceProperties    properties;
251     };
252 
253     vki.getPhysicalDeviceProperties2(physicalDevice, &properties);
254 
255     return sampleLocationsProperties;
256 }
257 
numSamplesPerPixel(const MultisamplePixelGrid & pixelGrid)258 inline uint32_t numSamplesPerPixel(const MultisamplePixelGrid &pixelGrid)
259 {
260     return static_cast<uint32_t>(pixelGrid.samplesPerPixel());
261 }
262 
makeEmptySampleLocationsInfo()263 inline VkSampleLocationsInfoEXT makeEmptySampleLocationsInfo()
264 {
265     const VkSampleLocationsInfoEXT info = {
266         VK_STRUCTURE_TYPE_SAMPLE_LOCATIONS_INFO_EXT, // VkStructureType               sType;
267         DE_NULL,                                     // const void*                   pNext;
268         (VkSampleCountFlagBits)0,                    // VkSampleCountFlagBits         sampleLocationsPerPixel;
269         makeExtent2D(0, 0),                          // VkExtent2D                    sampleLocationGridSize;
270         0,                                           // uint32_t                      sampleLocationsCount;
271         DE_NULL,                                     // const VkSampleLocationEXT*    pSampleLocations;
272     };
273     return info;
274 }
275 
logPixelGrid(tcu::TestLog & log,const VkPhysicalDeviceSampleLocationsPropertiesEXT & sampleLocationsProperties,const MultisamplePixelGrid & pixelGrid)276 void logPixelGrid(tcu::TestLog &log, const VkPhysicalDeviceSampleLocationsPropertiesEXT &sampleLocationsProperties,
277                   const MultisamplePixelGrid &pixelGrid)
278 {
279     log << tcu::TestLog::Section("pixelGrid", "Multisample pixel grid configuration:") << tcu::TestLog::Message
280         << sampleLocationsProperties << tcu::TestLog::EndMessage << tcu::TestLog::Message
281         << "Specified grid size = " << pixelGrid.size() << tcu::TestLog::EndMessage;
282 
283     for (uint32_t gridY = 0; gridY < pixelGrid.size().y(); ++gridY)
284         for (uint32_t gridX = 0; gridX < pixelGrid.size().x(); ++gridX)
285         {
286             log << tcu::TestLog::Message << "Pixel(" << gridX << ", " << gridY << ")" << tcu::TestLog::EndMessage;
287 
288             for (uint32_t sampleNdx = 0; sampleNdx < numSamplesPerPixel(pixelGrid); ++sampleNdx)
289             {
290                 const VkSampleLocationEXT &loc = pixelGrid.getSample(gridX, gridY, sampleNdx);
291                 log << tcu::TestLog::Message << "* Sample(" << sampleNdx << ") = " << Vec2(loc.x, loc.y)
292                     << tcu::TestLog::EndMessage;
293             }
294         }
295 
296     log << tcu::TestLog::Message << "Sample locations visualization" << tcu::TestLog::EndMessage;
297 
298     {
299         const uint32_t height = deMinu32(1u << sampleLocationsProperties.sampleLocationSubPixelBits,
300                                          16u); // increase if you want more precision
301         const uint32_t width  = 2 * height;    // works well with a fixed-size font
302         std::vector<char> buffer(width * height);
303 
304         for (uint32_t gridY = 0; gridY < pixelGrid.size().y(); ++gridY)
305             for (uint32_t gridX = 0; gridX < pixelGrid.size().x(); ++gridX)
306             {
307                 std::fill(buffer.begin(), buffer.end(), '.');
308 
309                 for (uint32_t sampleNdx = 0; sampleNdx < numSamplesPerPixel(pixelGrid); ++sampleNdx)
310                 {
311                     const VkSampleLocationEXT &loc = pixelGrid.getSample(gridX, gridY, sampleNdx);
312                     const uint32_t ndx =
313                         deMinu32(width - 1, static_cast<uint32_t>(static_cast<float>(width) * loc.x)) +
314                         deMinu32(height - 1, static_cast<uint32_t>(static_cast<float>(height) * loc.y)) * width;
315                     const uint32_t evenNdx = ndx - ndx % 2;
316 
317                     buffer[evenNdx]     = '[';
318                     buffer[evenNdx + 1] = ']';
319                 }
320 
321                 std::ostringstream str;
322                 str << "Pixel(" << gridX << ", " << gridY << ")\n";
323 
324                 for (uint32_t lineNdx = 0; lineNdx < height; ++lineNdx)
325                 {
326                     str.write(&buffer[width * lineNdx], width);
327                     str << "\n";
328                 }
329 
330                 log << tcu::TestLog::Message << str.str() << tcu::TestLog::EndMessage;
331             }
332     }
333 
334     log << tcu::TestLog::EndSection;
335 }
336 
337 //! Place samples very close to each other
fillSampleLocationsPacked(MultisamplePixelGrid & grid,const uint32_t subPixelBits)338 void fillSampleLocationsPacked(MultisamplePixelGrid &grid, const uint32_t subPixelBits)
339 {
340     const uint32_t numLocations = 1u << subPixelBits;
341     const int offset[3]         = {-1, 0, 1};
342     de::Random rng(214);
343 
344     for (uint32_t gridY = 0; gridY < grid.size().y(); ++gridY)
345         for (uint32_t gridX = 0; gridX < grid.size().x(); ++gridX)
346         {
347             // Will start placing from this location
348             const UVec2 baseLocationNdx(rng.getUint32() % numLocations, rng.getUint32() % numLocations);
349             UVec2 locationNdx = baseLocationNdx;
350 
351             std::set<UVec2, LessThan<UVec2>> takenLocationIndices;
352             for (uint32_t sampleNdx = 0; sampleNdx < numSamplesPerPixel(grid); /* no increment */)
353             {
354                 if (takenLocationIndices.find(locationNdx) == takenLocationIndices.end())
355                 {
356                     const VkSampleLocationEXT location = {
357                         static_cast<float>(locationNdx.x()) / static_cast<float>(numLocations), // float x;
358                         static_cast<float>(locationNdx.y()) / static_cast<float>(numLocations), // float y;
359                     };
360 
361                     grid.setSample(gridX, gridY, sampleNdx, location);
362                     takenLocationIndices.insert(locationNdx);
363 
364                     ++sampleNdx; // next sample
365                 }
366 
367                 // Find next location by applying a small offset. Just keep iterating if a redundant location is chosen
368                 locationNdx.x() = static_cast<uint32_t>(deClamp32(
369                     locationNdx.x() + offset[rng.getUint32() % DE_LENGTH_OF_ARRAY(offset)], 0u, numLocations - 1));
370                 locationNdx.y() = static_cast<uint32_t>(deClamp32(
371                     locationNdx.y() + offset[rng.getUint32() % DE_LENGTH_OF_ARRAY(offset)], 0u, numLocations - 1));
372             }
373         }
374 }
375 
376 //! Unorm/int compare, very low threshold as we are expecting near-exact values
compareGreenImage(tcu::TestLog & log,const char * name,const char * description,const tcu::ConstPixelBufferAccess & image)377 bool compareGreenImage(tcu::TestLog &log, const char *name, const char *description,
378                        const tcu::ConstPixelBufferAccess &image)
379 {
380     tcu::TextureLevel greenImage(image.getFormat(), image.getWidth(), image.getHeight());
381     tcu::clear(greenImage.getAccess(), tcu::RGBA::green().toIVec());
382     return tcu::intThresholdCompare(log, name, description, greenImage.getAccess(), image, tcu::UVec4(2u),
383                                     tcu::COMPARE_LOG_RESULT);
384 }
385 
386 //! Silent compare - no logging
intThresholdCompare(const tcu::ConstPixelBufferAccess & reference,const tcu::ConstPixelBufferAccess & result,const UVec4 & threshold)387 bool intThresholdCompare(const tcu::ConstPixelBufferAccess &reference, const tcu::ConstPixelBufferAccess &result,
388                          const UVec4 &threshold)
389 {
390     using namespace tcu;
391 
392     int width  = reference.getWidth();
393     int height = reference.getHeight();
394     int depth  = reference.getDepth();
395     UVec4 maxDiff(0, 0, 0, 0);
396 
397     TCU_CHECK_INTERNAL(result.getWidth() == width && result.getHeight() == height && result.getDepth() == depth);
398 
399     for (int z = 0; z < depth; z++)
400     {
401         for (int y = 0; y < height; y++)
402         {
403             for (int x = 0; x < width; x++)
404             {
405                 IVec4 refPix = reference.getPixelInt(x, y, z);
406                 IVec4 cmpPix = result.getPixelInt(x, y, z);
407                 UVec4 diff   = abs(refPix - cmpPix).cast<uint32_t>();
408 
409                 maxDiff = max(maxDiff, diff);
410             }
411         }
412     }
413 
414     return boolAll(lessThanEqual(maxDiff, threshold));
415 }
416 
countUniqueColors(const tcu::ConstPixelBufferAccess & image)417 int countUniqueColors(const tcu::ConstPixelBufferAccess &image)
418 {
419     std::set<Vec4, LessThan<Vec4>> colors;
420 
421     for (int y = 0; y < image.getHeight(); ++y)
422         for (int x = 0; x < image.getWidth(); ++x)
423         {
424             colors.insert(image.getPixel(x, y));
425         }
426 
427     return static_cast<int>(colors.size());
428 }
429 
makeImage(const DeviceInterface & vk,const VkDevice device,const VkImageCreateFlags flags,const VkFormat format,const UVec2 & size,const VkSampleCountFlagBits samples,const VkImageUsageFlags usage)430 Move<VkImage> makeImage(const DeviceInterface &vk, const VkDevice device, const VkImageCreateFlags flags,
431                         const VkFormat format, const UVec2 &size, const VkSampleCountFlagBits samples,
432                         const VkImageUsageFlags usage)
433 {
434     const VkImageCreateInfo imageParams = {
435         VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
436         DE_NULL,                             // const void* pNext;
437         flags,                               // VkImageCreateFlags flags;
438         VK_IMAGE_TYPE_2D,                    // VkImageType imageType;
439         format,                              // VkFormat format;
440         makeExtent3D(size.x(), size.y(), 1), // VkExtent3D extent;
441         1u,                                  // uint32_t mipLevels;
442         1u,                                  // uint32_t arrayLayers;
443         samples,                             // VkSampleCountFlagBits samples;
444         VK_IMAGE_TILING_OPTIMAL,             // VkImageTiling tiling;
445         usage,                               // VkImageUsageFlags usage;
446         VK_SHARING_MODE_EXCLUSIVE,           // VkSharingMode sharingMode;
447         0u,                                  // uint32_t queueFamilyIndexCount;
448         DE_NULL,                             // const uint32_t* pQueueFamilyIndices;
449         VK_IMAGE_LAYOUT_UNDEFINED,           // VkImageLayout initialLayout;
450     };
451     return createImage(vk, device, &imageParams);
452 }
453 
makeEvent(const DeviceInterface & vk,const VkDevice device)454 Move<VkEvent> makeEvent(const DeviceInterface &vk, const VkDevice device)
455 {
456     const VkEventCreateInfo createInfo = {
457         VK_STRUCTURE_TYPE_EVENT_CREATE_INFO, // VkStructureType       sType;
458         DE_NULL,                             // const void*           pNext;
459         (VkEventCreateFlags)0,               // VkEventCreateFlags    flags;
460     };
461     return createEvent(vk, device, &createInfo);
462 }
463 
464 //! Generate NDC space sample locations at each framebuffer pixel
465 //! Data is filled starting at pixel (0,0) and for each pixel there are numSamples locations
genFramebufferSampleLocations(const MultisamplePixelGrid & pixelGrid,const UVec2 & gridSize,const UVec2 & framebufferSize)466 std::vector<Vec2> genFramebufferSampleLocations(const MultisamplePixelGrid &pixelGrid, const UVec2 &gridSize,
467                                                 const UVec2 &framebufferSize)
468 {
469     std::vector<Vec2> locations;
470 
471     for (uint32_t y = 0; y < framebufferSize.y(); ++y)
472         for (uint32_t x = 0; x < framebufferSize.x(); ++x)
473             for (uint32_t sampleNdx = 0; sampleNdx < numSamplesPerPixel(pixelGrid); ++sampleNdx)
474             {
475                 const VkSampleLocationEXT &location =
476                     pixelGrid.getSample(x % gridSize.x(), y % gridSize.y(), sampleNdx);
477                 const float globalX = location.x + static_cast<float>(x);
478                 const float globalY = location.y + static_cast<float>(y);
479 
480                 // Transform to [-1, 1] space
481                 locations.push_back(Vec2(-1.0f + 2.0f * (globalX / static_cast<float>(framebufferSize.x())),
482                                          -1.0f + 2.0f * (globalY / static_cast<float>(framebufferSize.y()))));
483             }
484 
485     return locations;
486 }
487 
488 struct PositionColor
489 {
490     tcu::Vec4 position;
491     tcu::Vec4 color;
492 
PositionColorvkt::pipeline::__anonf162cbe40111::PositionColor493     PositionColor(const tcu::Vec4 &pos, const tcu::Vec4 &col) : position(pos), color(col)
494     {
495     }
496 };
497 
genVerticesFullQuad(const Vec4 & color=Vec4 (1.0f),const float z=0.0f)498 std::vector<PositionColor> genVerticesFullQuad(const Vec4 &color = Vec4(1.0f), const float z = 0.0f)
499 {
500     const PositionColor vertices[] = {
501         PositionColor(Vec4(1.0f, -1.0f, z, 1.0f), color), PositionColor(Vec4(-1.0f, -1.0f, z, 1.0f), color),
502         PositionColor(Vec4(-1.0f, 1.0f, z, 1.0f), color),
503 
504         PositionColor(Vec4(-1.0f, 1.0f, z, 1.0f), color), PositionColor(Vec4(1.0f, 1.0f, z, 1.0f), color),
505         PositionColor(Vec4(1.0f, -1.0f, z, 1.0f), color),
506     };
507 
508     return std::vector<PositionColor>(vertices, vertices + DE_LENGTH_OF_ARRAY(vertices));
509 }
510 
511 //! Some abstract geometry with angled edges, to make multisampling visible.
genVerticesShapes(const Vec4 & color=Vec4 (1.0f),const float z=0.0f)512 std::vector<PositionColor> genVerticesShapes(const Vec4 &color = Vec4(1.0f), const float z = 0.0f)
513 {
514     std::vector<PositionColor> vertices;
515 
516     const float numSteps  = 16.0f;
517     const float angleStep = (2.0f * DE_PI) / numSteps;
518 
519     for (float a = 0.0f; a <= 2.0f * DE_PI; a += angleStep)
520     {
521         vertices.push_back(PositionColor(Vec4(1.0f * deFloatCos(a), 1.0f * deFloatSin(a), z, 1.0f), color));
522         vertices.push_back(
523             PositionColor(Vec4(0.1f * deFloatCos(a - angleStep), 0.1f * deFloatSin(a - angleStep), z, 1.0f), color));
524         vertices.push_back(
525             PositionColor(Vec4(0.1f * deFloatCos(a + angleStep), 0.1f * deFloatSin(a + angleStep), z, 1.0f), color));
526     }
527 
528     return vertices;
529 }
530 
531 //! Stencil op that only allows drawing over the cleared area of an attachment.
stencilOpStateDrawOnce(void)532 inline VkStencilOpState stencilOpStateDrawOnce(void)
533 {
534     return makeStencilOpState(VK_STENCIL_OP_KEEP,  // stencil fail
535                               VK_STENCIL_OP_ZERO,  // depth & stencil pass
536                               VK_STENCIL_OP_KEEP,  // depth only fail
537                               VK_COMPARE_OP_EQUAL, // compare op
538                               ~0u,                 // compare mask
539                               ~0u,                 // write mask
540                               STENCIL_REFERENCE);  // reference
541 }
542 
543 //! Stencil op that simply increments the buffer with each passing test.
stencilOpStateIncrement(void)544 inline VkStencilOpState stencilOpStateIncrement(void)
545 {
546     return makeStencilOpState(VK_STENCIL_OP_KEEP,                // stencil fail
547                               VK_STENCIL_OP_INCREMENT_AND_CLAMP, // depth & stencil pass
548                               VK_STENCIL_OP_KEEP,                // depth only fail
549                               VK_COMPARE_OP_ALWAYS,              // compare op
550                               ~0u,                               // compare mask
551                               ~0u,                               // write mask
552                               STENCIL_REFERENCE);                // reference
553 }
554 
555 //! A few preconfigured vertex attribute configurations
556 enum VertexInputConfig
557 {
558     VERTEX_INPUT_NONE = 0u,
559     VERTEX_INPUT_VEC4,
560     VERTEX_INPUT_VEC4_VEC4,
561 };
562 
563 //! Create a MSAA pipeline, with max per-sample shading
preparePipelineWrapper(GraphicsPipelineWrapper & gpw,const std::vector<VkDynamicState> & dynamicState,const PipelineLayoutWrapper & pipelineLayout,const VkRenderPass renderPass,const ShaderWrapper vertexModule,const ShaderWrapper fragmentModule,const uint32_t subpassIndex,const VkViewport & viewport,const VkRect2D scissor,const VkSampleCountFlagBits numSamples,const bool useSampleLocations,const VkSampleLocationsInfoEXT & sampleLocationsInfo,const bool useDepth,const bool useStencil,const VertexInputConfig vertexInputConfig,const VkPrimitiveTopology topology,const VkStencilOpState & stencilOpState,const bool useFragmentShadingRate)564 void preparePipelineWrapper(GraphicsPipelineWrapper &gpw, const std::vector<VkDynamicState> &dynamicState,
565                             const PipelineLayoutWrapper &pipelineLayout, const VkRenderPass renderPass,
566                             const ShaderWrapper vertexModule, const ShaderWrapper fragmentModule,
567                             const uint32_t subpassIndex, const VkViewport &viewport, const VkRect2D scissor,
568                             const VkSampleCountFlagBits numSamples, const bool useSampleLocations,
569                             const VkSampleLocationsInfoEXT &sampleLocationsInfo, const bool useDepth,
570                             const bool useStencil, const VertexInputConfig vertexInputConfig,
571                             const VkPrimitiveTopology topology, const VkStencilOpState &stencilOpState,
572                             const bool useFragmentShadingRate)
573 {
574     std::vector<VkVertexInputBindingDescription> vertexInputBindingDescriptions;
575     std::vector<VkVertexInputAttributeDescription> vertexInputAttributeDescriptions;
576 
577     const uint32_t sizeofVec4 = static_cast<uint32_t>(sizeof(Vec4));
578 
579     switch (vertexInputConfig)
580     {
581     case VERTEX_INPUT_NONE:
582         break;
583 
584     case VERTEX_INPUT_VEC4:
585         vertexInputBindingDescriptions.push_back(
586             makeVertexInputBindingDescription(0u, sizeofVec4, VK_VERTEX_INPUT_RATE_VERTEX));
587         vertexInputAttributeDescriptions.push_back(
588             makeVertexInputAttributeDescription(0u, 0u, VK_FORMAT_R32G32B32A32_SFLOAT, 0u));
589         break;
590 
591     case VERTEX_INPUT_VEC4_VEC4:
592         vertexInputBindingDescriptions.push_back(
593             makeVertexInputBindingDescription(0u, 2u * sizeofVec4, VK_VERTEX_INPUT_RATE_VERTEX));
594         vertexInputAttributeDescriptions.push_back(
595             makeVertexInputAttributeDescription(0u, 0u, VK_FORMAT_R32G32B32A32_SFLOAT, 0u));
596         vertexInputAttributeDescriptions.push_back(
597             makeVertexInputAttributeDescription(1u, 0u, VK_FORMAT_R32G32B32A32_SFLOAT, sizeofVec4));
598         break;
599 
600     default:
601         DE_FATAL("Vertex input config not supported");
602         break;
603     }
604 
605     const VkPipelineVertexInputStateCreateInfo vertexInputStateInfo = {
606         VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,    // VkStructureType sType;
607         DE_NULL,                                                      // const void* pNext;
608         (VkPipelineVertexInputStateCreateFlags)0,                     // VkPipelineVertexInputStateCreateFlags flags;
609         static_cast<uint32_t>(vertexInputBindingDescriptions.size()), // uint32_t vertexBindingDescriptionCount;
610         dataOrNullPtr(
611             vertexInputBindingDescriptions), // const VkVertexInputBindingDescription* pVertexBindingDescriptions;
612         static_cast<uint32_t>(vertexInputAttributeDescriptions.size()), // uint32_t vertexAttributeDescriptionCount;
613         dataOrNullPtr(
614             vertexInputAttributeDescriptions), // const VkVertexInputAttributeDescription* pVertexAttributeDescriptions;
615     };
616 
617     const VkPipelineSampleLocationsStateCreateInfoEXT pipelineSampleLocationsCreateInfo = {
618         VK_STRUCTURE_TYPE_PIPELINE_SAMPLE_LOCATIONS_STATE_CREATE_INFO_EXT, // VkStructureType             sType;
619         DE_NULL,                                                           // const void*                 pNext;
620         useSampleLocations,  // VkBool32                    sampleLocationsEnable;
621         sampleLocationsInfo, // VkSampleLocationsInfoEXT    sampleLocationsInfo;
622     };
623 
624     const VkPipelineMultisampleStateCreateInfo pipelineMultisampleStateInfo = {
625         VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, // VkStructureType sType;
626         &pipelineSampleLocationsCreateInfo,                       // const void* pNext;
627         (VkPipelineMultisampleStateCreateFlags)0,                 // VkPipelineMultisampleStateCreateFlags flags;
628         numSamples,                                               // VkSampleCountFlagBits rasterizationSamples;
629         VK_TRUE,                                                  // VkBool32 sampleShadingEnable;
630         1.0f,                                                     // float minSampleShading;
631         DE_NULL,                                                  // const VkSampleMask* pSampleMask;
632         VK_FALSE,                                                 // VkBool32 alphaToCoverageEnable;
633         VK_FALSE                                                  // VkBool32 alphaToOneEnable;
634     };
635 
636     VkPipelineDepthStencilStateCreateInfo pipelineDepthStencilStateInfo = {
637         VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, // VkStructureType sType;
638         DE_NULL,                                                    // const void* pNext;
639         (VkPipelineDepthStencilStateCreateFlags)0,                  // VkPipelineDepthStencilStateCreateFlags flags;
640         useDepth,                                                   // VkBool32 depthTestEnable;
641         true,                                                       // VkBool32 depthWriteEnable;
642         VK_COMPARE_OP_LESS,                                         // VkCompareOp depthCompareOp;
643         VK_FALSE,                                                   // VkBool32 depthBoundsTestEnable;
644         useStencil,                                                 // VkBool32 stencilTestEnable;
645         stencilOpState,                                             // VkStencilOpState front;
646         stencilOpState,                                             // VkStencilOpState back;
647         0.0f,                                                       // float minDepthBounds;
648         1.0f,                                                       // float maxDepthBounds;
649     };
650 
651     const VkPipelineDynamicStateCreateInfo dynamicStateCreateInfo = {
652         VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, // VkStructureType sType;
653         DE_NULL,                                              // const void* pNext;
654         (VkPipelineDynamicStateCreateFlags)0,                 // VkPipelineDynamicStateCreateFlags flags;
655         static_cast<uint32_t>(dynamicState.size()),           // uint32_t dynamicStateCount;
656         dataOrNullPtr(dynamicState),                          // const VkDynamicState* pDynamicStates;
657     };
658 
659     const VkPipelineColorBlendAttachmentState colorBlendAttachmentState{
660         VK_FALSE,                // VkBool32                 blendEnable
661         VK_BLEND_FACTOR_ZERO,    // VkBlendFactor            srcColorBlendFactor
662         VK_BLEND_FACTOR_ZERO,    // VkBlendFactor            dstColorBlendFactor
663         VK_BLEND_OP_ADD,         // VkBlendOp                colorBlendOp
664         VK_BLEND_FACTOR_ZERO,    // VkBlendFactor            srcAlphaBlendFactor
665         VK_BLEND_FACTOR_ZERO,    // VkBlendFactor            dstAlphaBlendFactor
666         VK_BLEND_OP_ADD,         // VkBlendOp                alphaBlendOp
667         VK_COLOR_COMPONENT_R_BIT // VkColorComponentFlags    colorWriteMask
668             | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT};
669 
670     VkPipelineColorBlendStateCreateInfo colorBlendStateCreateInfoDefault = initVulkanStructure();
671     colorBlendStateCreateInfoDefault.attachmentCount                     = 1u;
672     colorBlendStateCreateInfoDefault.pAttachments                        = &colorBlendAttachmentState;
673 
674     const std::vector<VkViewport> viewports{viewport};
675     const std::vector<VkRect2D> scissors{scissor};
676 
677     VkPipelineFragmentShadingRateStateCreateInfoKHR shadingRateStateCreateInfo{
678         VK_STRUCTURE_TYPE_PIPELINE_FRAGMENT_SHADING_RATE_STATE_CREATE_INFO_KHR, // VkStructureType sType;
679         DE_NULL,                                                                // const void* pNext;
680         {2, 2},                                                                 // VkExtent2D fragmentSize;
681         {VK_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP_KHR,
682          VK_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP_KHR}, // VkFragmentShadingRateCombinerOpKHR combinerOps[2];
683     };
684 
685     gpw.setDefaultTopology(topology)
686         .setDynamicState(&dynamicStateCreateInfo)
687         .setDefaultRasterizationState()
688         .setupVertexInputState(&vertexInputStateInfo)
689         .setupPreRasterizationShaderState(viewports, scissors, pipelineLayout, renderPass, subpassIndex, vertexModule,
690                                           nullptr, ShaderWrapper(), ShaderWrapper(), ShaderWrapper(), DE_NULL,
691                                           (useFragmentShadingRate ? &shadingRateStateCreateInfo : nullptr))
692         .setupFragmentShaderState(pipelineLayout, renderPass, subpassIndex, fragmentModule,
693                                   &pipelineDepthStencilStateInfo, &pipelineMultisampleStateInfo)
694         .setupFragmentOutputState(renderPass, subpassIndex, &colorBlendStateCreateInfoDefault,
695                                   &pipelineMultisampleStateInfo)
696         .setMonolithicPipelineLayout(pipelineLayout)
697         .buildPipeline();
698 }
699 
preparePipelineWrapperSinglePassColor(GraphicsPipelineWrapper & gpw,const std::vector<VkDynamicState> & dynamicState,const PipelineLayoutWrapper & pipelineLayout,const VkRenderPass renderPass,const ShaderWrapper vertexModule,const ShaderWrapper fragmentModule,const VkViewport & viewport,const VkRect2D scissor,const VkSampleCountFlagBits numSamples,const bool useSampleLocations,const VkSampleLocationsInfoEXT & sampleLocationsInfo,const VertexInputConfig vertexInputConfig,const VkPrimitiveTopology topology,const bool useFragmentShadingRate)700 void preparePipelineWrapperSinglePassColor(GraphicsPipelineWrapper &gpw,
701                                            const std::vector<VkDynamicState> &dynamicState,
702                                            const PipelineLayoutWrapper &pipelineLayout, const VkRenderPass renderPass,
703                                            const ShaderWrapper vertexModule, const ShaderWrapper fragmentModule,
704                                            const VkViewport &viewport, const VkRect2D scissor,
705                                            const VkSampleCountFlagBits numSamples, const bool useSampleLocations,
706                                            const VkSampleLocationsInfoEXT &sampleLocationsInfo,
707                                            const VertexInputConfig vertexInputConfig,
708                                            const VkPrimitiveTopology topology, const bool useFragmentShadingRate)
709 {
710     preparePipelineWrapper(gpw, dynamicState, pipelineLayout, renderPass, vertexModule, fragmentModule,
711                            /*subpass*/ 0u, viewport, scissor, numSamples, useSampleLocations, sampleLocationsInfo,
712                            /*depth test*/ false, /*stencil test*/ false, vertexInputConfig, topology,
713                            stencilOpStateIncrement(), useFragmentShadingRate);
714 }
715 
716 //! Utility to build and maintain render pass, framebuffer and related resources.
717 //! Use bake() before using the render pass.
718 class RenderTarget
719 {
720 public:
RenderTarget(void)721     RenderTarget(void)
722     {
723         nextSubpass();
724     }
725 
726     //! Returns an attachment index that is used to reference this attachment later
addAttachment(const VkImage image,const VkImageView imageView,const VkAttachmentDescriptionFlags flags,const VkFormat format,const VkSampleCountFlagBits numSamples,const VkAttachmentLoadOp loadOp,const VkAttachmentStoreOp storeOp,const VkAttachmentLoadOp stencilLoadOp,const VkAttachmentStoreOp stencilStoreOp,const VkImageLayout initialLayout,const VkImageLayout finalLayout,const VkClearValue clearValue,const VkSampleLocationsInfoEXT * pInitialSampleLocations=DE_NULL)727     uint32_t addAttachment(const VkImage image, const VkImageView imageView, const VkAttachmentDescriptionFlags flags,
728                            const VkFormat format, const VkSampleCountFlagBits numSamples,
729                            const VkAttachmentLoadOp loadOp, const VkAttachmentStoreOp storeOp,
730                            const VkAttachmentLoadOp stencilLoadOp, const VkAttachmentStoreOp stencilStoreOp,
731                            const VkImageLayout initialLayout, const VkImageLayout finalLayout,
732                            const VkClearValue clearValue,
733                            const VkSampleLocationsInfoEXT *pInitialSampleLocations = DE_NULL)
734     {
735         const uint32_t index = static_cast<uint32_t>(m_attachments.size());
736 
737         m_images.push_back(image);
738         m_attachments.push_back(imageView);
739         m_attachmentDescriptions.push_back(
740             makeAttachmentDescription(flags,          // VkAttachmentDescriptionFlags flags;
741                                       format,         // VkFormat format;
742                                       numSamples,     // VkSampleCountFlagBits samples;
743                                       loadOp,         // VkAttachmentLoadOp loadOp;
744                                       storeOp,        // VkAttachmentStoreOp storeOp;
745                                       stencilLoadOp,  // VkAttachmentLoadOp stencilLoadOp;
746                                       stencilStoreOp, // VkAttachmentStoreOp stencilStoreOp;
747                                       initialLayout,  // VkImageLayout initialLayout;
748                                       finalLayout     // VkImageLayout finalLayout;
749                                       ));
750         m_clearValues.push_back(clearValue); // always add, even if unused
751 
752         if (pInitialSampleLocations)
753         {
754             const VkAttachmentSampleLocationsEXT attachmentSampleLocations = {
755                 index,                    // uint32_t                    attachmentIndex;
756                 *pInitialSampleLocations, // VkSampleLocationsInfoEXT    sampleLocationsInfo;
757             };
758             m_attachmentSampleLocations.push_back(attachmentSampleLocations);
759         }
760 
761         return index;
762     }
763 
addSubpassColorAttachment(const uint32_t attachmentIndex,const VkImageLayout subpassLayout)764     void addSubpassColorAttachment(const uint32_t attachmentIndex, const VkImageLayout subpassLayout)
765     {
766         m_subpasses.back().colorAttachmentReferences.push_back(makeAttachmentReference(attachmentIndex, subpassLayout));
767         m_subpasses.back().resolveAttachmentReferences.push_back(
768             makeAttachmentReference(VK_ATTACHMENT_UNUSED, VK_IMAGE_LAYOUT_UNDEFINED));
769     }
770 
addSubpassColorAttachmentWithResolve(const uint32_t colorAttachmentIndex,const VkImageLayout colorSubpassLayout,const uint32_t resolveAttachmentIndex,const VkImageLayout resolveSubpassLayout,const VkSampleLocationsInfoEXT * pSampleLocations=DE_NULL)771     void addSubpassColorAttachmentWithResolve(const uint32_t colorAttachmentIndex,
772                                               const VkImageLayout colorSubpassLayout,
773                                               const uint32_t resolveAttachmentIndex,
774                                               const VkImageLayout resolveSubpassLayout,
775                                               const VkSampleLocationsInfoEXT *pSampleLocations = DE_NULL)
776     {
777         m_subpasses.back().colorAttachmentReferences.push_back(
778             makeAttachmentReference(colorAttachmentIndex, colorSubpassLayout));
779         m_subpasses.back().resolveAttachmentReferences.push_back(
780             makeAttachmentReference(resolveAttachmentIndex, resolveSubpassLayout));
781 
782         if (pSampleLocations)
783         {
784             const VkSubpassSampleLocationsEXT subpassSampleLocations = {
785                 static_cast<uint32_t>(m_subpasses.size() - 1), // uint32_t                    subpassIndex;
786                 *pSampleLocations,                             // VkSampleLocationsInfoEXT    sampleLocationsInfo;
787             };
788             m_subpassSampleLocations.push_back(subpassSampleLocations);
789         }
790     }
791 
addSubpassDepthStencilAttachment(const uint32_t attachmentIndex,const VkImageLayout subpassLayout,const VkSampleLocationsInfoEXT * pSampleLocations=DE_NULL)792     void addSubpassDepthStencilAttachment(const uint32_t attachmentIndex, const VkImageLayout subpassLayout,
793                                           const VkSampleLocationsInfoEXT *pSampleLocations = DE_NULL)
794     {
795         m_subpasses.back().depthStencilAttachmentReferences.push_back(
796             makeAttachmentReference(attachmentIndex, subpassLayout));
797 
798         if (pSampleLocations)
799         {
800             const VkSubpassSampleLocationsEXT subpassSampleLocations = {
801                 static_cast<uint32_t>(m_subpasses.size() - 1), // uint32_t                    subpassIndex;
802                 *pSampleLocations,                             // VkSampleLocationsInfoEXT    sampleLocationsInfo;
803             };
804             m_subpassSampleLocations.push_back(subpassSampleLocations);
805         }
806     }
807 
addSubpassInputAttachment(const uint32_t attachmentIndex,const VkImageLayout subpassLayout)808     void addSubpassInputAttachment(const uint32_t attachmentIndex, const VkImageLayout subpassLayout)
809     {
810         m_subpasses.back().inputAttachmentReferences.push_back(makeAttachmentReference(attachmentIndex, subpassLayout));
811     }
812 
addSubpassPreserveAttachment(const uint32_t attachmentIndex)813     void addSubpassPreserveAttachment(const uint32_t attachmentIndex)
814     {
815         m_subpasses.back().preserveAttachmentReferences.push_back(attachmentIndex);
816     }
817 
nextSubpass(void)818     void nextSubpass(void)
819     {
820         m_subpasses.push_back(SubpassDescription());
821     }
822 
823     //! Create a RenderPass and Framebuffer based on provided attachments
bake(const DeviceInterface & vk,const VkDevice device,const PipelineConstructionType pipelineConstructionType,const UVec2 & framebufferSize)824     void bake(const DeviceInterface &vk, const VkDevice device, const PipelineConstructionType pipelineConstructionType,
825               const UVec2 &framebufferSize)
826     {
827         const uint32_t numSubpasses = static_cast<uint32_t>(m_subpasses.size());
828 
829         std::vector<VkSubpassDescription> subpassDescriptions;
830         std::vector<VkSubpassDependency> subpassDependencies;
831         for (uint32_t subpassNdx = 0; subpassNdx < numSubpasses; ++subpassNdx)
832         {
833             const SubpassDescription &sd           = m_subpasses[subpassNdx];
834             const VkSubpassDescription description = {
835                 (VkSubpassDescriptionFlags)0,                               // VkSubpassDescriptionFlags flags;
836                 VK_PIPELINE_BIND_POINT_GRAPHICS,                            // VkPipelineBindPoint pipelineBindPoint;
837                 static_cast<uint32_t>(sd.inputAttachmentReferences.size()), // uint32_t inputAttachmentCount;
838                 dataOrNullPtr(sd.inputAttachmentReferences), // const VkAttachmentReference* pInputAttachments;
839                 static_cast<uint32_t>(sd.colorAttachmentReferences.size()), // uint32_t colorAttachmentCount;
840                 dataOrNullPtr(sd.colorAttachmentReferences),   // const VkAttachmentReference* pColorAttachments;
841                 dataOrNullPtr(sd.resolveAttachmentReferences), // const VkAttachmentReference* pResolveAttachments;
842                 dataOrNullPtr(
843                     sd.depthStencilAttachmentReferences), // const VkAttachmentReference* pDepthStencilAttachment;
844                 static_cast<uint32_t>(sd.preserveAttachmentReferences.size()), // uint32_t preserveAttachmentCount;
845                 dataOrNullPtr(sd.preserveAttachmentReferences)                 // const uint32_t* pPreserveAttachments;
846             };
847             subpassDescriptions.push_back(description);
848 
849             // Add a very coarse dependency enforcing sequential ordering of subpasses
850             if (subpassNdx > 0)
851             {
852                 static const VkAccessFlags accessAny =
853                     VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
854                     VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT |
855                     VK_ACCESS_INPUT_ATTACHMENT_READ_BIT;
856                 const VkSubpassDependency dependency = {
857                     subpassNdx - 1,                     // uint32_t                srcSubpass;
858                     subpassNdx,                         // uint32_t                dstSubpass;
859                     VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, // VkPipelineStageFlags    srcStageMask;
860                     VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, // VkPipelineStageFlags    dstStageMask;
861                     accessAny,                          // VkAccessFlags           srcAccessMask;
862                     accessAny,                          // VkAccessFlags           dstAccessMask;
863                     (VkDependencyFlags)0,               // VkDependencyFlags       dependencyFlags;
864                 };
865                 subpassDependencies.push_back(dependency);
866             }
867         }
868         // add a final dependency to synchronize results for the copy commands that will follow the renderpass
869         const VkSubpassDependency finalDependency = {
870             numSubpasses - 1,    // uint32_t                srcSubpass;
871             VK_SUBPASS_EXTERNAL, // uint32_t                dstSubpass;
872             VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
873                 VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, // VkPipelineStageFlags    srcStageMask;
874             VK_PIPELINE_STAGE_TRANSFER_BIT,                // VkPipelineStageFlags    dstStageMask;
875             VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
876                 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, // VkAccessFlags           srcAccessMask;
877             VK_ACCESS_TRANSFER_READ_BIT,                      // VkAccessFlags           dstAccessMask;
878             (VkDependencyFlags)0,                             // VkDependencyFlags       dependencyFlags;
879         };
880         subpassDependencies.push_back(finalDependency);
881 
882         const VkRenderPassCreateInfo renderPassInfo = {
883             VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,              // VkStructureType sType;
884             DE_NULL,                                                // const void* pNext;
885             (VkRenderPassCreateFlags)0,                             // VkRenderPassCreateFlags flags;
886             static_cast<uint32_t>(m_attachmentDescriptions.size()), // uint32_t attachmentCount;
887             dataOrNullPtr(m_attachmentDescriptions),                // const VkAttachmentDescription* pAttachments;
888             static_cast<uint32_t>(subpassDescriptions.size()),      // uint32_t subpassCount;
889             dataOrNullPtr(subpassDescriptions),                     // const VkSubpassDescription* pSubpasses;
890             static_cast<uint32_t>(subpassDependencies.size()),      // uint32_t dependencyCount;
891             dataOrNullPtr(subpassDependencies)                      // const VkSubpassDependency* pDependencies;
892         };
893 
894         m_renderPass = RenderPassWrapper(pipelineConstructionType, vk, device, &renderPassInfo);
895         m_renderPass.createFramebuffer(vk, device, static_cast<uint32_t>(m_attachments.size()), dataOrNullPtr(m_images),
896                                        dataOrNullPtr(m_attachments), framebufferSize.x(), framebufferSize.y());
897     }
898 
getRenderPassWrapper(void) const899     const RenderPassWrapper &getRenderPassWrapper(void) const
900     {
901         return m_renderPass;
902     }
903 
getRenderPass(void) const904     VkRenderPass getRenderPass(void) const
905     {
906         return *m_renderPass;
907     }
908 
getFramebuffer(void) const909     VkFramebuffer getFramebuffer(void) const
910     {
911         return m_renderPass.getFramebuffer();
912     }
913 
recordBeginRenderPass(const DeviceInterface & vk,const VkCommandBuffer cmdBuffer,const VkRect2D & renderArea,const VkSubpassContents subpassContents) const914     void recordBeginRenderPass(const DeviceInterface &vk, const VkCommandBuffer cmdBuffer, const VkRect2D &renderArea,
915                                const VkSubpassContents subpassContents) const
916     {
917         const VkRenderPassSampleLocationsBeginInfoEXT renderPassSampleLocationsBeginInfo = {
918             VK_STRUCTURE_TYPE_RENDER_PASS_SAMPLE_LOCATIONS_BEGIN_INFO_EXT, // VkStructureType                          sType;
919             DE_NULL, // const void*                              pNext;
920             static_cast<uint32_t>(
921                 m_attachmentSampleLocations
922                     .size()), // uint32_t                                 attachmentInitialSampleLocationsCount;
923             dataOrNullPtr(
924                 m_attachmentSampleLocations), // const VkAttachmentSampleLocationsEXT*    pAttachmentInitialSampleLocations;
925             static_cast<uint32_t>(
926                 m_subpassSampleLocations
927                     .size()), // uint32_t                                 postSubpassSampleLocationsCount;
928             dataOrNullPtr(
929                 m_subpassSampleLocations), // const VkSubpassSampleLocationsEXT*       pPostSubpassSampleLocations;
930         };
931         m_renderPass.begin(vk, cmdBuffer, renderArea, static_cast<uint32_t>(m_clearValues.size()),
932                            dataOrNullPtr(m_clearValues), subpassContents, &renderPassSampleLocationsBeginInfo);
933     }
934 
nextSubpass(const DeviceInterface & vk,const VkCommandBuffer cmdBuffer,const VkSubpassContents subpassContents) const935     void nextSubpass(const DeviceInterface &vk, const VkCommandBuffer cmdBuffer,
936                      const VkSubpassContents subpassContents) const
937     {
938         m_renderPass.nextSubpass(vk, cmdBuffer, subpassContents);
939     }
940 
endRenderPass(const DeviceInterface & vk,const VkCommandBuffer cmdBuffer) const941     void endRenderPass(const DeviceInterface &vk, const VkCommandBuffer cmdBuffer) const
942     {
943         m_renderPass.end(vk, cmdBuffer);
944     }
945 
946 private:
947     struct SubpassDescription
948     {
949         std::vector<VkAttachmentReference> inputAttachmentReferences;
950         std::vector<VkAttachmentReference> colorAttachmentReferences;
951         std::vector<VkAttachmentReference> resolveAttachmentReferences;
952         std::vector<VkAttachmentReference> depthStencilAttachmentReferences;
953         std::vector<uint32_t> preserveAttachmentReferences;
954     };
955 
956     std::vector<SubpassDescription> m_subpasses;
957     std::vector<VkImage> m_images;
958     std::vector<VkImageView> m_attachments;
959     std::vector<VkAttachmentDescription> m_attachmentDescriptions;
960     std::vector<VkClearValue> m_clearValues;
961     std::vector<VkAttachmentSampleLocationsEXT> m_attachmentSampleLocations;
962     std::vector<VkSubpassSampleLocationsEXT> m_subpassSampleLocations;
963     RenderPassWrapper m_renderPass;
964 
965     // No copying allowed
966     RenderTarget(const RenderTarget &);
967     RenderTarget &operator=(const RenderTarget &);
968 };
969 
recordImageBarrier(const DeviceInterface & vk,const VkCommandBuffer cmdBuffer,const VkImage image,const VkImageAspectFlags aspect,const VkPipelineStageFlags srcStageMask,const VkPipelineStageFlags dstStageMask,const VkAccessFlags srcAccessMask,const VkAccessFlags dstAccessMask,const VkImageLayout oldLayout,const VkImageLayout newLayout,const VkSampleLocationsInfoEXT * pSampleLocationsInfo=DE_NULL)970 void recordImageBarrier(const DeviceInterface &vk, const VkCommandBuffer cmdBuffer, const VkImage image,
971                         const VkImageAspectFlags aspect, const VkPipelineStageFlags srcStageMask,
972                         const VkPipelineStageFlags dstStageMask, const VkAccessFlags srcAccessMask,
973                         const VkAccessFlags dstAccessMask, const VkImageLayout oldLayout, const VkImageLayout newLayout,
974                         const VkSampleLocationsInfoEXT *pSampleLocationsInfo = DE_NULL)
975 {
976     const VkImageMemoryBarrier barrier = {
977         VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,            // VkStructureType            sType;
978         pSampleLocationsInfo,                              // const void*                pNext;
979         srcAccessMask,                                     // VkAccessFlags              srcAccessMask;
980         dstAccessMask,                                     // VkAccessFlags              dstAccessMask;
981         oldLayout,                                         // VkImageLayout              oldLayout;
982         newLayout,                                         // VkImageLayout              newLayout;
983         VK_QUEUE_FAMILY_IGNORED,                           // uint32_t                   srcQueueFamilyIndex;
984         VK_QUEUE_FAMILY_IGNORED,                           // uint32_t                   dstQueueFamilyIndex;
985         image,                                             // VkImage                    image;
986         makeImageSubresourceRange(aspect, 0u, 1u, 0u, 1u), // VkImageSubresourceRange    subresourceRange;
987     };
988 
989     vk.cmdPipelineBarrier(cmdBuffer, srcStageMask, dstStageMask, (VkDependencyFlags)0, 0u, DE_NULL, 0u, DE_NULL, 1u,
990                           &barrier);
991 }
992 
recordWaitEventWithImage(const DeviceInterface & vk,const VkCommandBuffer cmdBuffer,const VkEvent event,const VkImage image,const VkImageAspectFlags aspect,const VkPipelineStageFlags srcStageMask,const VkPipelineStageFlags dstStageMask,const VkAccessFlags srcAccessMask,const VkAccessFlags dstAccessMask,const VkImageLayout oldLayout,const VkImageLayout newLayout,const VkSampleLocationsInfoEXT * pSampleLocationsInfo=DE_NULL)993 void recordWaitEventWithImage(const DeviceInterface &vk, const VkCommandBuffer cmdBuffer, const VkEvent event,
994                               const VkImage image, const VkImageAspectFlags aspect,
995                               const VkPipelineStageFlags srcStageMask, const VkPipelineStageFlags dstStageMask,
996                               const VkAccessFlags srcAccessMask, const VkAccessFlags dstAccessMask,
997                               const VkImageLayout oldLayout, const VkImageLayout newLayout,
998                               const VkSampleLocationsInfoEXT *pSampleLocationsInfo = DE_NULL)
999 {
1000     const VkImageMemoryBarrier barrier = {
1001         VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,            // VkStructureType            sType;
1002         pSampleLocationsInfo,                              // const void*                pNext;
1003         srcAccessMask,                                     // VkAccessFlags              srcAccessMask;
1004         dstAccessMask,                                     // VkAccessFlags              dstAccessMask;
1005         oldLayout,                                         // VkImageLayout              oldLayout;
1006         newLayout,                                         // VkImageLayout              newLayout;
1007         VK_QUEUE_FAMILY_IGNORED,                           // uint32_t                   srcQueueFamilyIndex;
1008         VK_QUEUE_FAMILY_IGNORED,                           // uint32_t                   dstQueueFamilyIndex;
1009         image,                                             // VkImage                    image;
1010         makeImageSubresourceRange(aspect, 0u, 1u, 0u, 1u), // VkImageSubresourceRange    subresourceRange;
1011     };
1012 
1013     vk.cmdWaitEvents(cmdBuffer,    // VkCommandBuffer                             commandBuffer,
1014                      1u,           // uint32_t                                    eventCount,
1015                      &event,       // const VkEvent*                              pEvents,
1016                      srcStageMask, // VkPipelineStageFlags                        srcStageMask,
1017                      dstStageMask, // VkPipelineStageFlags                        dstStageMask,
1018                      0u,           // uint32_t                                    memoryBarrierCount,
1019                      DE_NULL,      // const VkMemoryBarrier*                      pMemoryBarriers,
1020                      0u,           // uint32_t                                    bufferMemoryBarrierCount,
1021                      DE_NULL,      // const VkBufferMemoryBarrier*                pBufferMemoryBarriers,
1022                      1u,           // uint32_t                                    imageMemoryBarrierCount,
1023                      &barrier);    // const VkImageMemoryBarrier*                 pImageMemoryBarriers);
1024 }
1025 
recordCopyImageToBuffer(const DeviceInterface & vk,const VkCommandBuffer cmdBuffer,const UVec2 & imageSize,const VkImage srcImage,const VkBuffer dstBuffer)1026 void recordCopyImageToBuffer(const DeviceInterface &vk, const VkCommandBuffer cmdBuffer, const UVec2 &imageSize,
1027                              const VkImage srcImage, const VkBuffer dstBuffer)
1028 {
1029     // Resolve image -> host buffer
1030     {
1031         const VkBufferImageCopy region = {
1032             0ull, // VkDeviceSize                bufferOffset;
1033             0u,   // uint32_t                    bufferRowLength;
1034             0u,   // uint32_t                    bufferImageHeight;
1035             makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u,
1036                                        1u),                 // VkImageSubresourceLayers    imageSubresource;
1037             makeOffset3D(0, 0, 0),                          // VkOffset3D                  imageOffset;
1038             makeExtent3D(imageSize.x(), imageSize.y(), 1u), // VkExtent3D                  imageExtent;
1039         };
1040 
1041         vk.cmdCopyImageToBuffer(cmdBuffer, srcImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dstBuffer, 1u, &region);
1042     }
1043     // Buffer write barrier
1044     {
1045         const VkBufferMemoryBarrier barrier = {
1046             VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, // VkStructureType    sType;
1047             DE_NULL,                                 // const void*        pNext;
1048             VK_ACCESS_TRANSFER_WRITE_BIT,            // VkAccessFlags      srcAccessMask;
1049             VK_ACCESS_HOST_READ_BIT,                 // VkAccessFlags      dstAccessMask;
1050             VK_QUEUE_FAMILY_IGNORED,                 // uint32_t           srcQueueFamilyIndex;
1051             VK_QUEUE_FAMILY_IGNORED,                 // uint32_t           dstQueueFamilyIndex;
1052             dstBuffer,                               // VkBuffer           buffer;
1053             0ull,                                    // VkDeviceSize       offset;
1054             VK_WHOLE_SIZE,                           // VkDeviceSize       size;
1055         };
1056 
1057         vk.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT,
1058                               (VkDependencyFlags)0, 0u, DE_NULL, 1u, &barrier, DE_NULL, 0u);
1059     }
1060 }
1061 
recordClearAttachments(const DeviceInterface & vk,const VkCommandBuffer cmdBuffer,const uint32_t colorAttachment,const VkClearValue & colorClearValue,const VkImageAspectFlags depthStencilAspect,const VkClearValue & depthStencilClearValue,const VkRect2D & clearRect)1062 void recordClearAttachments(const DeviceInterface &vk, const VkCommandBuffer cmdBuffer, const uint32_t colorAttachment,
1063                             const VkClearValue &colorClearValue, const VkImageAspectFlags depthStencilAspect,
1064                             const VkClearValue &depthStencilClearValue, const VkRect2D &clearRect)
1065 {
1066     std::vector<VkClearAttachment> attachments;
1067 
1068     const VkClearRect rect = {
1069         clearRect, // VkRect2D    rect;
1070         0u,        // uint32_t    baseArrayLayer;
1071         1u,        // uint32_t    layerCount;
1072     };
1073 
1074     // Clear color
1075     {
1076         const VkClearAttachment attachment = {
1077             VK_IMAGE_ASPECT_COLOR_BIT, // VkImageAspectFlags    aspectMask;
1078             colorAttachment,           // uint32_t              colorAttachment;
1079             colorClearValue,           // VkClearValue          clearValue;
1080         };
1081         attachments.push_back(attachment);
1082     }
1083 
1084     if ((depthStencilAspect & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) != 0u)
1085     {
1086         const VkClearAttachment attachment = {
1087             depthStencilAspect,     // VkImageAspectFlags    aspectMask;
1088             VK_ATTACHMENT_UNUSED,   // uint32_t              colorAttachment;
1089             depthStencilClearValue, // VkClearValue          clearValue;
1090         };
1091         attachments.push_back(attachment);
1092     }
1093 
1094     vk.cmdClearAttachments(cmdBuffer, static_cast<uint32_t>(attachments.size()), dataOrNullPtr(attachments), 1u, &rect);
1095 }
1096 
1097 //! Suitable for executing in a render pass, no queries
beginSecondaryCommandBuffer(const DeviceInterface & vk,const VkCommandBuffer commandBuffer,const RenderPassWrapper & renderPass,const uint32_t subpass,const VkSampleCountFlagBits samples,const PipelineConstructionType pct)1098 void beginSecondaryCommandBuffer(const DeviceInterface &vk, const VkCommandBuffer commandBuffer,
1099                                  const RenderPassWrapper &renderPass, const uint32_t subpass,
1100                                  const VkSampleCountFlagBits samples, const PipelineConstructionType pct)
1101 {
1102     DE_UNREF(samples);
1103     DE_UNREF(pct);
1104     VkCommandBufferInheritanceInfo inheritanceInfo = {
1105         VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO, // VkStructureType                  sType;
1106         DE_NULL,                                           // const void*                      pNext;
1107         *renderPass,                                       // VkRenderPass                     renderPass;
1108         subpass,                                           // uint32_t                         subpass;
1109         renderPass.getFramebuffer(),                       // VkFramebuffer                    framebuffer;
1110         VK_FALSE,                                          // VkBool32                         occlusionQueryEnable;
1111         (VkQueryControlFlags)0,                            // VkQueryControlFlags              queryFlags;
1112         (VkQueryPipelineStatisticFlags)0,                  // VkQueryPipelineStatisticFlags    pipelineStatistics;
1113     };
1114 
1115     const VkCommandBufferBeginInfo beginInfo = {
1116         VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, // VkStructureType                          sType;
1117         DE_NULL,                                     // const void*                              pNext;
1118         (VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT |
1119          VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT), // VkCommandBufferUsageFlags                flags;
1120         &inheritanceInfo, // const VkCommandBufferInheritanceInfo*    pInheritanceInfo;
1121     };
1122 
1123 #ifndef CTS_USES_VULKANSC
1124     vk::VkCommandBufferInheritanceRenderingInfo inheritanceRenderingInfo = vk::initVulkanStructure();
1125     inheritanceRenderingInfo.flags                                       = (VkRenderingFlags)0u;
1126     inheritanceRenderingInfo.viewMask                                    = 0x0;
1127     inheritanceRenderingInfo.rasterizationSamples                        = samples;
1128     std::vector<vk::VkFormat> colorFormats;
1129     if (isConstructionTypeShaderObject(pct))
1130     {
1131         renderPass.fillInheritanceRenderingInfo(subpass, &colorFormats, &inheritanceRenderingInfo);
1132         inheritanceInfo.pNext = &inheritanceRenderingInfo;
1133     }
1134 #endif
1135 
1136     VK_CHECK(vk.beginCommandBuffer(commandBuffer, &beginInfo));
1137 }
1138 
1139 //! Verify results of a VkPhysicalDeviceSampleLocationsPropertiesEXT query with VkPhysicalDeviceProperties2KHR
testQuerySampleLocationProperties(Context & context)1140 tcu::TestStatus testQuerySampleLocationProperties(Context &context)
1141 {
1142     const VkPhysicalDeviceSampleLocationsPropertiesEXT sampleLocationsProperties =
1143         getSampleLocationsPropertiesEXT(context);
1144 
1145     context.getTestContext().getLog() << tcu::TestLog::Section("VkPhysicalDeviceSampleLocationsPropertiesEXT",
1146                                                                "Query results")
1147                                       << tcu::TestLog::Message << sampleLocationsProperties << tcu::TestLog::EndMessage
1148                                       << tcu::TestLog::EndSection;
1149 
1150     const VkSampleCountFlags allowedSampleCounts =
1151         (VK_SAMPLE_COUNT_2_BIT | VK_SAMPLE_COUNT_4_BIT | VK_SAMPLE_COUNT_8_BIT | VK_SAMPLE_COUNT_16_BIT |
1152          VK_SAMPLE_COUNT_32_BIT | VK_SAMPLE_COUNT_64_BIT);
1153 
1154     if ((sampleLocationsProperties.sampleLocationSampleCounts & allowedSampleCounts) == 0)
1155     {
1156         return tcu::TestStatus::fail("VkPhysicalDeviceSampleLocationsPropertiesEXT: sampleLocationSampleCounts should "
1157                                      "specify at least one MSAA sample count");
1158     }
1159 
1160     if (sampleLocationsProperties.maxSampleLocationGridSize.width == 0u ||
1161         sampleLocationsProperties.maxSampleLocationGridSize.height == 0u ||
1162         sampleLocationsProperties.maxSampleLocationGridSize.width >
1163             16384u || // max not specified, but try to catch nonsense values like -1
1164         sampleLocationsProperties.maxSampleLocationGridSize.height > 16384u)
1165     {
1166         return tcu::TestStatus::fail(
1167             "VkPhysicalDeviceSampleLocationsPropertiesEXT: maxSampleLocationGridSize must be at least (1,1) size");
1168     }
1169 
1170     for (int i = 0; i < 2; ++i)
1171     {
1172         if (sampleLocationsProperties.sampleLocationCoordinateRange[i] < 0.0f ||
1173             sampleLocationsProperties.sampleLocationCoordinateRange[i] > 1.0f)
1174         {
1175             return tcu::TestStatus::fail("VkPhysicalDeviceSampleLocationsPropertiesEXT: "
1176                                          "sampleLocationCoordinateRange[] values must be in [0, 1] range");
1177         }
1178     }
1179 
1180     if (sampleLocationsProperties.sampleLocationSubPixelBits == 0u ||
1181         sampleLocationsProperties.sampleLocationSubPixelBits >
1182             64u) // max not specified, but try to catch nonsense values
1183     {
1184         return tcu::TestStatus::fail(
1185             "VkPhysicalDeviceSampleLocationsPropertiesEXT: sampleLocationSubPixelBits should be greater than 0");
1186     }
1187 
1188     return tcu::TestStatus::pass("Pass");
1189 }
1190 
1191 //! Verify results of vkGetPhysicalDeviceMultisamplePropertiesEXT queries
testQueryMultisampleProperties(Context & context)1192 tcu::TestStatus testQueryMultisampleProperties(Context &context)
1193 {
1194     const InstanceInterface &vki          = context.getInstanceInterface();
1195     const VkPhysicalDevice physicalDevice = context.getPhysicalDevice();
1196     tcu::TestLog &log                     = context.getTestContext().getLog();
1197 
1198     const VkPhysicalDeviceSampleLocationsPropertiesEXT sampleLocationsProperties =
1199         getSampleLocationsPropertiesEXT(context);
1200 
1201     const VkSampleCountFlagBits sampleCountRange[] = {
1202         VK_SAMPLE_COUNT_1_BIT,  VK_SAMPLE_COUNT_2_BIT,  VK_SAMPLE_COUNT_4_BIT,  VK_SAMPLE_COUNT_8_BIT,
1203         VK_SAMPLE_COUNT_16_BIT, VK_SAMPLE_COUNT_32_BIT, VK_SAMPLE_COUNT_64_BIT,
1204     };
1205 
1206     bool allOk = true;
1207 
1208     for (const VkSampleCountFlagBits *pLoopNumSamples = sampleCountRange;
1209          pLoopNumSamples < DE_ARRAY_END(sampleCountRange); ++pLoopNumSamples)
1210     {
1211         VkMultisamplePropertiesEXT multisampleProperties = {
1212             VK_STRUCTURE_TYPE_MULTISAMPLE_PROPERTIES_EXT, // VkStructureType    sType;
1213             DE_NULL,                                      // void*              pNext;
1214             VkExtent2D(),                                 // VkExtent2D         maxSampleLocationGridSize;
1215         };
1216 
1217         vki.getPhysicalDeviceMultisamplePropertiesEXT(physicalDevice, *pLoopNumSamples, &multisampleProperties);
1218 
1219         log << tcu::TestLog::Section("getPhysicalDeviceMultisamplePropertiesEXT", "Query results")
1220             << tcu::TestLog::Message << "Sample count: " << *pLoopNumSamples << tcu::TestLog::EndMessage
1221             << tcu::TestLog::Message << multisampleProperties << tcu::TestLog::EndMessage;
1222 
1223         const bool isSupportedSampleCount =
1224             (*pLoopNumSamples & sampleLocationsProperties.sampleLocationSampleCounts) != 0;
1225 
1226         if (isSupportedSampleCount)
1227         {
1228             if (!(multisampleProperties.maxSampleLocationGridSize.width >=
1229                       sampleLocationsProperties.maxSampleLocationGridSize.width &&
1230                   multisampleProperties.maxSampleLocationGridSize.height >=
1231                       sampleLocationsProperties.maxSampleLocationGridSize.height))
1232             {
1233                 allOk = false;
1234                 log << tcu::TestLog::Message
1235                     << "FAIL: Grid size should be the same or larger than "
1236                        "VkPhysicalDeviceSampleLocationsPropertiesEXT::maxSampleLocationGridSize"
1237                     << tcu::TestLog::EndMessage;
1238             }
1239         }
1240         else
1241         {
1242             if (!(multisampleProperties.maxSampleLocationGridSize.width == 0u &&
1243                   multisampleProperties.maxSampleLocationGridSize.height == 0u))
1244             {
1245                 allOk = false;
1246                 log << tcu::TestLog::Message << "FAIL: Expected (0, 0) grid size" << tcu::TestLog::EndMessage;
1247             }
1248         }
1249 
1250         log << tcu::TestLog::EndSection;
1251     }
1252 
1253     return allOk ? tcu::TestStatus::pass("Pass") : tcu::TestStatus::fail("Some values were incorrect");
1254 }
1255 
1256 // These tests only use a color attachment and focus on per-sample data
1257 namespace VerifySamples
1258 {
1259 
1260 //! Data layout used in verify sample locations and interpolation cases
1261 namespace SampleDataSSBO
1262 {
1263 
1264 static VkDeviceSize STATIC_SIZE = 6 * sizeof(uint32_t);
1265 
renderSize(void * const basePtr)1266 static UVec2 &renderSize(void *const basePtr)
1267 {
1268     return *reinterpret_cast<UVec2 *>(static_cast<uint8_t *>(basePtr) + 0 * sizeof(uint32_t));
1269 }
gridSize(void * const basePtr)1270 static UVec2 &gridSize(void *const basePtr)
1271 {
1272     return *reinterpret_cast<UVec2 *>(static_cast<uint8_t *>(basePtr) + 2 * sizeof(uint32_t));
1273 }
samplesPerPixel(void * const basePtr)1274 static uint32_t &samplesPerPixel(void *const basePtr)
1275 {
1276     return *reinterpret_cast<uint32_t *>(static_cast<uint8_t *>(basePtr) + 4 * sizeof(uint32_t));
1277 }
1278 
1279 template <typename T>
sampleData(void * const basePtr)1280 static T *sampleData(void *const basePtr)
1281 {
1282     DE_STATIC_ASSERT(sizeof(T) == sizeof(Vec2));
1283     return reinterpret_cast<T *>(static_cast<uint8_t *>(basePtr) + STATIC_SIZE);
1284 }
1285 
1286 } // namespace SampleDataSSBO
1287 
1288 enum TestOptionFlagBits
1289 {
1290     TEST_OPTION_DYNAMIC_STATE_BIT             = 0x1, //!< Use dynamic pipeline state to pass in sample locations
1291     TEST_OPTION_CLOSELY_PACKED_BIT            = 0x2, //!< Place samples as close as possible to each other
1292     TEST_OPTION_FRAGMENT_SHADING_RATE_BIT     = 0x4, //!< Use VK_KHR_fragment_shading_rate
1293     TEST_OPTION_VARIABLE_SAMPLE_LOCATIONS_BIT = 0x8  //!< Use variable sample locations
1294 };
1295 typedef uint32_t TestOptionFlags;
1296 
1297 struct TestParams
1298 {
1299     PipelineConstructionType pipelineConstructionType;
1300     VkSampleCountFlagBits numSamples;
1301     TestOptionFlags options;
1302 };
1303 
checkSupportVerifyTests(Context & context,const TestParams params)1304 void checkSupportVerifyTests(Context &context, const TestParams params)
1305 {
1306     checkSupportSampleLocations(context);
1307 
1308     context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_SAMPLE_RATE_SHADING);
1309 
1310     if ((context.getDeviceProperties().limits.framebufferColorSampleCounts & params.numSamples) == 0u)
1311         TCU_THROW(NotSupportedError, "framebufferColorSampleCounts: sample count not supported");
1312 
1313     if ((getSampleLocationsPropertiesEXT(context).sampleLocationSampleCounts & params.numSamples) == 0u)
1314         TCU_THROW(NotSupportedError, "VkPhysicalDeviceSampleLocationsPropertiesEXT: sample count not supported");
1315 
1316     if (TEST_OPTION_FRAGMENT_SHADING_RATE_BIT & params.options)
1317         checkFragmentShadingRateRequirements(context, params.numSamples);
1318 
1319     if (TEST_OPTION_VARIABLE_SAMPLE_LOCATIONS_BIT & params.options &&
1320         !getSampleLocationsPropertiesEXT(context).variableSampleLocations)
1321         TCU_THROW(NotSupportedError,
1322                   "VkPhysicalDeviceSampleLocationsPropertiesEXT: variableSampleLocations not supported");
1323 
1324     checkPipelineConstructionRequirements(context.getInstanceInterface(), context.getPhysicalDevice(),
1325                                           params.pipelineConstructionType);
1326 }
1327 
declareSampleDataSSBO(void)1328 std::string declareSampleDataSSBO(void)
1329 {
1330     std::ostringstream str;
1331     str << "layout(set = 0, binding = 0, std430) readonly buffer SampleData {\n" // make sure this matches SampleDataSSBO definition
1332         << "    uvec2 renderSize;\n"
1333         << "    uvec2 gridSize;\n"
1334         << "    uint  samplesPerPixel;\n"
1335         << "          // padding 1-uint size;\n"
1336         << "    vec2  data[];\n"
1337         << "} sb_data;\n";
1338     return str.str();
1339 }
1340 
addProgramsVerifyLocationGeometry(SourceCollections & programCollection,const TestParams)1341 void addProgramsVerifyLocationGeometry(SourceCollections &programCollection, const TestParams)
1342 {
1343     // Vertex shader
1344     {
1345         std::ostringstream src;
1346         src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
1347             << "\n"
1348             << "layout(location = 0) in vec4 in_position;\n"
1349             << "\n"
1350             << "out gl_PerVertex {\n"
1351             << "    vec4 gl_Position;\n"
1352             << "};\n"
1353             << "\n"
1354             << "void main(void)\n"
1355             << "{\n"
1356             << "    gl_Position = in_position;\n"
1357             << "}\n";
1358 
1359         programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
1360     }
1361 
1362     // Fragment shader
1363     {
1364         std::ostringstream src;
1365         src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
1366             << "\n"
1367             << "layout(location = 0) out vec4 o_color;\n"
1368             << "\n"
1369             << declareSampleDataSSBO() << "\n"
1370             << "void main(void)\n"
1371             << "{\n"
1372             << "    uvec2 fragCoord = uvec2(gl_FragCoord.xy);\n"
1373             << "    uint  index     = (fragCoord.y * sb_data.renderSize.x + fragCoord.x) * sb_data.samplesPerPixel + "
1374                "gl_SampleID;\n"
1375             << "\n"
1376             << "    if (gl_PrimitiveID == index)\n"
1377             << "        o_color = vec4(0.0, 1.0, 0.0, 1.0);\n"
1378             << "    else\n"
1379             << "        o_color = vec4(1.0, 0.0, 0.0, 1.0);\n"
1380             << "}\n";
1381 
1382         programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
1383     }
1384 }
1385 
addProgramsVerifyInterpolation(SourceCollections & programCollection,const TestParams)1386 void addProgramsVerifyInterpolation(SourceCollections &programCollection, const TestParams)
1387 {
1388     // Vertex shader
1389     {
1390         std::ostringstream src;
1391         src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
1392             << "\n"
1393             << "layout(location = 0) in  vec4 in_position;\n"
1394             << "layout(location = 0) out vec2 o_position;\n"
1395             << "\n"
1396             << "out gl_PerVertex {\n"
1397             << "    vec4 gl_Position;\n"
1398             << "};\n"
1399             << "\n"
1400             << "void main(void)\n"
1401             << "{\n"
1402             << "    gl_Position = in_position;\n"
1403             << "    o_position  = in_position.xy;\n" // user-data that will be interpolated
1404             << "}\n";
1405 
1406         programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
1407     }
1408 
1409     // Fragment shader
1410     {
1411         std::ostringstream src;
1412         src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
1413             << "\n"
1414             << "layout(location = 0) sample in  vec2 in_value;\n"
1415             << "layout(location = 0)        out vec4 o_color;\n"
1416             << "\n"
1417             << declareSampleDataSSBO() << "\n"
1418             << "void main(void)\n"
1419             << "{\n"
1420             << "    uvec2 fragCoord         = uvec2(gl_FragCoord.xy);\n"
1421             << "    uint  index             = (fragCoord.y * sb_data.renderSize.x + fragCoord.x) * "
1422                "sb_data.samplesPerPixel + gl_SampleID;\n"
1423             << "    vec2  diff              = abs(sb_data.data[index] - in_value);\n"
1424             << "    vec2  threshold         = vec2(0.002);\n"
1425             << "\n"
1426             << "    if (all(lessThan(diff, threshold)))\n"
1427             << "        o_color = vec4(0.0, 1.0, 0.0, 1.0);\n"
1428             << "    else\n"
1429             << "        o_color = vec4(1.0, 0.0, 0.0, 1.0);\n"
1430             << "}\n";
1431 
1432         programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
1433     }
1434 }
1435 
1436 class TestBase : public TestInstance
1437 {
1438 public:
TestBase(Context & context,const TestParams params)1439     TestBase(Context &context, const TestParams params)
1440         : TestInstance(context)
1441         , m_params(params)
1442         , m_sampleLocationsProperties(getSampleLocationsPropertiesEXT(context))
1443         , m_colorFormat(VK_FORMAT_R8G8B8A8_UNORM)
1444         , m_numVertices(0)
1445         , m_currentGridNdx(0)
1446     {
1447         VkMultisamplePropertiesEXT multisampleProperties = {
1448             VK_STRUCTURE_TYPE_MULTISAMPLE_PROPERTIES_EXT, // VkStructureType    sType;
1449             DE_NULL,                                      // void*              pNext;
1450             VkExtent2D(),                                 // VkExtent2D         maxSampleLocationGridSize;
1451         };
1452 
1453         m_context.getInstanceInterface().getPhysicalDeviceMultisamplePropertiesEXT(
1454             m_context.getPhysicalDevice(), m_params.numSamples, &multisampleProperties);
1455 
1456         // Generate grid size combinations
1457         for (uint32_t y = multisampleProperties.maxSampleLocationGridSize.height; y >= 1u; y >>= 1)
1458             for (uint32_t x = multisampleProperties.maxSampleLocationGridSize.width; x >= 1u; x >>= 1)
1459             {
1460                 DE_ASSERT(multisampleProperties.maxSampleLocationGridSize.width % x == 0u);
1461                 DE_ASSERT(multisampleProperties.maxSampleLocationGridSize.height % y == 0u);
1462                 m_gridSizes.push_back(UVec2(x, y));
1463             }
1464     }
1465 
iterate(void)1466     tcu::TestStatus iterate(void)
1467     {
1468         // Will be executed several times, for all possible pixel grid sizes
1469         if (!(currentGridSize().x() >= 1 && currentGridSize().y() >= 1))
1470             return tcu::TestStatus::fail("maxSampleLocationGridSize is invalid");
1471 
1472         // Prepare the pixel grid
1473         {
1474             const uint32_t pixelGridRepetitions =
1475                 2; // just to make sure the pattern is consistently applied across the framebuffer
1476             m_renderSize =
1477                 UVec2(pixelGridRepetitions * currentGridSize().x(), pixelGridRepetitions * currentGridSize().y());
1478             m_pixelGrid =
1479                 MovePtr<MultisamplePixelGrid>(new MultisamplePixelGrid(currentGridSize(), m_params.numSamples));
1480 
1481             if ((m_params.options & TEST_OPTION_CLOSELY_PACKED_BIT) != 0u)
1482                 fillSampleLocationsPacked(*m_pixelGrid, m_sampleLocationsProperties.sampleLocationSubPixelBits);
1483             else
1484                 fillSampleLocationsRandom(*m_pixelGrid, m_sampleLocationsProperties.sampleLocationSubPixelBits);
1485 
1486             logPixelGrid(m_context.getTestContext().getLog(), m_sampleLocationsProperties, *m_pixelGrid);
1487         }
1488 
1489         // Create images
1490         {
1491             const DeviceInterface &vk = m_context.getDeviceInterface();
1492             const VkDevice device     = m_context.getDevice();
1493             Allocator &allocator      = m_context.getDefaultAllocator();
1494 
1495             // Images and staging buffers
1496 
1497             m_colorImage      = makeImage(vk, device, (VkImageCreateFlags)0, m_colorFormat, m_renderSize,
1498                                           m_params.numSamples, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT);
1499             m_colorImageAlloc = bindImage(vk, device, allocator, *m_colorImage, MemoryRequirement::Any);
1500             m_colorImageView  = makeImageView(vk, device, *m_colorImage, VK_IMAGE_VIEW_TYPE_2D, m_colorFormat,
1501                                               makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u));
1502 
1503             m_resolveImage =
1504                 makeImage(vk, device, (VkImageCreateFlags)0, m_colorFormat, m_renderSize, VK_SAMPLE_COUNT_1_BIT,
1505                           VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
1506             m_resolveImageAlloc = bindImage(vk, device, allocator, *m_resolveImage, MemoryRequirement::Any);
1507             m_resolveImageView  = makeImageView(vk, device, *m_resolveImage, VK_IMAGE_VIEW_TYPE_2D, m_colorFormat,
1508                                                 makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u));
1509 
1510             const VkDeviceSize colorBufferSize =
1511                 m_renderSize.x() * m_renderSize.y() * tcu::getPixelSize(mapVkFormat(m_colorFormat));
1512             m_colorBuffer      = makeBuffer(vk, device, colorBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT);
1513             m_colorBufferAlloc = bindBuffer(vk, device, allocator, *m_colorBuffer, MemoryRequirement::HostVisible);
1514         }
1515 
1516         if (!testPixelGrid())
1517             return tcu::TestStatus::fail("Fail");
1518 
1519         if (shrinkCurrentGrid())
1520             return tcu::TestStatus::incomplete();
1521         else
1522             return tcu::TestStatus::pass("Pass");
1523     }
1524 
1525 protected:
1526     //! Return true if the test passed the current grid size
1527     virtual bool testPixelGrid(void) = 0;
1528 
currentGridSize(void)1529     const UVec2 &currentGridSize(void)
1530     {
1531         return m_gridSizes[m_currentGridNdx];
1532     }
1533 
1534     //! Return false if the grid is already at (1, 1) size
shrinkCurrentGrid(void)1535     bool shrinkCurrentGrid(void)
1536     {
1537         if (m_gridSizes.size() <= m_currentGridNdx + 1)
1538             return false;
1539 
1540         ++m_currentGridNdx;
1541         return true;
1542     }
1543 
drawSinglePass(const VertexInputConfig vertexInputConfig)1544     void drawSinglePass(const VertexInputConfig vertexInputConfig)
1545     {
1546         DE_ASSERT(m_descriptorSetLayout);
1547 
1548         const InstanceInterface &vki          = m_context.getInstanceInterface();
1549         const DeviceInterface &vk             = m_context.getDeviceInterface();
1550         const VkPhysicalDevice physicalDevice = m_context.getPhysicalDevice();
1551         const VkDevice device                 = m_context.getDevice();
1552         const VkViewport viewport             = makeViewport(m_renderSize);
1553         const VkRect2D renderArea             = makeRect2D(m_renderSize);
1554         const VkRect2D scissor                = makeRect2D(m_renderSize);
1555         const ShaderWrapper vertexModule(ShaderWrapper(vk, device, m_context.getBinaryCollection().get("vert"), 0u));
1556         const ShaderWrapper fragmentModule(ShaderWrapper(vk, device, m_context.getBinaryCollection().get("frag"), 0u));
1557         const PipelineLayoutWrapper pipelineLayout(m_params.pipelineConstructionType, vk, device,
1558                                                    *m_descriptorSetLayout);
1559 
1560         const bool useDynamicStateSampleLocations = ((m_params.options & TEST_OPTION_DYNAMIC_STATE_BIT) != 0u);
1561         const bool useFragmentShadingRate         = ((m_params.options & TEST_OPTION_FRAGMENT_SHADING_RATE_BIT) != 0u);
1562         const VkSampleLocationsInfoEXT sampleLocationsInfo = makeSampleLocationsInfo(*m_pixelGrid);
1563 
1564         RenderTarget rt;
1565 
1566         rt.addAttachment(*m_colorImage,                            // VkImage                        image,
1567                          *m_colorImageView,                        // VkImageView                    imageView,
1568                          (VkAttachmentDescriptionFlags)0,          // VkAttachmentDescriptionFlags    flags,
1569                          m_colorFormat,                            // VkFormat                        format,
1570                          m_params.numSamples,                      // VkSampleCountFlagBits        numSamples,
1571                          VK_ATTACHMENT_LOAD_OP_CLEAR,              // VkAttachmentLoadOp            loadOp,
1572                          VK_ATTACHMENT_STORE_OP_STORE,             // VkAttachmentStoreOp            storeOp,
1573                          VK_ATTACHMENT_LOAD_OP_DONT_CARE,          // VkAttachmentLoadOp            stencilLoadOp,
1574                          VK_ATTACHMENT_STORE_OP_DONT_CARE,         // VkAttachmentStoreOp            stencilStoreOp,
1575                          VK_IMAGE_LAYOUT_UNDEFINED,                // VkImageLayout                initialLayout,
1576                          VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout                finalLayout,
1577                          makeClearValueColor(CLEAR_COLOR_0));      // VkClearValue                    clearValue,
1578 
1579         rt.addAttachment(*m_resolveImage,                      // VkImage                        image
1580                          *m_resolveImageView,                  // VkImageView                    imageView,
1581                          (VkAttachmentDescriptionFlags)0,      // VkAttachmentDescriptionFlags    flags,
1582                          m_colorFormat,                        // VkFormat                        format,
1583                          VK_SAMPLE_COUNT_1_BIT,                // VkSampleCountFlagBits        numSamples,
1584                          VK_ATTACHMENT_LOAD_OP_DONT_CARE,      // VkAttachmentLoadOp            loadOp,
1585                          VK_ATTACHMENT_STORE_OP_STORE,         // VkAttachmentStoreOp            storeOp,
1586                          VK_ATTACHMENT_LOAD_OP_DONT_CARE,      // VkAttachmentLoadOp            stencilLoadOp,
1587                          VK_ATTACHMENT_STORE_OP_DONT_CARE,     // VkAttachmentStoreOp            stencilStoreOp,
1588                          VK_IMAGE_LAYOUT_UNDEFINED,            // VkImageLayout                initialLayout,
1589                          VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, // VkImageLayout                finalLayout,
1590                          VkClearValue());                      // VkClearValue                    clearValue,
1591 
1592         if (TEST_OPTION_VARIABLE_SAMPLE_LOCATIONS_BIT & m_params.options)
1593         {
1594             rt.addSubpassColorAttachmentWithResolve(0u, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, 1u,
1595                                                     VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, &sampleLocationsInfo);
1596         }
1597         else
1598         {
1599             rt.addSubpassColorAttachmentWithResolve(0u, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, 1u,
1600                                                     VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
1601         }
1602 
1603         rt.bake(vk, device, m_params.pipelineConstructionType, m_renderSize);
1604 
1605         GraphicsPipelineWrapper pipeline(vki, vk, physicalDevice, device, m_context.getDeviceExtensions(),
1606                                          m_params.pipelineConstructionType);
1607 
1608         if (useDynamicStateSampleLocations)
1609         {
1610             std::vector<VkDynamicState> dynamicState;
1611             dynamicState.push_back(VK_DYNAMIC_STATE_SAMPLE_LOCATIONS_EXT);
1612 
1613             preparePipelineWrapperSinglePassColor(
1614                 pipeline, dynamicState, pipelineLayout, rt.getRenderPass(), vertexModule, fragmentModule, viewport,
1615                 scissor, m_params.numSamples, /*use sample locations*/ true, makeEmptySampleLocationsInfo(),
1616                 vertexInputConfig, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, useFragmentShadingRate);
1617         }
1618         else
1619         {
1620             preparePipelineWrapperSinglePassColor(
1621                 pipeline, std::vector<VkDynamicState>(), pipelineLayout, rt.getRenderPass(), vertexModule,
1622                 fragmentModule, viewport, scissor, m_params.numSamples, /*use sample locations*/ true,
1623                 sampleLocationsInfo, vertexInputConfig, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, useFragmentShadingRate);
1624         }
1625 
1626         const Unique<VkCommandPool> cmdPool(createCommandPool(
1627             vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, m_context.getUniversalQueueFamilyIndex()));
1628         const Unique<VkCommandBuffer> cmdBuffer(makeCommandBuffer(vk, device, *cmdPool));
1629 
1630         beginCommandBuffer(vk, *cmdBuffer);
1631 
1632         rt.recordBeginRenderPass(vk, *cmdBuffer, renderArea, VK_SUBPASS_CONTENTS_INLINE);
1633 
1634         vk.cmdBindVertexBuffers(*cmdBuffer, /*first binding*/ 0u, /*num bindings*/ 1u, &m_vertexBuffer.get(),
1635                                 /*offsets*/ &ZERO);
1636         pipeline.bind(*cmdBuffer);
1637 
1638         if (useDynamicStateSampleLocations)
1639             vk.cmdSetSampleLocationsEXT(*cmdBuffer, &sampleLocationsInfo);
1640 
1641         if (m_descriptorSet)
1642             vk.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipelineLayout, 0u, 1u,
1643                                      &m_descriptorSet.get(), 0u, DE_NULL);
1644 
1645         vk.cmdDraw(*cmdBuffer, m_numVertices, 1u, 0u, 0u);
1646         rt.endRenderPass(vk, *cmdBuffer);
1647 
1648         recordCopyImageToBuffer(vk, *cmdBuffer, m_renderSize, *m_resolveImage, *m_colorBuffer);
1649 
1650         endCommandBuffer(vk, *cmdBuffer);
1651         submitCommandsAndWait(vk, device, m_context.getUniversalQueue(), *cmdBuffer);
1652 
1653         invalidateAlloc(vk, device, *m_colorBufferAlloc);
1654     }
1655 
createSampleDataBufferAndDescriptors(const VkDeviceSize bufferSize)1656     void createSampleDataBufferAndDescriptors(const VkDeviceSize bufferSize)
1657     {
1658         // Make sure the old descriptor set is destroyed before we destroy its pool
1659         m_descriptorSet = Move<VkDescriptorSet>();
1660 
1661         const DeviceInterface &vk = m_context.getDeviceInterface();
1662         const VkDevice device     = m_context.getDevice();
1663         Allocator &allocator      = m_context.getDefaultAllocator();
1664 
1665         m_sampleDataBuffer = makeBuffer(vk, device, bufferSize, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
1666         m_sampleDataBufferAlloc =
1667             bindBuffer(vk, device, allocator, *m_sampleDataBuffer, MemoryRequirement::HostVisible);
1668 
1669         m_descriptorSetLayout = DescriptorSetLayoutBuilder()
1670                                     .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_FRAGMENT_BIT)
1671                                     .build(vk, device);
1672 
1673         m_descriptorPool = DescriptorPoolBuilder()
1674                                .addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)
1675                                .build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
1676 
1677         m_descriptorSet = makeDescriptorSet(vk, device, *m_descriptorPool, *m_descriptorSetLayout);
1678 
1679         const VkDescriptorBufferInfo bufferDescriptorInfo =
1680             makeDescriptorBufferInfo(*m_sampleDataBuffer, 0ull, bufferSize);
1681         DescriptorSetUpdateBuilder()
1682             .writeSingle(*m_descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u),
1683                          VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &bufferDescriptorInfo)
1684             .update(vk, device);
1685 
1686         SampleDataSSBO::renderSize(m_sampleDataBufferAlloc->getHostPtr())      = m_renderSize;
1687         SampleDataSSBO::gridSize(m_sampleDataBufferAlloc->getHostPtr())        = m_pixelGrid->size();
1688         SampleDataSSBO::samplesPerPixel(m_sampleDataBufferAlloc->getHostPtr()) = m_pixelGrid->samplesPerPixel();
1689 
1690         flushAlloc(vk, device, *m_sampleDataBufferAlloc);
1691     }
1692 
1693     template <typename Vertex>
createVertexBuffer(const std::vector<Vertex> & vertices)1694     void createVertexBuffer(const std::vector<Vertex> &vertices)
1695     {
1696         const DeviceInterface &vk           = m_context.getDeviceInterface();
1697         const VkDevice device               = m_context.getDevice();
1698         Allocator &allocator                = m_context.getDefaultAllocator();
1699         const VkDeviceSize vertexBufferSize = static_cast<VkDeviceSize>(vertices.size() * sizeof(vertices[0]));
1700 
1701         m_numVertices       = static_cast<uint32_t>(vertices.size());
1702         m_vertexBuffer      = makeBuffer(vk, device, vertexBufferSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
1703         m_vertexBufferAlloc = bindBuffer(vk, device, allocator, *m_vertexBuffer, MemoryRequirement::HostVisible);
1704 
1705         deMemcpy(m_vertexBufferAlloc->getHostPtr(), dataOrNullPtr(vertices),
1706                  static_cast<std::size_t>(vertexBufferSize));
1707         flushAlloc(vk, device, *m_vertexBufferAlloc);
1708     }
1709 
1710     const TestParams m_params;
1711     const VkPhysicalDeviceSampleLocationsPropertiesEXT m_sampleLocationsProperties;
1712     const VkFormat m_colorFormat;
1713     UVec2 m_renderSize;
1714     MovePtr<MultisamplePixelGrid> m_pixelGrid;
1715     uint32_t m_numVertices;
1716     Move<VkBuffer> m_vertexBuffer;
1717     MovePtr<Allocation> m_vertexBufferAlloc;
1718     Move<VkImage> m_colorImage;
1719     Move<VkImageView> m_colorImageView;
1720     MovePtr<Allocation> m_colorImageAlloc;
1721     Move<VkImage> m_resolveImage;
1722     Move<VkImageView> m_resolveImageView;
1723     MovePtr<Allocation> m_resolveImageAlloc;
1724     Move<VkBuffer> m_colorBuffer;
1725     MovePtr<Allocation> m_colorBufferAlloc;
1726     Move<VkBuffer> m_sampleDataBuffer;
1727     MovePtr<Allocation> m_sampleDataBufferAlloc;
1728     Move<VkDescriptorSetLayout> m_descriptorSetLayout;
1729     Move<VkDescriptorPool> m_descriptorPool;
1730     Move<VkDescriptorSet> m_descriptorSet;
1731 
1732 private:
1733     uint32_t m_currentGridNdx;
1734     std::vector<UVec2> m_gridSizes;
1735 };
1736 
1737 //! Check that each custom sample has the expected position
1738 class VerifyLocationTest : public TestBase
1739 {
1740 public:
VerifyLocationTest(Context & context,const TestParams params)1741     VerifyLocationTest(Context &context, const TestParams params) : TestBase(context, params)
1742     {
1743     }
1744 
testPixelGrid(void)1745     bool testPixelGrid(void)
1746     {
1747         // Create vertices
1748         {
1749             // For each sample location (in the whole framebuffer), create a sub-pixel triangle that contains it.
1750             // NDC viewport size is 2.0 in X and Y and NDC pixel width/height depends on the framebuffer resolution.
1751             const Vec2 pixelSize = Vec2(2.0f) / m_renderSize.cast<float>();
1752             const Vec2 offset =
1753                 pixelSize / UVec2(1u << m_sampleLocationsProperties.sampleLocationSubPixelBits).cast<float>();
1754             std::vector<Vec4> vertices;
1755 
1756             // Surround with a roughly centered triangle
1757             const float y1 = 0.5f * offset.y();
1758             const float y2 = 0.35f * offset.y();
1759             const float x1 = 0.5f * offset.x();
1760 
1761             const std::vector<Vec2> locations =
1762                 genFramebufferSampleLocations(*m_pixelGrid, m_pixelGrid->size(), m_renderSize);
1763             for (std::vector<Vec2>::const_iterator iter = locations.begin(); iter != locations.end(); ++iter)
1764             {
1765                 vertices.push_back(Vec4(iter->x(), iter->y() - y1, 0.0f, 1.0f));
1766                 vertices.push_back(Vec4(iter->x() - x1, iter->y() + y2, 0.0f, 1.0f));
1767                 vertices.push_back(Vec4(iter->x() + x1, iter->y() + y2, 0.0f, 1.0f));
1768             }
1769 
1770             createVertexBuffer(vertices);
1771         }
1772 
1773         createSampleDataBufferAndDescriptors(SampleDataSSBO::STATIC_SIZE); // no per-sample data used
1774 
1775         drawSinglePass(VERTEX_INPUT_VEC4); // sample locations are taken from the pixel grid
1776 
1777         // Verify
1778 
1779         const tcu::ConstPixelBufferAccess image(
1780             tcu::ConstPixelBufferAccess(mapVkFormat(m_colorFormat), tcu::IVec3(m_renderSize.x(), m_renderSize.y(), 1),
1781                                         m_colorBufferAlloc->getHostPtr()));
1782 
1783         return compareGreenImage(m_context.getTestContext().getLog(), "resolve0", "Resolved test image", image);
1784     }
1785 };
1786 
1787 //! Verify that vertex attributes are correctly interpolated at each custom sample location
1788 class VerifyInterpolationTest : public TestBase
1789 {
1790 public:
VerifyInterpolationTest(Context & context,const TestParams params)1791     VerifyInterpolationTest(Context &context, const TestParams params) : TestBase(context, params)
1792     {
1793     }
1794 
testPixelGrid(void)1795     bool testPixelGrid(void)
1796     {
1797         createVertexBuffer(genVerticesFullQuad());
1798 
1799         // Create sample data SSBO
1800         {
1801             const uint32_t numSamples     = m_pixelGrid->samplesPerPixel();
1802             const uint32_t numDataEntries = numSamples * m_renderSize.x() * m_renderSize.y();
1803             const VkDeviceSize bufferSize = SampleDataSSBO::STATIC_SIZE + sizeof(Vec2) * numDataEntries;
1804 
1805             createSampleDataBufferAndDescriptors(bufferSize);
1806 
1807             Vec2 *const pSampleData = SampleDataSSBO::sampleData<Vec2>(m_sampleDataBufferAlloc->getHostPtr());
1808             const std::vector<Vec2> locations =
1809                 genFramebufferSampleLocations(*m_pixelGrid, m_pixelGrid->size(), m_renderSize);
1810 
1811             // Fill SSBO with interpolated values (here: from -1.0 to 1.0 across the render area in both x and y)
1812             DE_ASSERT(locations.size() == numDataEntries);
1813             std::copy(locations.begin(), locations.end(), pSampleData);
1814 
1815             flushAlloc(m_context.getDeviceInterface(), m_context.getDevice(), *m_sampleDataBufferAlloc);
1816         }
1817 
1818         drawSinglePass(VERTEX_INPUT_VEC4_VEC4); // sample locations are taken from the pixel grid
1819 
1820         // Verify
1821 
1822         const tcu::ConstPixelBufferAccess image(
1823             tcu::ConstPixelBufferAccess(mapVkFormat(m_colorFormat), tcu::IVec3(m_renderSize.x(), m_renderSize.y(), 1),
1824                                         m_colorBufferAlloc->getHostPtr()));
1825 
1826         return compareGreenImage(m_context.getTestContext().getLog(), "resolve0", "Resolved test image", image);
1827     }
1828 };
1829 
1830 template <typename Test, typename ProgramsFunc>
addCases(tcu::TestCaseGroup * group,const VkSampleCountFlagBits numSamples,PipelineConstructionType pipelineConstructionType,bool useFragmentShadingRate,const ProgramsFunc initPrograms)1831 void addCases(tcu::TestCaseGroup *group, const VkSampleCountFlagBits numSamples,
1832               PipelineConstructionType pipelineConstructionType, bool useFragmentShadingRate,
1833               const ProgramsFunc initPrograms)
1834 {
1835     TestParams params;
1836     deMemset(&params, 0, sizeof(params));
1837 
1838     params.pipelineConstructionType = pipelineConstructionType;
1839     params.numSamples               = numSamples;
1840 
1841     struct TestOptions
1842     {
1843         std::string testSuffix;
1844         TestOptionFlags testFlags;
1845     };
1846 
1847     TestOptions testOpts[] = {
1848         {"", useFragmentShadingRate ? (TestOptionFlags)TEST_OPTION_FRAGMENT_SHADING_RATE_BIT :
1849                                       (TestOptionFlags)0 | (TestOptionFlags)TEST_OPTION_VARIABLE_SAMPLE_LOCATIONS_BIT},
1850         {"_invariable",
1851          useFragmentShadingRate ? (TestOptionFlags)TEST_OPTION_FRAGMENT_SHADING_RATE_BIT : (TestOptionFlags)0}};
1852 
1853     for (const auto &options : testOpts)
1854     {
1855         params.options = options.testFlags;
1856 
1857         addInstanceTestCaseWithPrograms<Test>(group, (getString(numSamples) + options.testSuffix).c_str(),
1858                                               checkSupportVerifyTests, initPrograms, params);
1859 
1860         params.options |= (TestOptionFlags)TEST_OPTION_DYNAMIC_STATE_BIT;
1861         addInstanceTestCaseWithPrograms<Test>(group, (getString(numSamples) + "_dynamic" + options.testSuffix).c_str(),
1862                                               checkSupportVerifyTests, initPrograms, params);
1863 
1864         params.options |= (TestOptionFlags)TEST_OPTION_CLOSELY_PACKED_BIT;
1865         addInstanceTestCaseWithPrograms<Test>(group, (getString(numSamples) + "_packed" + options.testSuffix).c_str(),
1866                                               checkSupportVerifyTests, initPrograms, params);
1867     }
1868 }
1869 
1870 } // namespace VerifySamples
1871 
1872 // Draw tests with at least two "passes" where sample locations may change.
1873 // Test case is based on a combination of parameters defined below. Not all combinations are compatible.
1874 namespace Draw
1875 {
1876 
1877 //! Options common to all test cases
1878 enum TestOptionFlagBits
1879 {
1880     TEST_OPTION_SAME_PATTERN_BIT  = 1u << 0, //!< Use the same sample pattern for all operations
1881     TEST_OPTION_DYNAMIC_STATE_BIT = 1u << 1, //!< Use dynamic pipeline state to pass in sample locations
1882     TEST_OPTION_SECONDARY_COMMAND_BUFFER_BIT =
1883         1u << 2, //!< Put drawing commands in a secondary buffer, including sample locations change (if dynamic)
1884     TEST_OPTION_GENERAL_LAYOUT_BIT = 1u << 3, //!< Transition the image to general layout at some point in rendering
1885     TEST_OPTION_WAIT_EVENTS_BIT =
1886         1u << 4, //!< Use image memory barriers with vkCmdWaitEvents rather than vkCmdPipelineBarrier
1887     TEST_OPTION_FRAGMENT_SHADING_RATE_BIT = 1u << 5, //!< Use VK_KHR_fragment_shading_rate
1888 };
1889 typedef uint32_t TestOptionFlags;
1890 
1891 //! Determines where draws/clears with custom samples occur in the test
1892 enum TestDrawIn
1893 {
1894     TEST_DRAW_IN_RENDER_PASSES = 0u, //!< Each operation in a separate render pass
1895     TEST_DRAW_IN_SUBPASSES,          //!< Each operation in a separate subpass of the same render pass
1896     TEST_DRAW_IN_SAME_SUBPASS,       //!< Each operation in the same subpass
1897 };
1898 
1899 //! How a clear before the second pass will be done
1900 enum TestClears
1901 {
1902     TEST_CLEARS_NO_CLEAR = 0u,         //!< Don't clear
1903     TEST_CLEARS_LOAD_OP_CLEAR,         //!< Render pass attachment load clear
1904     TEST_CLEARS_CMD_CLEAR_ATTACHMENTS, //!< vkCmdClearAttachments within a subpass
1905     TEST_CLEARS_CMD_CLEAR_IMAGE,       //!< vkCmdClear{Color|DepthStencil}Image outside a render pass
1906 };
1907 
1908 //! What type of image will be verified with custom samples
1909 enum TestImageAspect
1910 {
1911     TEST_IMAGE_ASPECT_COLOR = 0u, //!< Color image
1912     TEST_IMAGE_ASPECT_DEPTH,      //!< Depth aspect of an image (can be mixed format)
1913     TEST_IMAGE_ASPECT_STENCIL,    //!< Stencil aspect of an image (can be mixed format)
1914 };
1915 
1916 struct TestParams
1917 {
1918     PipelineConstructionType pipelineConstructionType;
1919     VkSampleCountFlagBits numSamples;
1920     TestOptionFlags options;
1921     TestDrawIn drawIn;
1922     TestClears clears;
1923     TestImageAspect imageAspect;
1924 };
1925 
checkSupportDrawTests(Context & context,const TestParams params)1926 void checkSupportDrawTests(Context &context, const TestParams params)
1927 {
1928     checkSupportSampleLocations(context);
1929 
1930     if ((context.getDeviceProperties().limits.framebufferColorSampleCounts & params.numSamples) == 0u)
1931         TCU_THROW(NotSupportedError, "framebufferColorSampleCounts: sample count not supported");
1932 
1933     if ((getSampleLocationsPropertiesEXT(context).sampleLocationSampleCounts & params.numSamples) == 0u)
1934         TCU_THROW(NotSupportedError, "VkPhysicalDeviceSampleLocationsPropertiesEXT: sample count not supported");
1935 
1936     // Are we allowed to modify the sample pattern within the same subpass?
1937     if (params.drawIn == TEST_DRAW_IN_SAME_SUBPASS && ((params.options & TEST_OPTION_SAME_PATTERN_BIT) == 0) &&
1938         !getSampleLocationsPropertiesEXT(context).variableSampleLocations)
1939         TCU_THROW(NotSupportedError,
1940                   "VkPhysicalDeviceSampleLocationsPropertiesEXT: variableSampleLocations not supported");
1941 
1942     if (TEST_OPTION_FRAGMENT_SHADING_RATE_BIT & params.options)
1943         checkFragmentShadingRateRequirements(context, params.numSamples);
1944 
1945     checkPipelineConstructionRequirements(context.getInstanceInterface(), context.getPhysicalDevice(),
1946                                           params.pipelineConstructionType);
1947 
1948 #ifndef CTS_USES_VULKANSC
1949     if (TEST_OPTION_WAIT_EVENTS_BIT & params.options &&
1950         context.isDeviceFunctionalitySupported("VK_KHR_portability_subset") &&
1951         !context.getPortabilitySubsetFeatures().events)
1952     {
1953         TCU_THROW(NotSupportedError, "VK_KHR_portability_subset: Events are not supported by this implementation");
1954     }
1955 #endif // CTS_USES_VULKANSC
1956 }
1957 
getString(const TestImageAspect aspect)1958 const char *getString(const TestImageAspect aspect)
1959 {
1960     switch (aspect)
1961     {
1962     case TEST_IMAGE_ASPECT_COLOR:
1963         return "color";
1964     case TEST_IMAGE_ASPECT_DEPTH:
1965         return "depth";
1966     case TEST_IMAGE_ASPECT_STENCIL:
1967         return "stencil";
1968     }
1969     DE_ASSERT(0);
1970     return DE_NULL;
1971 }
1972 
getString(const TestDrawIn drawIn)1973 const char *getString(const TestDrawIn drawIn)
1974 {
1975     switch (drawIn)
1976     {
1977     case TEST_DRAW_IN_RENDER_PASSES:
1978         return "separate_renderpass";
1979     case TEST_DRAW_IN_SUBPASSES:
1980         return "separate_subpass";
1981     case TEST_DRAW_IN_SAME_SUBPASS:
1982         return "same_subpass";
1983     }
1984     DE_ASSERT(0);
1985     return DE_NULL;
1986 }
1987 
getString(const TestClears clears)1988 const char *getString(const TestClears clears)
1989 {
1990     switch (clears)
1991     {
1992     case TEST_CLEARS_NO_CLEAR:
1993         return "no_clear";
1994     case TEST_CLEARS_LOAD_OP_CLEAR:
1995         return "load_op_clear";
1996     case TEST_CLEARS_CMD_CLEAR_ATTACHMENTS:
1997         return "clear_attachments";
1998     case TEST_CLEARS_CMD_CLEAR_IMAGE:
1999         return "clear_image";
2000     }
2001     DE_ASSERT(0);
2002     return DE_NULL;
2003 }
2004 
getTestOptionFlagsString(const uint32_t flags)2005 std::string getTestOptionFlagsString(const uint32_t flags)
2006 {
2007     std::ostringstream str;
2008 
2009     if ((flags & TEST_OPTION_SAME_PATTERN_BIT) != 0)
2010         str << (str.tellp() > 0 ? "_" : "") << "same_pattern";
2011     if ((flags & TEST_OPTION_DYNAMIC_STATE_BIT) != 0)
2012         str << (str.tellp() > 0 ? "_" : "") << "dynamic";
2013     if ((flags & TEST_OPTION_SECONDARY_COMMAND_BUFFER_BIT) != 0)
2014         str << (str.tellp() > 0 ? "_" : "") << "secondary_cmd_buf";
2015     if ((flags & TEST_OPTION_GENERAL_LAYOUT_BIT) != 0)
2016         str << (str.tellp() > 0 ? "_" : "") << "general_layout";
2017     if ((flags & TEST_OPTION_WAIT_EVENTS_BIT) != 0)
2018         str << (str.tellp() > 0 ? "_" : "") << "event";
2019 
2020     return str.str();
2021 }
2022 
initPrograms(SourceCollections & programCollection,const TestParams)2023 void initPrograms(SourceCollections &programCollection, const TestParams)
2024 {
2025     // Vertex shader
2026     {
2027         std::ostringstream src;
2028         src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
2029             << "\n"
2030             << "layout(location = 0) in  vec4 in_position;\n"
2031             << "layout(location = 1) in  vec4 in_color;\n"
2032             << "layout(location = 0) out vec4 o_color;\n"
2033             << "\n"
2034             << "out gl_PerVertex {\n"
2035             << "    vec4 gl_Position;\n"
2036             << "};\n"
2037             << "\n"
2038             << "void main(void)\n"
2039             << "{\n"
2040             << "    gl_Position = in_position;\n"
2041             << "    o_color     = in_color;\n"
2042             << "\n"
2043             // We use instance index to draw the left shape (index = 0) or the right shape (index = 1).
2044             // Vertices are squished and moved to either half of the viewport.
2045             << "    if (gl_InstanceIndex == 0)\n"
2046             << "        gl_Position.x = 0.5 * (gl_Position.x - 1.0);\n"
2047             << "    else if (gl_InstanceIndex == 1)\n"
2048             << "        gl_Position.x = 0.5 * (gl_Position.x + 1.0);\n"
2049             << "}\n";
2050 
2051         programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
2052     }
2053 
2054     // Fragment shader
2055     {
2056         std::ostringstream src;
2057         src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
2058             << "\n"
2059             << "layout(location = 0) in  vec4 in_color;\n"
2060             << "layout(location = 0) out vec4 o_color;\n"
2061             << "\n"
2062             << "void main(void)\n"
2063             << "{\n"
2064             << "    o_color = in_color;\n"
2065             << "}\n";
2066 
2067         programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
2068     }
2069 }
2070 
2071 //! Draw shapes using changing sample patterns. Add clears and other operations as necessary
2072 class DrawTest : public TestInstance
2073 {
2074     static const uint32_t NUM_PASSES = 2u;
2075 
2076 public:
DrawTest(Context & context,const TestParams params)2077     DrawTest(Context &context, const TestParams params)
2078         : TestInstance(context)
2079         , m_params(params)
2080         , m_sampleLocationsProperties(getSampleLocationsPropertiesEXT(context))
2081         , m_renderSize(64, 32)
2082         , m_numVertices(0)
2083         , m_colorFormat(VK_FORMAT_R8G8B8A8_UNORM)
2084         , m_depthStencilFormat(VK_FORMAT_UNDEFINED)
2085         , m_depthStencilAspect(0)
2086     {
2087         VkMultisamplePropertiesEXT multisampleProperties = {
2088             VK_STRUCTURE_TYPE_MULTISAMPLE_PROPERTIES_EXT, // VkStructureType    sType;
2089             DE_NULL,                                      // void*              pNext;
2090             VkExtent2D(),                                 // VkExtent2D         maxSampleLocationGridSize;
2091         };
2092 
2093         // For this test always use the full pixel grid
2094 
2095         m_context.getInstanceInterface().getPhysicalDeviceMultisamplePropertiesEXT(
2096             m_context.getPhysicalDevice(), m_params.numSamples, &multisampleProperties);
2097         m_gridSize.x() = multisampleProperties.maxSampleLocationGridSize.width;
2098         m_gridSize.y() = multisampleProperties.maxSampleLocationGridSize.height;
2099     }
2100 
iterate(void)2101     tcu::TestStatus iterate(void)
2102     {
2103         // Requirements
2104         if (!(m_gridSize.x() >= 1 && m_gridSize.y() >= 1))
2105             return tcu::TestStatus::fail("maxSampleLocationGridSize is invalid");
2106 
2107         // Images
2108         {
2109             const DeviceInterface &vk = m_context.getDeviceInterface();
2110             const VkDevice device     = m_context.getDevice();
2111             Allocator &allocator      = m_context.getDefaultAllocator();
2112             const VkImageUsageFlags colorImageUsageFlags =
2113                 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
2114 
2115             m_colorImage      = makeImage(vk, device, (VkImageCreateFlags)0, m_colorFormat, m_renderSize,
2116                                           m_params.numSamples, colorImageUsageFlags);
2117             m_colorImageAlloc = bindImage(vk, device, allocator, *m_colorImage, MemoryRequirement::Any);
2118             m_colorImageView  = makeImageView(vk, device, *m_colorImage, VK_IMAGE_VIEW_TYPE_2D, m_colorFormat,
2119                                               makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u));
2120 
2121             m_resolveImage      = makeImage(vk, device, (VkImageCreateFlags)0, m_colorFormat, m_renderSize,
2122                                             VK_SAMPLE_COUNT_1_BIT, colorImageUsageFlags);
2123             m_resolveImageAlloc = bindImage(vk, device, allocator, *m_resolveImage, MemoryRequirement::Any);
2124             m_resolveImageView  = makeImageView(vk, device, *m_resolveImage, VK_IMAGE_VIEW_TYPE_2D, m_colorFormat,
2125                                                 makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u));
2126 
2127             const VkDeviceSize colorBufferSize =
2128                 m_renderSize.x() * m_renderSize.y() * tcu::getPixelSize(mapVkFormat(m_colorFormat));
2129             m_colorBuffer      = makeBuffer(vk, device, colorBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT);
2130             m_colorBufferAlloc = bindBuffer(vk, device, allocator, *m_colorBuffer, MemoryRequirement::HostVisible);
2131 
2132             if (m_params.imageAspect != TEST_IMAGE_ASPECT_COLOR)
2133             {
2134                 const VkImageUsageFlags depthStencilImageUsageFlags =
2135                     VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
2136 
2137                 m_depthStencilFormat = findSupportedDepthStencilFormat(m_context, useDepth(), useStencil());
2138                 m_depthStencilAspect = (useDepth() ? VK_IMAGE_ASPECT_DEPTH_BIT : (VkImageAspectFlagBits)0) |
2139                                        (useStencil() ? VK_IMAGE_ASPECT_STENCIL_BIT : (VkImageAspectFlagBits)0);
2140                 m_depthStencilImage =
2141                     makeImage(vk, device, VK_IMAGE_CREATE_SAMPLE_LOCATIONS_COMPATIBLE_DEPTH_BIT_EXT,
2142                               m_depthStencilFormat, m_renderSize, m_params.numSamples, depthStencilImageUsageFlags);
2143                 m_depthStencilImageAlloc =
2144                     bindImage(vk, device, allocator, *m_depthStencilImage, MemoryRequirement::Any);
2145                 m_depthStencilImageView =
2146                     makeImageView(vk, device, *m_depthStencilImage, VK_IMAGE_VIEW_TYPE_2D, m_depthStencilFormat,
2147                                   makeImageSubresourceRange(m_depthStencilAspect, 0u, 1u, 0u, 1u));
2148             }
2149         }
2150 
2151         // Vertices
2152         {
2153             const DeviceInterface &vk = m_context.getDeviceInterface();
2154             const VkDevice device     = m_context.getDevice();
2155             Allocator &allocator      = m_context.getDefaultAllocator();
2156 
2157             std::vector<PositionColor> vertices;
2158 
2159             if (useDepth())
2160             {
2161                 append(vertices, genVerticesShapes(RGBA::black().toVec(),
2162                                                    DEPTH_REFERENCE / 2.0f)); // mask above (z = 0.0 is nearest)
2163                 append(vertices, genVerticesFullQuad(RGBA::white().toVec(),
2164                                                      DEPTH_REFERENCE)); // fill below the mask, using the depth test
2165             }
2166             else if (useStencil())
2167             {
2168                 append(vertices, genVerticesShapes(RGBA::black().toVec(), DEPTH_REFERENCE)); // first mask
2169                 append(vertices,
2170                        genVerticesFullQuad(RGBA::white().toVec(),
2171                                            DEPTH_REFERENCE / 2.0f)); // then fill the whole area, using the stencil test
2172             }
2173             else
2174                 vertices = genVerticesShapes();
2175 
2176             const VkDeviceSize vertexBufferSize = static_cast<VkDeviceSize>(vertices.size() * sizeof(vertices[0]));
2177 
2178             m_numVertices       = static_cast<uint32_t>(vertices.size());
2179             m_vertexBuffer      = makeBuffer(vk, device, vertexBufferSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
2180             m_vertexBufferAlloc = bindBuffer(vk, device, allocator, *m_vertexBuffer, MemoryRequirement::HostVisible);
2181 
2182             deMemcpy(m_vertexBufferAlloc->getHostPtr(), dataOrNullPtr(vertices),
2183                      static_cast<std::size_t>(vertexBufferSize));
2184             flushAlloc(vk, device, *m_vertexBufferAlloc);
2185         }
2186 
2187         // Multisample pixel grids - set up two sample patterns for two draw passes
2188         {
2189             const uint32_t numGrids = (useSameSamplePattern() ? 1u : NUM_PASSES);
2190             m_pixelGrids.reserve(numGrids);
2191 
2192             for (uint32_t passNdx = 0u; passNdx < numGrids; ++passNdx)
2193             {
2194                 const uint32_t seed = 142u + 75u * passNdx;
2195                 m_pixelGrids.push_back(MultisamplePixelGrid(m_gridSize, m_params.numSamples));
2196                 fillSampleLocationsRandom(m_pixelGrids.back(), m_sampleLocationsProperties.sampleLocationSubPixelBits,
2197                                           seed);
2198                 logPixelGrid(m_context.getTestContext().getLog(), m_sampleLocationsProperties, m_pixelGrids.back());
2199             }
2200         }
2201 
2202         // Some test cases will not clear the left hand image, so we can use it directly
2203         const bool isClearCase      = (m_params.clears != TEST_CLEARS_NO_CLEAR);
2204         const bool hasLeftSideImage = (!isClearCase || (m_params.drawIn != TEST_DRAW_IN_RENDER_PASSES &&
2205                                                         m_params.clears != TEST_CLEARS_CMD_CLEAR_ATTACHMENTS));
2206 
2207         // Render second pass reference image with the first pattern
2208         tcu::TextureLevel refImagePattern0;
2209         if (!useSameSamplePattern() && !hasLeftSideImage)
2210         {
2211             const tcu::TextureFormat colorFormat = mapVkFormat(m_colorFormat);
2212 
2213             drawPatternChangeReference();
2214 
2215             refImagePattern0.setStorage(colorFormat, m_renderSize.x(), m_renderSize.y());
2216             tcu::copy(refImagePattern0.getAccess(),
2217                       tcu::ConstPixelBufferAccess(colorFormat, tcu::IVec3(m_renderSize.x(), m_renderSize.y(), 1),
2218                                                   m_colorBufferAlloc->getHostPtr()));
2219         }
2220 
2221         // Two-pass rendering
2222 
2223         switch (m_params.drawIn)
2224         {
2225         case TEST_DRAW_IN_RENDER_PASSES:
2226             drawRenderPasses();
2227             break;
2228         case TEST_DRAW_IN_SUBPASSES:
2229             drawSubpasses();
2230             break;
2231         case TEST_DRAW_IN_SAME_SUBPASS:
2232             drawSameSubpass();
2233             break;
2234 
2235         default:
2236             DE_ASSERT(0);
2237             break;
2238         }
2239 
2240         // Log the result
2241 
2242         const tcu::ConstPixelBufferAccess image(
2243             tcu::ConstPixelBufferAccess(mapVkFormat(m_colorFormat), tcu::IVec3(m_renderSize.x(), m_renderSize.y(), 1),
2244                                         m_colorBufferAlloc->getHostPtr()));
2245 
2246         m_context.getTestContext().getLog()
2247             << tcu::TestLog::ImageSet("Result", "Final result") << tcu::TestLog::Image("resolve0", "resolve0", image)
2248             << tcu::TestLog::EndImageSet;
2249 
2250         // Verify result
2251         {
2252             DE_ASSERT((m_renderSize.x() % 2) == 0);
2253             DE_ASSERT((m_renderSize.y() % 2) == 0);
2254 
2255             // Count colors in each image half separately, each half may have its own background color
2256             const int numBackgroundColors    = 1;
2257             const int numExpectedColorsRight = numBackgroundColors + static_cast<int>(m_params.numSamples);
2258             const int numExpectedColorsLeft  = (isClearCase ? numBackgroundColors : numExpectedColorsRight);
2259             const int numActualColorsLeft =
2260                 countUniqueColors(tcu::getSubregion(image, 0, 0, m_renderSize.x() / 2, m_renderSize.y()));
2261             const int numActualColorsRight = countUniqueColors(
2262                 tcu::getSubregion(image, m_renderSize.x() / 2, 0, m_renderSize.x() / 2, m_renderSize.y()));
2263 
2264             if (numActualColorsLeft != numExpectedColorsLeft || numActualColorsRight != numExpectedColorsRight)
2265             {
2266                 std::ostringstream msg;
2267                 msg << "Expected " << numExpectedColorsLeft << " unique colors, but got " << numActualColorsLeft;
2268 
2269                 if (numActualColorsLeft != numActualColorsRight)
2270                     msg << " and " << numActualColorsRight;
2271 
2272                 m_context.getTestContext().getLog() << tcu::TestLog::Message << msg.str() << tcu::TestLog::EndMessage;
2273 
2274                 return tcu::TestStatus::fail("Resolved image has incorrect pixels");
2275             }
2276 
2277             if (hasLeftSideImage)
2278             {
2279                 // Compare the left and the right half
2280                 const bool match = intThresholdCompare(
2281                     tcu::getSubregion(image, 0, 0, m_renderSize.x() / 2, m_renderSize.y()),
2282                     tcu::getSubregion(image, m_renderSize.x() / 2, 0, m_renderSize.x() / 2, m_renderSize.y()),
2283                     UVec4(2u));
2284                 if (useSameSamplePattern() && !match)
2285                     return tcu::TestStatus::fail("Multisample pattern should be identical in both image halves");
2286                 else if (!useSameSamplePattern() && match)
2287                     return tcu::TestStatus::fail(
2288                         "Multisample pattern doesn't seem to change between left and right image halves");
2289             }
2290             else if (!useSameSamplePattern())
2291             {
2292                 // Compare the right half with the previously rendered reference image -- patterns should be different
2293                 bool match = intThresholdCompare(
2294                     tcu::getSubregion(refImagePattern0.getAccess(), m_renderSize.x() / 2, 0, m_renderSize.x() / 2,
2295                                       m_renderSize.y()),
2296                     tcu::getSubregion(image, m_renderSize.x() / 2, 0, m_renderSize.x() / 2, m_renderSize.y()),
2297                     UVec4(2u));
2298 
2299                 if (match)
2300                     return tcu::TestStatus::fail("Multisample pattern doesn't seem to change between passes");
2301             }
2302         }
2303 
2304         return tcu::TestStatus::pass("Pass");
2305     }
2306 
2307 protected:
useDepth(void) const2308     bool useDepth(void) const
2309     {
2310         return m_params.imageAspect == TEST_IMAGE_ASPECT_DEPTH;
2311     }
useStencil(void) const2312     bool useStencil(void) const
2313     {
2314         return m_params.imageAspect == TEST_IMAGE_ASPECT_STENCIL;
2315     }
useSameSamplePattern(void) const2316     bool useSameSamplePattern(void) const
2317     {
2318         return (m_params.options & TEST_OPTION_SAME_PATTERN_BIT) != 0u;
2319     }
useDynamicState(void) const2320     bool useDynamicState(void) const
2321     {
2322         return (m_params.options & TEST_OPTION_DYNAMIC_STATE_BIT) != 0u;
2323     }
useSecondaryCmdBuffer(void) const2324     bool useSecondaryCmdBuffer(void) const
2325     {
2326         return (m_params.options & TEST_OPTION_SECONDARY_COMMAND_BUFFER_BIT) != 0u;
2327     }
useGeneralLayout(void) const2328     bool useGeneralLayout(void) const
2329     {
2330         return (m_params.options & TEST_OPTION_GENERAL_LAYOUT_BIT) != 0u;
2331     }
useWaitEvents(void) const2332     bool useWaitEvents(void) const
2333     {
2334         return (m_params.options & TEST_OPTION_WAIT_EVENTS_BIT) != 0u;
2335     }
useFragmentShadingRate(void) const2336     bool useFragmentShadingRate(void) const
2337     {
2338         return (m_params.options & TEST_OPTION_FRAGMENT_SHADING_RATE_BIT) != 0u;
2339     }
2340 
2341     //! Draw the second pass image, but with sample pattern from the first pass -- used to verify that the pattern is different
drawPatternChangeReference(void)2342     void drawPatternChangeReference(void)
2343     {
2344         const InstanceInterface &vki          = m_context.getInstanceInterface();
2345         const DeviceInterface &vk             = m_context.getDeviceInterface();
2346         const VkPhysicalDevice physicalDevice = m_context.getPhysicalDevice();
2347         const VkDevice device                 = m_context.getDevice();
2348         const VkViewport viewport             = makeViewport(m_renderSize);
2349         const VkRect2D renderArea             = makeRect2D(m_renderSize);
2350         const VkRect2D scissor                = makeRect2D(m_renderSize);
2351         const ShaderWrapper vertexModule(ShaderWrapper(vk, device, m_context.getBinaryCollection().get("vert"), 0u));
2352         const ShaderWrapper fragmentModule(ShaderWrapper(vk, device, m_context.getBinaryCollection().get("frag"), 0u));
2353         const PipelineLayoutWrapper pipelineLayout(m_params.pipelineConstructionType, vk, device);
2354         const VkSampleLocationsInfoEXT sampleLocationsInfo = makeSampleLocationsInfo(m_pixelGrids[0]);
2355         const VkClearValue clearColor0 = (m_params.clears == TEST_CLEARS_NO_CLEAR ? makeClearValueColor(CLEAR_COLOR_0) :
2356                                                                                     makeClearValueColor(CLEAR_COLOR_1));
2357 
2358         RenderTarget rt;
2359 
2360         rt.addAttachment(*m_colorImage,                            // VkImage                        image
2361                          *m_colorImageView,                        // VkImageView                    imageView,
2362                          (VkAttachmentDescriptionFlags)0,          // VkAttachmentDescriptionFlags    flags,
2363                          m_colorFormat,                            // VkFormat                        format,
2364                          m_params.numSamples,                      // VkSampleCountFlagBits        numSamples,
2365                          VK_ATTACHMENT_LOAD_OP_CLEAR,              // VkAttachmentLoadOp            loadOp,
2366                          VK_ATTACHMENT_STORE_OP_STORE,             // VkAttachmentStoreOp            storeOp,
2367                          VK_ATTACHMENT_LOAD_OP_DONT_CARE,          // VkAttachmentLoadOp            stencilLoadOp,
2368                          VK_ATTACHMENT_STORE_OP_DONT_CARE,         // VkAttachmentStoreOp            stencilStoreOp,
2369                          VK_IMAGE_LAYOUT_UNDEFINED,                // VkImageLayout                initialLayout,
2370                          VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout                finalLayout,
2371                          clearColor0);                             // VkClearValue                    clearValue,
2372 
2373         rt.addAttachment(*m_resolveImage,                      // VkImage                        image
2374                          *m_resolveImageView,                  // VkImageView                    imageView,
2375                          (VkAttachmentDescriptionFlags)0,      // VkAttachmentDescriptionFlags    flags,
2376                          m_colorFormat,                        // VkFormat                        format,
2377                          VK_SAMPLE_COUNT_1_BIT,                // VkSampleCountFlagBits        numSamples,
2378                          VK_ATTACHMENT_LOAD_OP_DONT_CARE,      // VkAttachmentLoadOp            loadOp,
2379                          VK_ATTACHMENT_STORE_OP_STORE,         // VkAttachmentStoreOp            storeOp,
2380                          VK_ATTACHMENT_LOAD_OP_DONT_CARE,      // VkAttachmentLoadOp            stencilLoadOp,
2381                          VK_ATTACHMENT_STORE_OP_DONT_CARE,     // VkAttachmentStoreOp            stencilStoreOp,
2382                          VK_IMAGE_LAYOUT_UNDEFINED,            // VkImageLayout                initialLayout,
2383                          VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, // VkImageLayout                finalLayout,
2384                          VkClearValue());                      // VkClearValue                    clearValue,
2385 
2386         rt.addSubpassColorAttachmentWithResolve(0u, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, 1u,
2387                                                 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
2388 
2389         if (useDepth() || useStencil())
2390         {
2391             rt.addAttachment(
2392                 *m_depthStencilImage,                             // VkImage                        image
2393                 *m_depthStencilImageView,                         // VkImageView                    imageView,
2394                 (VkAttachmentDescriptionFlags)0,                  // VkAttachmentDescriptionFlags    flags,
2395                 m_depthStencilFormat,                             // VkFormat                        format,
2396                 m_params.numSamples,                              // VkSampleCountFlagBits        numSamples,
2397                 VK_ATTACHMENT_LOAD_OP_CLEAR,                      // VkAttachmentLoadOp            loadOp,
2398                 VK_ATTACHMENT_STORE_OP_STORE,                     // VkAttachmentStoreOp            storeOp,
2399                 VK_ATTACHMENT_LOAD_OP_CLEAR,                      // VkAttachmentLoadOp            stencilLoadOp,
2400                 VK_ATTACHMENT_STORE_OP_STORE,                     // VkAttachmentStoreOp            stencilStoreOp,
2401                 VK_IMAGE_LAYOUT_UNDEFINED,                        // VkImageLayout                initialLayout,
2402                 VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, // VkImageLayout                finalLayout,
2403                 makeClearValueDepthStencil(DEPTH_CLEAR,
2404                                            STENCIL_REFERENCE), // VkClearValue                    clearValue,
2405                 &sampleLocationsInfo);                         // VkSampleLocationsInfoEXT*    pInitialSampleLocations
2406 
2407             rt.addSubpassDepthStencilAttachment(2u, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
2408                                                 &sampleLocationsInfo);
2409         }
2410 
2411         rt.bake(vk, device, m_params.pipelineConstructionType, m_renderSize);
2412 
2413         GraphicsPipelineWrapper pipeline(vki, vk, physicalDevice, device, m_context.getDeviceExtensions(),
2414                                          m_params.pipelineConstructionType);
2415         preparePipelineWrapper(
2416             pipeline, std::vector<VkDynamicState>(), pipelineLayout, rt.getRenderPass(), vertexModule, fragmentModule,
2417             /*subpass index*/ 0u, viewport, scissor, m_params.numSamples, /*use sample locations*/ true,
2418             sampleLocationsInfo, useDepth(), useStencil(), VERTEX_INPUT_VEC4_VEC4, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
2419             stencilOpStateDrawOnce(), useFragmentShadingRate());
2420 
2421         const Unique<VkCommandPool> cmdPool(createCommandPool(
2422             vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, m_context.getUniversalQueueFamilyIndex()));
2423         const Unique<VkCommandBuffer> cmdBuffer(makeCommandBuffer(vk, device, *cmdPool));
2424         Move<VkCommandBuffer> secondaryCmdBuffer;
2425         VkCommandBuffer currentCmdBuffer = *cmdBuffer;
2426 
2427         beginCommandBuffer(vk, currentCmdBuffer);
2428         rt.recordBeginRenderPass(
2429             vk, currentCmdBuffer, renderArea,
2430             (useSecondaryCmdBuffer() ? VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS : VK_SUBPASS_CONTENTS_INLINE));
2431 
2432         // For maximum consistency also use a secondary command buffer, if the two-pass path uses it
2433         if (useSecondaryCmdBuffer())
2434         {
2435             secondaryCmdBuffer = allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_SECONDARY);
2436             currentCmdBuffer   = *secondaryCmdBuffer;
2437 
2438             beginSecondaryCommandBuffer(vk, currentCmdBuffer, rt.getRenderPassWrapper(), /*subpass*/ 0u,
2439                                         m_params.numSamples, m_params.pipelineConstructionType);
2440         }
2441 
2442         vk.cmdBindVertexBuffers(currentCmdBuffer, /*first binding*/ 0u, /*num bindings*/ 1u, &m_vertexBuffer.get(),
2443                                 /*offsets*/ &ZERO);
2444         pipeline.bind(currentCmdBuffer);
2445 
2446         // Draw the right shape only
2447         vk.cmdDraw(currentCmdBuffer, m_numVertices, /*instance count*/ 1u, /*first vertex*/ 0u, /*first instance*/ 1u);
2448 
2449         if (useSecondaryCmdBuffer())
2450         {
2451             endCommandBuffer(vk, currentCmdBuffer);
2452             currentCmdBuffer = *cmdBuffer;
2453 
2454             vk.cmdExecuteCommands(currentCmdBuffer, 1u, &secondaryCmdBuffer.get());
2455         }
2456 
2457         rt.endRenderPass(vk, *cmdBuffer);
2458 
2459         recordCopyImageToBuffer(vk, *cmdBuffer, m_renderSize, *m_resolveImage, *m_colorBuffer);
2460 
2461         endCommandBuffer(vk, *cmdBuffer);
2462         submitCommandsAndWait(vk, device, m_context.getUniversalQueue(), *cmdBuffer);
2463 
2464         invalidateAlloc(vk, device, *m_colorBufferAlloc);
2465     }
2466 
2467     //! Draw two shapes with distinct sample patterns, each in its own render pass
drawRenderPasses(void)2468     void drawRenderPasses(void)
2469     {
2470         const InstanceInterface &vki          = m_context.getInstanceInterface();
2471         const DeviceInterface &vk             = m_context.getDeviceInterface();
2472         const VkPhysicalDevice physicalDevice = m_context.getPhysicalDevice();
2473         const VkDevice device                 = m_context.getDevice();
2474         const VkViewport viewport             = makeViewport(m_renderSize);
2475         const VkRect2D renderArea             = makeRect2D(m_renderSize);
2476         const VkRect2D scissor                = makeRect2D(m_renderSize);
2477         const ShaderWrapper vertexModule(ShaderWrapper(vk, device, m_context.getBinaryCollection().get("vert"), 0u));
2478         const ShaderWrapper fragmentModule(ShaderWrapper(vk, device, m_context.getBinaryCollection().get("frag"), 0u));
2479         const PipelineLayoutWrapper pipelineLayout(m_params.pipelineConstructionType, vk, device);
2480         const VkClearValue clearColor0        = makeClearValueColor(CLEAR_COLOR_0);
2481         const VkClearValue clearColor1        = makeClearValueColor(CLEAR_COLOR_1);
2482         const VkClearValue clearDepthStencil0 = makeClearValueDepthStencil(DEPTH_CLEAR, STENCIL_REFERENCE);
2483         const VkSampleLocationsInfoEXT sampleLocationsInfo[NUM_PASSES] = {
2484             makeSampleLocationsInfo(m_pixelGrids[0]),
2485             makeSampleLocationsInfo(m_pixelGrids[useSameSamplePattern() ? 0 : 1]),
2486         };
2487         const Unique<VkCommandPool> cmdPool(createCommandPool(
2488             vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, m_context.getUniversalQueueFamilyIndex()));
2489         Move<VkCommandBuffer> cmdBuffer[NUM_PASSES] = {
2490             makeCommandBuffer(vk, device, *cmdPool),
2491             makeCommandBuffer(vk, device, *cmdPool),
2492         };
2493         Move<VkCommandBuffer> secondaryCmdBuffer[NUM_PASSES];
2494         RenderTarget rt[NUM_PASSES];
2495         std::vector<GraphicsPipelineWrapper> pipelines;
2496         Move<VkEvent> event[2]; /*color and depth/stencil*/
2497 
2498         // Layouts expected by the second render pass
2499         const VkImageLayout colorLayout1        = useGeneralLayout() && !(useDepth() || useStencil()) ?
2500                                                       VK_IMAGE_LAYOUT_GENERAL :
2501                                                       VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
2502         const VkImageLayout depthStencilLayout1 = useGeneralLayout() && (useDepth() || useStencil()) ?
2503                                                       VK_IMAGE_LAYOUT_GENERAL :
2504                                                       VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
2505 
2506         // First render pass - no resolves
2507         {
2508             rt[0].addAttachment(*m_colorImage,                    // VkImage                        image
2509                                 *m_colorImageView,                // VkImageView                    imageView,
2510                                 (VkAttachmentDescriptionFlags)0,  // VkAttachmentDescriptionFlags    flags,
2511                                 m_colorFormat,                    // VkFormat                        format,
2512                                 m_params.numSamples,              // VkSampleCountFlagBits        numSamples,
2513                                 VK_ATTACHMENT_LOAD_OP_CLEAR,      // VkAttachmentLoadOp            loadOp,
2514                                 VK_ATTACHMENT_STORE_OP_STORE,     // VkAttachmentStoreOp            storeOp,
2515                                 VK_ATTACHMENT_LOAD_OP_DONT_CARE,  // VkAttachmentLoadOp            stencilLoadOp,
2516                                 VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp            stencilStoreOp,
2517                                 VK_IMAGE_LAYOUT_UNDEFINED,        // VkImageLayout                initialLayout,
2518                                 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout                finalLayout,
2519                                 clearColor0);                             // VkClearValue                    clearValue,
2520 
2521             rt[0].addSubpassColorAttachment(0u, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
2522 
2523             if (useDepth() || useStencil())
2524             {
2525                 rt[0].addAttachment(
2526                     *m_depthStencilImage,                             // VkImage                        image
2527                     *m_depthStencilImageView,                         // VkImageView                    imageView,
2528                     (VkAttachmentDescriptionFlags)0,                  // VkAttachmentDescriptionFlags    flags,
2529                     m_depthStencilFormat,                             // VkFormat                        format,
2530                     m_params.numSamples,                              // VkSampleCountFlagBits        numSamples,
2531                     VK_ATTACHMENT_LOAD_OP_CLEAR,                      // VkAttachmentLoadOp            loadOp,
2532                     VK_ATTACHMENT_STORE_OP_STORE,                     // VkAttachmentStoreOp            storeOp,
2533                     VK_ATTACHMENT_LOAD_OP_CLEAR,                      // VkAttachmentLoadOp            stencilLoadOp,
2534                     VK_ATTACHMENT_STORE_OP_STORE,                     // VkAttachmentStoreOp            stencilStoreOp,
2535                     VK_IMAGE_LAYOUT_UNDEFINED,                        // VkImageLayout                initialLayout,
2536                     VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, // VkImageLayout                finalLayout,
2537                     clearDepthStencil0,                               // VkClearValue                    clearValue,
2538                     &sampleLocationsInfo[0]); // VkSampleLocationsInfoEXT*    pInitialSampleLocations
2539 
2540                 rt[0].addSubpassDepthStencilAttachment(1u, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
2541                                                        &sampleLocationsInfo[0]);
2542             }
2543 
2544             rt[0].bake(vk, device, m_params.pipelineConstructionType, m_renderSize);
2545         }
2546 
2547         // Second render pass
2548         {
2549             const VkAttachmentLoadOp loadOp =
2550                 (m_params.clears == TEST_CLEARS_LOAD_OP_CLEAR ? VK_ATTACHMENT_LOAD_OP_CLEAR :
2551                                                                 VK_ATTACHMENT_LOAD_OP_LOAD);
2552 
2553             rt[1].addAttachment(*m_colorImage,                    // VkImage                        image
2554                                 *m_colorImageView,                // VkImageView                    imageView,
2555                                 (VkAttachmentDescriptionFlags)0,  // VkAttachmentDescriptionFlags    flags,
2556                                 m_colorFormat,                    // VkFormat                        format,
2557                                 m_params.numSamples,              // VkSampleCountFlagBits        numSamples,
2558                                 loadOp,                           // VkAttachmentLoadOp            loadOp,
2559                                 VK_ATTACHMENT_STORE_OP_STORE,     // VkAttachmentStoreOp            storeOp,
2560                                 VK_ATTACHMENT_LOAD_OP_DONT_CARE,  // VkAttachmentLoadOp            stencilLoadOp,
2561                                 VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp            stencilStoreOp,
2562                                 colorLayout1,                     // VkImageLayout                initialLayout,
2563                                 colorLayout1,                     // VkImageLayout                finalLayout,
2564                                 clearColor1);                     // VkClearValue                    clearValue,
2565 
2566             rt[1].addAttachment(*m_resolveImage,                      // VkImage                        image
2567                                 *m_resolveImageView,                  // VkImageView                    imageView,
2568                                 (VkAttachmentDescriptionFlags)0,      // VkAttachmentDescriptionFlags    flags,
2569                                 m_colorFormat,                        // VkFormat                        format,
2570                                 VK_SAMPLE_COUNT_1_BIT,                // VkSampleCountFlagBits        numSamples,
2571                                 VK_ATTACHMENT_LOAD_OP_DONT_CARE,      // VkAttachmentLoadOp            loadOp,
2572                                 VK_ATTACHMENT_STORE_OP_STORE,         // VkAttachmentStoreOp            storeOp,
2573                                 VK_ATTACHMENT_LOAD_OP_DONT_CARE,      // VkAttachmentLoadOp            stencilLoadOp,
2574                                 VK_ATTACHMENT_STORE_OP_DONT_CARE,     // VkAttachmentStoreOp            stencilStoreOp,
2575                                 VK_IMAGE_LAYOUT_UNDEFINED,            // VkImageLayout                initialLayout,
2576                                 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, // VkImageLayout                finalLayout,
2577                                 VkClearValue());                      // VkClearValue                    clearValue,
2578 
2579             rt[1].addSubpassColorAttachmentWithResolve(0u, colorLayout1, 1u, colorLayout1);
2580 
2581             if (useDepth() || useStencil())
2582             {
2583                 rt[1].addAttachment(*m_depthStencilImage,            // VkImage                        image
2584                                     *m_depthStencilImageView,        // VkImageView                    imageView,
2585                                     (VkAttachmentDescriptionFlags)0, // VkAttachmentDescriptionFlags    flags,
2586                                     m_depthStencilFormat,            // VkFormat                        format,
2587                                     m_params.numSamples,             // VkSampleCountFlagBits        numSamples,
2588                                     loadOp,                          // VkAttachmentLoadOp            loadOp,
2589                                     VK_ATTACHMENT_STORE_OP_STORE,    // VkAttachmentStoreOp            storeOp,
2590                                     loadOp,                          // VkAttachmentLoadOp            stencilLoadOp,
2591                                     VK_ATTACHMENT_STORE_OP_STORE,    // VkAttachmentStoreOp            stencilStoreOp,
2592                                     depthStencilLayout1,             // VkImageLayout                initialLayout,
2593                                     depthStencilLayout1,             // VkImageLayout                finalLayout,
2594                                     clearDepthStencil0,              // VkClearValue                    clearValue,
2595                                     &sampleLocationsInfo[1]); // VkSampleLocationsInfoEXT*    pInitialSampleLocations
2596 
2597                 rt[1].addSubpassDepthStencilAttachment(2u, depthStencilLayout1, &sampleLocationsInfo[1]);
2598             }
2599 
2600             rt[1].bake(vk, device, m_params.pipelineConstructionType, m_renderSize);
2601         }
2602 
2603         // Pipelines
2604         pipelines.reserve(NUM_PASSES);
2605         if (useDynamicState())
2606         {
2607             std::vector<VkDynamicState> dynamicState;
2608             dynamicState.push_back(VK_DYNAMIC_STATE_SAMPLE_LOCATIONS_EXT);
2609 
2610             for (uint32_t passNdx = 0; passNdx < NUM_PASSES; ++passNdx)
2611             {
2612                 pipelines.emplace_back(vki, vk, physicalDevice, device, m_context.getDeviceExtensions(),
2613                                        m_params.pipelineConstructionType);
2614                 preparePipelineWrapper(pipelines.back(), dynamicState, pipelineLayout, rt[passNdx].getRenderPass(),
2615                                        vertexModule, fragmentModule,
2616                                        /*subpass index*/ 0u, viewport, scissor, m_params.numSamples,
2617                                        /*use sample locations*/ true, makeEmptySampleLocationsInfo(), useDepth(),
2618                                        useStencil(), VERTEX_INPUT_VEC4_VEC4, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
2619                                        stencilOpStateDrawOnce(), useFragmentShadingRate());
2620             }
2621         }
2622         else
2623             for (uint32_t passNdx = 0; passNdx < NUM_PASSES; ++passNdx)
2624             {
2625                 pipelines.emplace_back(vki, vk, physicalDevice, device, m_context.getDeviceExtensions(),
2626                                        m_params.pipelineConstructionType);
2627                 preparePipelineWrapper(pipelines.back(), std::vector<VkDynamicState>(), pipelineLayout,
2628                                        rt[passNdx].getRenderPass(), vertexModule, fragmentModule,
2629                                        /*subpass index*/ 0u, viewport, scissor, m_params.numSamples,
2630                                        /*use sample locations*/ true, sampleLocationsInfo[passNdx], useDepth(),
2631                                        useStencil(), VERTEX_INPUT_VEC4_VEC4, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
2632                                        stencilOpStateDrawOnce(), useFragmentShadingRate());
2633             }
2634 
2635         // Record secondary command buffers
2636 
2637         if (useSecondaryCmdBuffer())
2638         {
2639             secondaryCmdBuffer[0] = allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_SECONDARY);
2640             secondaryCmdBuffer[1] = allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_SECONDARY);
2641 
2642             // First render pass contents
2643             beginSecondaryCommandBuffer(vk, *secondaryCmdBuffer[0], rt[0].getRenderPassWrapper(), /*subpass*/ 0u,
2644                                         m_params.numSamples, m_params.pipelineConstructionType);
2645             recordFirstPassContents(*secondaryCmdBuffer[0], pipelines[0], sampleLocationsInfo[0]);
2646             endCommandBuffer(vk, *secondaryCmdBuffer[0]);
2647 
2648             // Second render pass contents
2649             beginSecondaryCommandBuffer(vk, *secondaryCmdBuffer[1], rt[1].getRenderPassWrapper(), /*subpass*/ 0u,
2650                                         m_params.numSamples, m_params.pipelineConstructionType);
2651             recordSecondPassContents(*secondaryCmdBuffer[1], pipelines[1], sampleLocationsInfo[1], clearColor1,
2652                                      clearDepthStencil0, scissor);
2653             endCommandBuffer(vk, *secondaryCmdBuffer[1]);
2654         }
2655 
2656         // Record primary command buffers
2657 
2658         VkCommandBuffer currentCmdBuffer = *cmdBuffer[0];
2659         beginCommandBuffer(vk, currentCmdBuffer);
2660 
2661         // First render pass
2662         if (useSecondaryCmdBuffer())
2663         {
2664             rt[0].recordBeginRenderPass(vk, currentCmdBuffer, renderArea,
2665                                         VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS);
2666             vk.cmdExecuteCommands(currentCmdBuffer, 1u, &secondaryCmdBuffer[0].get());
2667             rt[0].endRenderPass(vk, currentCmdBuffer);
2668         }
2669         else
2670         {
2671             rt[0].recordBeginRenderPass(vk, currentCmdBuffer, renderArea, VK_SUBPASS_CONTENTS_INLINE);
2672             recordFirstPassContents(currentCmdBuffer, pipelines[0], sampleLocationsInfo[0]);
2673             rt[0].endRenderPass(vk, currentCmdBuffer);
2674         }
2675 
2676         endCommandBuffer(vk, currentCmdBuffer);
2677 
2678         // Record the second primary command buffer
2679         currentCmdBuffer = *cmdBuffer[1];
2680         beginCommandBuffer(vk, currentCmdBuffer);
2681 
2682         if (m_params.clears == TEST_CLEARS_CMD_CLEAR_IMAGE)
2683         {
2684             {
2685                 const VkImageLayout finalLayout =
2686                     (useWaitEvents() ? VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL : colorLayout1);
2687 
2688                 recordImageBarrier(vk, currentCmdBuffer, *m_colorImage,
2689                                    VK_IMAGE_ASPECT_COLOR_BIT,                     // VkImageAspectFlags    aspect,
2690                                    VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, // VkPipelineStageFlags srcStageMask,
2691                                    VK_PIPELINE_STAGE_TRANSFER_BIT,                // VkPipelineStageFlags dstStageMask,
2692                                    VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,          // VkAccessFlags        srcAccessMask,
2693                                    VK_ACCESS_TRANSFER_WRITE_BIT,                  // VkAccessFlags        dstAccessMask,
2694                                    VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,      // VkImageLayout        oldLayout,
2695                                    VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);         // VkImageLayout        newLayout)
2696 
2697                 const VkImageSubresourceRange subresourceRange =
2698                     makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
2699                 vk.cmdClearColorImage(currentCmdBuffer, *m_colorImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
2700                                       &clearColor1.color, 1u, &subresourceRange);
2701 
2702                 recordImageBarrier(vk, currentCmdBuffer, *m_colorImage,
2703                                    VK_IMAGE_ASPECT_COLOR_BIT,                     // VkImageAspectFlags    aspect,
2704                                    VK_PIPELINE_STAGE_TRANSFER_BIT,                // VkPipelineStageFlags srcStageMask,
2705                                    VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, // VkPipelineStageFlags dstStageMask,
2706                                    VK_ACCESS_TRANSFER_WRITE_BIT,                  // VkAccessFlags        srcAccessMask,
2707                                    (VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
2708                                     VK_ACCESS_COLOR_ATTACHMENT_READ_BIT), // VkAccessFlags        dstAccessMask,
2709                                    VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,  // VkImageLayout        oldLayout,
2710                                    finalLayout);                          // VkImageLayout        newLayout)
2711             }
2712 
2713             if (useDepth() || useStencil())
2714             {
2715                 const VkImageLayout finalLayout =
2716                     (useWaitEvents() ? VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL : depthStencilLayout1);
2717 
2718                 recordImageBarrier(vk, currentCmdBuffer, *m_depthStencilImage,
2719                                    getImageAspectFlags(m_depthStencilFormat),    // VkImageAspectFlags    aspect,
2720                                    VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,    // VkPipelineStageFlags srcStageMask,
2721                                    VK_PIPELINE_STAGE_TRANSFER_BIT,               // VkPipelineStageFlags dstStageMask,
2722                                    VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, // VkAccessFlags        srcAccessMask,
2723                                    VK_ACCESS_TRANSFER_WRITE_BIT,                 // VkAccessFlags        dstAccessMask,
2724                                    VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, // VkImageLayout        oldLayout,
2725                                    VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,             // VkImageLayout        newLayout)
2726                                    &sampleLocationsInfo[0]);                         // VkSampleLocationsInfoEXT
2727 
2728                 const VkImageSubresourceRange subresourceRange =
2729                     makeImageSubresourceRange(m_depthStencilAspect, 0u, 1u, 0u, 1u);
2730                 vk.cmdClearDepthStencilImage(currentCmdBuffer, *m_depthStencilImage,
2731                                              VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &clearDepthStencil0.depthStencil, 1u,
2732                                              &subresourceRange);
2733 
2734                 recordImageBarrier(vk, currentCmdBuffer, *m_depthStencilImage,
2735                                    getImageAspectFlags(m_depthStencilFormat),  // VkImageAspectFlags    aspect,
2736                                    VK_PIPELINE_STAGE_TRANSFER_BIT,             // VkPipelineStageFlags srcStageMask,
2737                                    VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT, // VkPipelineStageFlags dstStageMask,
2738                                    VK_ACCESS_TRANSFER_WRITE_BIT,               // VkAccessFlags        srcAccessMask,
2739                                    (VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT |
2740                                     VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT), // VkAccessFlags        dstAccessMask,
2741                                    VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,          // VkImageLayout        oldLayout,
2742                                    finalLayout,                                   // VkImageLayout        newLayout)
2743                                    &sampleLocationsInfo[0]);                      // VkSampleLocationsInfoEXT
2744             }
2745         }
2746         else if (!useWaitEvents())
2747         {
2748             // Barrier between the render passes
2749 
2750             recordImageBarrier(vk, currentCmdBuffer, *m_colorImage,
2751                                VK_IMAGE_ASPECT_COLOR_BIT,                     // VkImageAspectFlags    aspect,
2752                                VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, // VkPipelineStageFlags srcStageMask,
2753                                VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, // VkPipelineStageFlags dstStageMask,
2754                                VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,          // VkAccessFlags        srcAccessMask,
2755                                (VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
2756                                 VK_ACCESS_COLOR_ATTACHMENT_READ_BIT),    // VkAccessFlags        dstAccessMask,
2757                                VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout        oldLayout,
2758                                colorLayout1);                            // VkImageLayout        newLayout)
2759 
2760             if (useDepth() || useStencil())
2761             {
2762                 recordImageBarrier(vk, currentCmdBuffer, *m_depthStencilImage,
2763                                    getImageAspectFlags(m_depthStencilFormat),    // VkImageAspectFlags    aspect,
2764                                    VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,    // VkPipelineStageFlags srcStageMask,
2765                                    VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT,   // VkPipelineStageFlags dstStageMask,
2766                                    VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, // VkAccessFlags        srcAccessMask,
2767                                    (VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT |
2768                                     VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT), // VkAccessFlags        dstAccessMask,
2769                                    VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, // VkImageLayout        oldLayout,
2770                                    depthStencilLayout1);                             // VkImageLayout        newLayout)
2771             }
2772         }
2773 
2774         if (useWaitEvents())
2775         {
2776             // Use events to sync both render passes
2777             event[0] = makeEvent(vk, device);
2778             vk.cmdSetEvent(currentCmdBuffer, *event[0], VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);
2779 
2780             recordWaitEventWithImage(
2781                 vk, currentCmdBuffer, *event[0], *m_colorImage,
2782                 VK_IMAGE_ASPECT_COLOR_BIT,                     // VkImageAspectFlags        aspect,
2783                 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, // VkPipelineStageFlags        srcStageMask,
2784                 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, // VkPipelineStageFlags        dstStageMask,
2785                 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,          // VkAccessFlags            srcAccessMask,
2786                 (VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
2787                  VK_ACCESS_COLOR_ATTACHMENT_READ_BIT),    // VkAccessFlags            dstAccessMask,
2788                 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout            oldLayout,
2789                 colorLayout1);                            // VkImageLayout            newLayout,
2790 
2791             if (useDepth() || useStencil())
2792             {
2793                 event[1] = makeEvent(vk, device);
2794                 vk.cmdSetEvent(currentCmdBuffer, *event[1], VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT);
2795 
2796                 recordWaitEventWithImage(
2797                     vk, currentCmdBuffer, *event[1], *m_depthStencilImage,
2798                     getImageAspectFlags(m_depthStencilFormat),    // VkImageAspectFlags        aspect,
2799                     VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,    // VkPipelineStageFlags        srcStageMask,
2800                     VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT,   // VkPipelineStageFlags        dstStageMask,
2801                     VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, // VkAccessFlags            srcAccessMask,
2802                     (VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT |
2803                      VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT),    // VkAccessFlags            dstAccessMask,
2804                     VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, // VkImageLayout            oldLayout,
2805                     depthStencilLayout1);                             // VkImageLayout            newLayout,
2806             }
2807         }
2808 
2809         // Second render pass
2810         if (useSecondaryCmdBuffer())
2811         {
2812             rt[1].recordBeginRenderPass(vk, currentCmdBuffer, renderArea,
2813                                         VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS);
2814             vk.cmdExecuteCommands(currentCmdBuffer, 1u, &secondaryCmdBuffer[1].get());
2815             rt[1].endRenderPass(vk, currentCmdBuffer);
2816         }
2817         else
2818         {
2819             rt[1].recordBeginRenderPass(vk, currentCmdBuffer, renderArea, VK_SUBPASS_CONTENTS_INLINE);
2820             recordSecondPassContents(currentCmdBuffer, pipelines[1], sampleLocationsInfo[1], clearColor1,
2821                                      clearDepthStencil0, scissor);
2822             rt[1].endRenderPass(vk, currentCmdBuffer);
2823         }
2824 
2825         // Resolve image -> host buffer
2826         recordCopyImageToBuffer(vk, currentCmdBuffer, m_renderSize, *m_resolveImage, *m_colorBuffer);
2827 
2828         endCommandBuffer(vk, currentCmdBuffer);
2829 
2830         // Submit work
2831         {
2832             const Unique<VkFence> fence(createFence(vk, device));
2833             const VkCommandBuffer buffers[NUM_PASSES] = {
2834                 *cmdBuffer[0],
2835                 *cmdBuffer[1],
2836             };
2837 
2838             const VkSubmitInfo submitInfo = {
2839                 VK_STRUCTURE_TYPE_SUBMIT_INFO, // VkStructureType                sType;
2840                 DE_NULL,                       // const void*                    pNext;
2841                 0u,                            // uint32_t                       waitSemaphoreCount;
2842                 DE_NULL,                       // const VkSemaphore*             pWaitSemaphores;
2843                 DE_NULL,                       // const VkPipelineStageFlags*    pWaitDstStageMask;
2844                 DE_LENGTH_OF_ARRAY(buffers),   // uint32_t                       commandBufferCount;
2845                 buffers,                       // const VkCommandBuffer*         pCommandBuffers;
2846                 0u,                            // uint32_t                       signalSemaphoreCount;
2847                 DE_NULL,                       // const VkSemaphore*             pSignalSemaphores;
2848             };
2849             VK_CHECK(vk.queueSubmit(m_context.getUniversalQueue(), 1u, &submitInfo, *fence));
2850             VK_CHECK(vk.waitForFences(device, 1u, &fence.get(), true, ~0ull));
2851         }
2852 
2853         invalidateAlloc(vk, device, *m_colorBufferAlloc);
2854     }
2855 
recordFirstPassContents(const VkCommandBuffer cmdBuffer,const GraphicsPipelineWrapper & pipeline,const VkSampleLocationsInfoEXT & sampleLocationsInfo)2856     void recordFirstPassContents(const VkCommandBuffer cmdBuffer, const GraphicsPipelineWrapper &pipeline,
2857                                  const VkSampleLocationsInfoEXT &sampleLocationsInfo)
2858     {
2859         const DeviceInterface &vk = m_context.getDeviceInterface();
2860 
2861         vk.cmdBindVertexBuffers(cmdBuffer, /*first binding*/ 0u, /*num bindings*/ 1u, &m_vertexBuffer.get(),
2862                                 /*offsets*/ &ZERO);
2863         pipeline.bind(cmdBuffer);
2864 
2865         if (useDynamicState())
2866             vk.cmdSetSampleLocationsEXT(cmdBuffer, &sampleLocationsInfo);
2867 
2868         if (m_params.clears == TEST_CLEARS_NO_CLEAR)
2869             vk.cmdDraw(cmdBuffer, m_numVertices, /*instance count*/ 1u, /*first vertex*/ 0u,
2870                        /*first instance*/ 0u); // left shape only
2871         else
2872             vk.cmdDraw(cmdBuffer, m_numVertices, /*instance count*/ NUM_PASSES, /*first vertex*/ 0u,
2873                        /*first instance*/ 0u); // both shapes
2874     }
2875 
recordSecondPassContents(const VkCommandBuffer cmdBuffer,const GraphicsPipelineWrapper & pipeline,const VkSampleLocationsInfoEXT & sampleLocationsInfo,const VkClearValue & clearColor,const VkClearValue & clearDepthStencil,const VkRect2D & clearRect)2876     void recordSecondPassContents(const VkCommandBuffer cmdBuffer, const GraphicsPipelineWrapper &pipeline,
2877                                   const VkSampleLocationsInfoEXT &sampleLocationsInfo, const VkClearValue &clearColor,
2878                                   const VkClearValue &clearDepthStencil, const VkRect2D &clearRect)
2879     {
2880         const DeviceInterface &vk = m_context.getDeviceInterface();
2881 
2882         vk.cmdBindVertexBuffers(cmdBuffer, /*first binding*/ 0u, /*num bindings*/ 1u, &m_vertexBuffer.get(),
2883                                 /*offsets*/ &ZERO);
2884         pipeline.bind(cmdBuffer);
2885 
2886         if (m_params.clears == TEST_CLEARS_CMD_CLEAR_ATTACHMENTS)
2887             recordClearAttachments(vk, cmdBuffer, 0u, clearColor, m_depthStencilAspect, clearDepthStencil, clearRect);
2888 
2889         if (useDynamicState())
2890             vk.cmdSetSampleLocationsEXT(cmdBuffer, &sampleLocationsInfo);
2891 
2892         // Draw the right shape only
2893         vk.cmdDraw(cmdBuffer, m_numVertices, /*instance count*/ 1u, /*first vertex*/ 0u, /*first instance*/ 1u);
2894     }
2895 
2896     //! Draw two shapes in two subpasses of the same render pass
drawSubpasses(void)2897     void drawSubpasses(void)
2898     {
2899         DE_ASSERT(m_params.clears != TEST_CLEARS_CMD_CLEAR_IMAGE);        // not possible in a render pass
2900         DE_ASSERT(m_params.clears != TEST_CLEARS_LOAD_OP_CLEAR);          // can't specify a load op for a subpass
2901         DE_ASSERT((m_params.options & TEST_OPTION_WAIT_EVENTS_BIT) == 0); // can't change layouts inside a subpass
2902 
2903         const InstanceInterface &vki          = m_context.getInstanceInterface();
2904         const DeviceInterface &vk             = m_context.getDeviceInterface();
2905         const VkPhysicalDevice physicalDevice = m_context.getPhysicalDevice();
2906         const VkDevice device                 = m_context.getDevice();
2907         const VkViewport viewport             = makeViewport(m_renderSize);
2908         const VkRect2D renderArea             = makeRect2D(m_renderSize);
2909         const VkRect2D scissor                = makeRect2D(m_renderSize);
2910         const ShaderWrapper vertexModule(ShaderWrapper(vk, device, m_context.getBinaryCollection().get("vert"), 0u));
2911         const ShaderWrapper fragmentModule(ShaderWrapper(vk, device, m_context.getBinaryCollection().get("frag"), 0u));
2912         const PipelineLayoutWrapper pipelineLayout(m_params.pipelineConstructionType, vk, device);
2913         const VkClearValue clearColor0        = makeClearValueColor(CLEAR_COLOR_0);
2914         const VkClearValue clearColor1        = makeClearValueColor(CLEAR_COLOR_1);
2915         const VkClearValue clearDepthStencil0 = makeClearValueDepthStencil(DEPTH_CLEAR, STENCIL_REFERENCE);
2916         const VkSampleLocationsInfoEXT sampleLocationsInfo[NUM_PASSES] = {
2917             makeSampleLocationsInfo(m_pixelGrids[0]),
2918             makeSampleLocationsInfo(m_pixelGrids[useSameSamplePattern() ? 0 : 1]),
2919         };
2920         const Unique<VkCommandPool> cmdPool(createCommandPool(
2921             vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, m_context.getUniversalQueueFamilyIndex()));
2922         const Unique<VkCommandBuffer> cmdBuffer(makeCommandBuffer(vk, device, *cmdPool));
2923         Move<VkCommandBuffer> secondaryCmdBuffer[NUM_PASSES];
2924         RenderTarget rt;
2925         std::vector<GraphicsPipelineWrapper> pipelines;
2926         Move<VkEvent> event;
2927 
2928         // Layouts used in the second subpass
2929         const VkImageLayout colorLayout1        = useGeneralLayout() && !(useDepth() || useStencil()) ?
2930                                                       VK_IMAGE_LAYOUT_GENERAL :
2931                                                       VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
2932         const VkImageLayout depthStencilLayout1 = useGeneralLayout() && (useDepth() || useStencil()) ?
2933                                                       VK_IMAGE_LAYOUT_GENERAL :
2934                                                       VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
2935 
2936         // Prepare the render pass
2937         {
2938             rt.addAttachment(*m_colorImage,                            // VkImage                        image
2939                              *m_colorImageView,                        // VkImageView                    imageView,
2940                              (VkAttachmentDescriptionFlags)0,          // VkAttachmentDescriptionFlags    flags,
2941                              m_colorFormat,                            // VkFormat                        format,
2942                              m_params.numSamples,                      // VkSampleCountFlagBits        numSamples,
2943                              VK_ATTACHMENT_LOAD_OP_CLEAR,              // VkAttachmentLoadOp            loadOp,
2944                              VK_ATTACHMENT_STORE_OP_STORE,             // VkAttachmentStoreOp            storeOp,
2945                              VK_ATTACHMENT_LOAD_OP_DONT_CARE,          // VkAttachmentLoadOp            stencilLoadOp,
2946                              VK_ATTACHMENT_STORE_OP_DONT_CARE,         // VkAttachmentStoreOp            stencilStoreOp,
2947                              VK_IMAGE_LAYOUT_UNDEFINED,                // VkImageLayout                initialLayout,
2948                              VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout                finalLayout,
2949                              clearColor0);                             // VkClearValue                    clearValue,
2950 
2951             rt.addAttachment(*m_resolveImage,                      // VkImage                        image
2952                              *m_resolveImageView,                  // VkImageView                    imageView,
2953                              (VkAttachmentDescriptionFlags)0,      // VkAttachmentDescriptionFlags    flags,
2954                              m_colorFormat,                        // VkFormat                        format,
2955                              VK_SAMPLE_COUNT_1_BIT,                // VkSampleCountFlagBits        numSamples,
2956                              VK_ATTACHMENT_LOAD_OP_DONT_CARE,      // VkAttachmentLoadOp            loadOp,
2957                              VK_ATTACHMENT_STORE_OP_STORE,         // VkAttachmentStoreOp            storeOp,
2958                              VK_ATTACHMENT_LOAD_OP_DONT_CARE,      // VkAttachmentLoadOp            stencilLoadOp,
2959                              VK_ATTACHMENT_STORE_OP_DONT_CARE,     // VkAttachmentStoreOp            stencilStoreOp,
2960                              VK_IMAGE_LAYOUT_UNDEFINED,            // VkImageLayout                initialLayout,
2961                              VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, // VkImageLayout                finalLayout,
2962                              VkClearValue());                      // VkClearValue                    clearValue,
2963 
2964             // First subpass
2965             rt.addSubpassColorAttachment(0u, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
2966 
2967             if (useDepth() || useStencil())
2968             {
2969                 rt.addAttachment(
2970                     *m_depthStencilImage,                             // VkImage                        image
2971                     *m_depthStencilImageView,                         // VkImageView                    imageView,
2972                     (VkAttachmentDescriptionFlags)0,                  // VkAttachmentDescriptionFlags    flags,
2973                     m_depthStencilFormat,                             // VkFormat                        format,
2974                     m_params.numSamples,                              // VkSampleCountFlagBits        numSamples,
2975                     VK_ATTACHMENT_LOAD_OP_CLEAR,                      // VkAttachmentLoadOp            loadOp,
2976                     VK_ATTACHMENT_STORE_OP_STORE,                     // VkAttachmentStoreOp            storeOp,
2977                     VK_ATTACHMENT_LOAD_OP_CLEAR,                      // VkAttachmentLoadOp            stencilLoadOp,
2978                     VK_ATTACHMENT_STORE_OP_STORE,                     // VkAttachmentStoreOp            stencilStoreOp,
2979                     VK_IMAGE_LAYOUT_UNDEFINED,                        // VkImageLayout                initialLayout,
2980                     VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, // VkImageLayout                finalLayout,
2981                     clearDepthStencil0,                               // VkClearValue                    clearValue,
2982                     &sampleLocationsInfo[0]); // VkSampleLocationsInfoEXT*    pInitialSampleLocations
2983 
2984                 rt.addSubpassDepthStencilAttachment(2u, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
2985                                                     &sampleLocationsInfo[0]);
2986             }
2987 
2988             // Second subpass
2989             rt.nextSubpass();
2990             rt.addSubpassColorAttachmentWithResolve(0u, colorLayout1, 1u, colorLayout1);
2991 
2992             if (useDepth() || useStencil())
2993                 rt.addSubpassDepthStencilAttachment(2u, depthStencilLayout1, &sampleLocationsInfo[1]);
2994 
2995             rt.bake(vk, device, m_params.pipelineConstructionType, m_renderSize);
2996         }
2997 
2998         // Pipelines
2999         pipelines.reserve(NUM_PASSES);
3000         if (useDynamicState())
3001         {
3002             std::vector<VkDynamicState> dynamicState;
3003             dynamicState.push_back(VK_DYNAMIC_STATE_SAMPLE_LOCATIONS_EXT);
3004 
3005             for (uint32_t passNdx = 0; passNdx < NUM_PASSES; ++passNdx)
3006             {
3007                 pipelines.emplace_back(vki, vk, physicalDevice, device, m_context.getDeviceExtensions(),
3008                                        m_params.pipelineConstructionType);
3009                 preparePipelineWrapper(
3010                     pipelines.back(), dynamicState, pipelineLayout, rt.getRenderPass(), vertexModule, fragmentModule,
3011                     /*subpass*/ passNdx, viewport, scissor, m_params.numSamples, /*use sample locations*/ true,
3012                     makeEmptySampleLocationsInfo(), useDepth(), useStencil(), VERTEX_INPUT_VEC4_VEC4,
3013                     VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, stencilOpStateDrawOnce(), useFragmentShadingRate());
3014             }
3015         }
3016         else
3017             for (uint32_t passNdx = 0; passNdx < NUM_PASSES; ++passNdx)
3018             {
3019                 pipelines.emplace_back(vki, vk, physicalDevice, device, m_context.getDeviceExtensions(),
3020                                        m_params.pipelineConstructionType);
3021                 preparePipelineWrapper(pipelines.back(), std::vector<VkDynamicState>(), pipelineLayout,
3022                                        rt.getRenderPass(), vertexModule, fragmentModule,
3023                                        /*subpass*/ passNdx, viewport, scissor, m_params.numSamples,
3024                                        /*use sample locations*/ true, sampleLocationsInfo[passNdx], useDepth(),
3025                                        useStencil(), VERTEX_INPUT_VEC4_VEC4, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
3026                                        stencilOpStateDrawOnce(), useFragmentShadingRate());
3027             }
3028 
3029         // Record secondary command buffers
3030 
3031         if (useSecondaryCmdBuffer())
3032         {
3033             secondaryCmdBuffer[0] = allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_SECONDARY);
3034             secondaryCmdBuffer[1] = allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_SECONDARY);
3035 
3036             // First subpass contents
3037             beginSecondaryCommandBuffer(vk, *secondaryCmdBuffer[0], rt.getRenderPassWrapper(), /*subpass*/ 0u,
3038                                         m_params.numSamples, m_params.pipelineConstructionType);
3039             recordFirstPassContents(*secondaryCmdBuffer[0], pipelines[0], sampleLocationsInfo[0]);
3040             endCommandBuffer(vk, *secondaryCmdBuffer[0]);
3041 
3042             // Second subpass contents
3043             beginSecondaryCommandBuffer(vk, *secondaryCmdBuffer[1], rt.getRenderPassWrapper(), /*subpass*/ 1u,
3044                                         m_params.numSamples, m_params.pipelineConstructionType);
3045             recordSecondPassContents(*secondaryCmdBuffer[1], pipelines[1], sampleLocationsInfo[1], clearColor1,
3046                                      clearDepthStencil0, scissor);
3047             endCommandBuffer(vk, *secondaryCmdBuffer[1]);
3048         }
3049 
3050         // Record primary command buffer
3051 
3052         beginCommandBuffer(vk, *cmdBuffer);
3053 
3054         if (useSecondaryCmdBuffer())
3055         {
3056             rt.recordBeginRenderPass(vk, *cmdBuffer, renderArea, VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS);
3057             vk.cmdExecuteCommands(*cmdBuffer, 1u, &secondaryCmdBuffer[0].get());
3058 
3059             rt.nextSubpass(vk, *cmdBuffer, VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS);
3060             vk.cmdExecuteCommands(*cmdBuffer, 1u, &secondaryCmdBuffer[1].get());
3061         }
3062         else
3063         {
3064             rt.recordBeginRenderPass(vk, *cmdBuffer, renderArea, VK_SUBPASS_CONTENTS_INLINE);
3065             recordFirstPassContents(*cmdBuffer, pipelines[0], sampleLocationsInfo[0]);
3066 
3067             rt.nextSubpass(vk, *cmdBuffer, VK_SUBPASS_CONTENTS_INLINE);
3068             recordSecondPassContents(*cmdBuffer, pipelines[1], sampleLocationsInfo[1], clearColor1, clearDepthStencil0,
3069                                      scissor);
3070         }
3071 
3072         rt.endRenderPass(vk, *cmdBuffer);
3073 
3074         // Resolve image -> host buffer
3075         recordCopyImageToBuffer(vk, *cmdBuffer, m_renderSize, *m_resolveImage, *m_colorBuffer);
3076 
3077         endCommandBuffer(vk, *cmdBuffer);
3078 
3079         submitCommandsAndWait(vk, device, m_context.getUniversalQueue(), *cmdBuffer);
3080         invalidateAlloc(vk, device, *m_colorBufferAlloc);
3081     }
3082 
3083     //! Draw two shapes within the same subpass of a renderpass
drawSameSubpass(void)3084     void drawSameSubpass(void)
3085     {
3086         DE_ASSERT(m_params.clears != TEST_CLEARS_CMD_CLEAR_IMAGE);           // not possible in a render pass
3087         DE_ASSERT(m_params.clears != TEST_CLEARS_LOAD_OP_CLEAR);             // can't specify a load op for a subpass
3088         DE_ASSERT((m_params.options & TEST_OPTION_WAIT_EVENTS_BIT) == 0);    // can't change layouts inside a subpass
3089         DE_ASSERT((m_params.options & TEST_OPTION_GENERAL_LAYOUT_BIT) == 0); // can't change layouts inside a subpass
3090 
3091         const InstanceInterface &vki          = m_context.getInstanceInterface();
3092         const DeviceInterface &vk             = m_context.getDeviceInterface();
3093         const VkPhysicalDevice physicalDevice = m_context.getPhysicalDevice();
3094         const VkDevice device                 = m_context.getDevice();
3095         const VkViewport viewport             = makeViewport(m_renderSize);
3096         const VkRect2D renderArea             = makeRect2D(m_renderSize);
3097         const VkRect2D scissor                = makeRect2D(m_renderSize);
3098         const ShaderWrapper vertexModule(ShaderWrapper(vk, device, m_context.getBinaryCollection().get("vert"), 0u));
3099         const ShaderWrapper fragmentModule(ShaderWrapper(vk, device, m_context.getBinaryCollection().get("frag"), 0u));
3100         const PipelineLayoutWrapper pipelineLayout(m_params.pipelineConstructionType, vk, device);
3101         const VkClearValue clearColor0        = makeClearValueColor(CLEAR_COLOR_0);
3102         const VkClearValue clearColor1        = makeClearValueColor(CLEAR_COLOR_1);
3103         const VkClearValue clearDepthStencil0 = makeClearValueDepthStencil(DEPTH_CLEAR, STENCIL_REFERENCE);
3104         const VkSampleLocationsInfoEXT sampleLocationsInfo[NUM_PASSES] = {
3105             makeSampleLocationsInfo(m_pixelGrids[0]),
3106             makeSampleLocationsInfo(m_pixelGrids[useSameSamplePattern() ? 0 : 1]),
3107         };
3108         const bool useFragmentShadingRate(TEST_OPTION_FRAGMENT_SHADING_RATE_BIT & m_params.options);
3109         const Unique<VkCommandPool> cmdPool(createCommandPool(
3110             vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, m_context.getUniversalQueueFamilyIndex()));
3111         const Unique<VkCommandBuffer> cmdBuffer(makeCommandBuffer(vk, device, *cmdPool));
3112         Move<VkCommandBuffer> secondaryCmdBuffer;
3113         RenderTarget rt;
3114         std::vector<GraphicsPipelineWrapper> pipelines;
3115         Move<VkEvent> event;
3116 
3117         // Prepare the render pass
3118         {
3119             rt.addAttachment(*m_colorImage,                            // VkImage                        image
3120                              *m_colorImageView,                        // VkImageView                    imageView,
3121                              (VkAttachmentDescriptionFlags)0,          // VkAttachmentDescriptionFlags    flags,
3122                              m_colorFormat,                            // VkFormat                        format,
3123                              m_params.numSamples,                      // VkSampleCountFlagBits        numSamples,
3124                              VK_ATTACHMENT_LOAD_OP_CLEAR,              // VkAttachmentLoadOp            loadOp,
3125                              VK_ATTACHMENT_STORE_OP_STORE,             // VkAttachmentStoreOp            storeOp,
3126                              VK_ATTACHMENT_LOAD_OP_DONT_CARE,          // VkAttachmentLoadOp            stencilLoadOp,
3127                              VK_ATTACHMENT_STORE_OP_DONT_CARE,         // VkAttachmentStoreOp            stencilStoreOp,
3128                              VK_IMAGE_LAYOUT_UNDEFINED,                // VkImageLayout                initialLayout,
3129                              VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout                finalLayout,
3130                              clearColor0);                             // VkClearValue                    clearValue,
3131 
3132             rt.addAttachment(*m_resolveImage,                      // VkImage                        image
3133                              *m_resolveImageView,                  // VkImageView                    imageView,
3134                              (VkAttachmentDescriptionFlags)0,      // VkAttachmentDescriptionFlags    flags,
3135                              m_colorFormat,                        // VkFormat                        format,
3136                              VK_SAMPLE_COUNT_1_BIT,                // VkSampleCountFlagBits        numSamples,
3137                              VK_ATTACHMENT_LOAD_OP_DONT_CARE,      // VkAttachmentLoadOp            loadOp,
3138                              VK_ATTACHMENT_STORE_OP_STORE,         // VkAttachmentStoreOp            storeOp,
3139                              VK_ATTACHMENT_LOAD_OP_DONT_CARE,      // VkAttachmentLoadOp            stencilLoadOp,
3140                              VK_ATTACHMENT_STORE_OP_DONT_CARE,     // VkAttachmentStoreOp            stencilStoreOp,
3141                              VK_IMAGE_LAYOUT_UNDEFINED,            // VkImageLayout                initialLayout,
3142                              VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, // VkImageLayout                finalLayout,
3143                              VkClearValue());                      // VkClearValue                    clearValue,
3144 
3145             rt.addSubpassColorAttachmentWithResolve(0u, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, 1u,
3146                                                     VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
3147 
3148             if (useDepth() || useStencil())
3149             {
3150                 rt.addAttachment(
3151                     *m_depthStencilImage,                             // VkImage                        image
3152                     *m_depthStencilImageView,                         // VkImageView                    imageView,
3153                     (VkAttachmentDescriptionFlags)0,                  // VkAttachmentDescriptionFlags    flags,
3154                     m_depthStencilFormat,                             // VkFormat                        format,
3155                     m_params.numSamples,                              // VkSampleCountFlagBits        numSamples,
3156                     VK_ATTACHMENT_LOAD_OP_CLEAR,                      // VkAttachmentLoadOp            loadOp,
3157                     VK_ATTACHMENT_STORE_OP_STORE,                     // VkAttachmentStoreOp            storeOp,
3158                     VK_ATTACHMENT_LOAD_OP_CLEAR,                      // VkAttachmentLoadOp            stencilLoadOp,
3159                     VK_ATTACHMENT_STORE_OP_STORE,                     // VkAttachmentStoreOp            stencilStoreOp,
3160                     VK_IMAGE_LAYOUT_UNDEFINED,                        // VkImageLayout                initialLayout,
3161                     VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, // VkImageLayout                finalLayout,
3162                     clearDepthStencil0,                               // VkClearValue                    clearValue,
3163                     &sampleLocationsInfo[0]); // VkSampleLocationsInfoEXT*    pInitialSampleLocations
3164 
3165                 rt.addSubpassDepthStencilAttachment(2u, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
3166                                                     &sampleLocationsInfo[0]);
3167             }
3168 
3169             rt.bake(vk, device, m_params.pipelineConstructionType, m_renderSize);
3170         }
3171 
3172         // Pipelines
3173         pipelines.reserve(NUM_PASSES);
3174         if (useDynamicState())
3175         {
3176             std::vector<VkDynamicState> dynamicState;
3177             dynamicState.push_back(VK_DYNAMIC_STATE_SAMPLE_LOCATIONS_EXT);
3178 
3179             for (uint32_t passNdx = 0; passNdx < NUM_PASSES; ++passNdx)
3180             {
3181                 pipelines.emplace_back(vki, vk, physicalDevice, device, m_context.getDeviceExtensions(),
3182                                        m_params.pipelineConstructionType);
3183                 preparePipelineWrapper(
3184                     pipelines.back(), dynamicState, pipelineLayout, rt.getRenderPass(), vertexModule, fragmentModule,
3185                     /*subpass*/ 0u, viewport, scissor, m_params.numSamples, /*use sample locations*/ true,
3186                     makeEmptySampleLocationsInfo(), useDepth(), useStencil(), VERTEX_INPUT_VEC4_VEC4,
3187                     VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, stencilOpStateDrawOnce(), useFragmentShadingRate);
3188             }
3189         }
3190         else
3191             for (uint32_t passNdx = 0; passNdx < NUM_PASSES; ++passNdx)
3192             {
3193                 pipelines.emplace_back(vki, vk, physicalDevice, device, m_context.getDeviceExtensions(),
3194                                        m_params.pipelineConstructionType);
3195                 preparePipelineWrapper(pipelines.back(), std::vector<VkDynamicState>(), pipelineLayout,
3196                                        rt.getRenderPass(), vertexModule, fragmentModule,
3197                                        /*subpass*/ 0u, viewport, scissor, m_params.numSamples,
3198                                        /*use sample locations*/ true, sampleLocationsInfo[passNdx], useDepth(),
3199                                        useStencil(), VERTEX_INPUT_VEC4_VEC4, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
3200                                        stencilOpStateDrawOnce(), useFragmentShadingRate);
3201             }
3202 
3203         // Record secondary command buffers
3204 
3205         if (useSecondaryCmdBuffer())
3206         {
3207             secondaryCmdBuffer = allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_SECONDARY);
3208 
3209             beginSecondaryCommandBuffer(vk, *secondaryCmdBuffer, rt.getRenderPassWrapper(), /*subpass*/ 0u,
3210                                         m_params.numSamples, m_params.pipelineConstructionType);
3211             recordFirstPassContents(*secondaryCmdBuffer, pipelines[0], sampleLocationsInfo[0]);
3212             recordSecondPassContents(*secondaryCmdBuffer, pipelines[1], sampleLocationsInfo[1], clearColor1,
3213                                      clearDepthStencil0, scissor);
3214             endCommandBuffer(vk, *secondaryCmdBuffer);
3215         }
3216 
3217         // Record primary command buffer
3218 
3219         beginCommandBuffer(vk, *cmdBuffer);
3220 
3221         if (useSecondaryCmdBuffer())
3222         {
3223             rt.recordBeginRenderPass(vk, *cmdBuffer, renderArea, VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS);
3224             vk.cmdExecuteCommands(*cmdBuffer, 1u, &secondaryCmdBuffer.get());
3225         }
3226         else
3227         {
3228             rt.recordBeginRenderPass(vk, *cmdBuffer, renderArea, VK_SUBPASS_CONTENTS_INLINE);
3229             recordFirstPassContents(*cmdBuffer, pipelines[0], sampleLocationsInfo[0]);
3230             recordSecondPassContents(*cmdBuffer, pipelines[1], sampleLocationsInfo[1], clearColor1, clearDepthStencil0,
3231                                      scissor);
3232         }
3233 
3234         rt.endRenderPass(vk, *cmdBuffer);
3235 
3236         // Resolve image -> host buffer
3237         recordCopyImageToBuffer(vk, *cmdBuffer, m_renderSize, *m_resolveImage, *m_colorBuffer);
3238 
3239         endCommandBuffer(vk, *cmdBuffer);
3240 
3241         submitCommandsAndWait(vk, device, m_context.getUniversalQueue(), *cmdBuffer);
3242         invalidateAlloc(vk, device, *m_colorBufferAlloc);
3243     }
3244 
3245     const TestParams m_params;
3246     const VkPhysicalDeviceSampleLocationsPropertiesEXT m_sampleLocationsProperties;
3247     const UVec2 m_renderSize;
3248     UVec2 m_gridSize;
3249     std::vector<MultisamplePixelGrid> m_pixelGrids;
3250     uint32_t m_numVertices;
3251     Move<VkBuffer> m_vertexBuffer;
3252     MovePtr<Allocation> m_vertexBufferAlloc;
3253     const VkFormat m_colorFormat;
3254     Move<VkImage> m_colorImage;
3255     Move<VkImageView> m_colorImageView;
3256     MovePtr<Allocation> m_colorImageAlloc;
3257     VkFormat m_depthStencilFormat;
3258     VkImageAspectFlags m_depthStencilAspect;
3259     Move<VkImage> m_depthStencilImage;
3260     Move<VkImageView> m_depthStencilImageView;
3261     MovePtr<Allocation> m_depthStencilImageAlloc;
3262     Move<VkImage> m_resolveImage;
3263     Move<VkImageView> m_resolveImageView;
3264     MovePtr<Allocation> m_resolveImageAlloc;
3265     Move<VkBuffer> m_colorBuffer;
3266     MovePtr<Allocation> m_colorBufferAlloc;
3267 };
3268 
3269 } // namespace Draw
3270 
createTestsInGroup(tcu::TestCaseGroup * rootGroup,PipelineConstructionType pipelineConstructionType,bool useFragmentShadingRate)3271 void createTestsInGroup(tcu::TestCaseGroup *rootGroup, PipelineConstructionType pipelineConstructionType,
3272                         bool useFragmentShadingRate)
3273 {
3274     // Queries
3275     if (!useFragmentShadingRate && (pipelineConstructionType == PIPELINE_CONSTRUCTION_TYPE_MONOLITHIC))
3276     {
3277         MovePtr<tcu::TestCaseGroup> group(new tcu::TestCaseGroup(rootGroup->getTestContext(), "query"));
3278 
3279         addFunctionCase(group.get(), "sample_locations_properties", checkSupportSampleLocations,
3280                         testQuerySampleLocationProperties);
3281         addFunctionCase(group.get(), "multisample_properties", checkSupportSampleLocations,
3282                         testQueryMultisampleProperties);
3283 
3284         rootGroup->addChild(group.release());
3285     }
3286 
3287     const VkSampleCountFlagBits sampleCountRange[] = {
3288         VK_SAMPLE_COUNT_2_BIT, VK_SAMPLE_COUNT_4_BIT, VK_SAMPLE_COUNT_8_BIT, VK_SAMPLE_COUNT_16_BIT,
3289         // There are no implementations that support 32 or 64 programmable samples currently
3290     };
3291 
3292     // Verify custom sample locations and interpolation
3293     {
3294         using namespace VerifySamples;
3295 
3296         MovePtr<tcu::TestCaseGroup> groupLocation(
3297             new tcu::TestCaseGroup(rootGroup->getTestContext(), "verify_location"));
3298         MovePtr<tcu::TestCaseGroup> groupInterpolation(
3299             new tcu::TestCaseGroup(rootGroup->getTestContext(), "verify_interpolation"));
3300 
3301         for (const VkSampleCountFlagBits *pLoopNumSamples = sampleCountRange;
3302              pLoopNumSamples < DE_ARRAY_END(sampleCountRange); ++pLoopNumSamples)
3303         {
3304             addCases<VerifyLocationTest>(groupLocation.get(), *pLoopNumSamples, pipelineConstructionType,
3305                                          useFragmentShadingRate, addProgramsVerifyLocationGeometry);
3306             addCases<VerifyInterpolationTest>(groupInterpolation.get(), *pLoopNumSamples, pipelineConstructionType,
3307                                               useFragmentShadingRate, addProgramsVerifyInterpolation);
3308         }
3309 
3310         rootGroup->addChild(groupLocation.release());
3311         rootGroup->addChild(groupInterpolation.release());
3312     }
3313 
3314     // Draw with custom samples and various options
3315     {
3316         using namespace Draw;
3317 
3318         const uint32_t globalOption =
3319             useFragmentShadingRate ? static_cast<uint32_t>(TEST_OPTION_FRAGMENT_SHADING_RATE_BIT) : 0u;
3320         const uint32_t optionSets[] = {
3321             globalOption | TEST_OPTION_SAME_PATTERN_BIT,
3322             globalOption | 0u,
3323             globalOption | TEST_OPTION_DYNAMIC_STATE_BIT,
3324             globalOption | TEST_OPTION_SECONDARY_COMMAND_BUFFER_BIT,
3325             globalOption | TEST_OPTION_DYNAMIC_STATE_BIT | TEST_OPTION_SECONDARY_COMMAND_BUFFER_BIT,
3326             globalOption | TEST_OPTION_GENERAL_LAYOUT_BIT,
3327             globalOption | TEST_OPTION_GENERAL_LAYOUT_BIT | TEST_OPTION_DYNAMIC_STATE_BIT,
3328             globalOption | TEST_OPTION_GENERAL_LAYOUT_BIT | TEST_OPTION_SECONDARY_COMMAND_BUFFER_BIT,
3329             globalOption | TEST_OPTION_GENERAL_LAYOUT_BIT | TEST_OPTION_DYNAMIC_STATE_BIT |
3330                 TEST_OPTION_SECONDARY_COMMAND_BUFFER_BIT,
3331             globalOption | TEST_OPTION_WAIT_EVENTS_BIT,
3332             globalOption | TEST_OPTION_WAIT_EVENTS_BIT | TEST_OPTION_GENERAL_LAYOUT_BIT,
3333             globalOption | TEST_OPTION_WAIT_EVENTS_BIT | TEST_OPTION_GENERAL_LAYOUT_BIT |
3334                 TEST_OPTION_SECONDARY_COMMAND_BUFFER_BIT,
3335         };
3336 
3337         const struct
3338         {
3339             TestDrawIn drawIn;
3340             TestClears clears;
3341         } drawClearSets[] = {
3342             {TEST_DRAW_IN_RENDER_PASSES, TEST_CLEARS_NO_CLEAR},
3343             {TEST_DRAW_IN_RENDER_PASSES, TEST_CLEARS_LOAD_OP_CLEAR},
3344             {TEST_DRAW_IN_RENDER_PASSES, TEST_CLEARS_CMD_CLEAR_ATTACHMENTS},
3345             {TEST_DRAW_IN_RENDER_PASSES, TEST_CLEARS_CMD_CLEAR_IMAGE},
3346             {TEST_DRAW_IN_SUBPASSES, TEST_CLEARS_NO_CLEAR},
3347             {TEST_DRAW_IN_SUBPASSES, TEST_CLEARS_CMD_CLEAR_ATTACHMENTS},
3348             {TEST_DRAW_IN_SAME_SUBPASS, TEST_CLEARS_NO_CLEAR},
3349             {TEST_DRAW_IN_SAME_SUBPASS, TEST_CLEARS_CMD_CLEAR_ATTACHMENTS},
3350         };
3351 
3352         const TestImageAspect aspectRange[] = {
3353             TEST_IMAGE_ASPECT_COLOR,
3354             TEST_IMAGE_ASPECT_DEPTH,
3355             TEST_IMAGE_ASPECT_STENCIL,
3356         };
3357 
3358         MovePtr<tcu::TestCaseGroup> drawGroup(new tcu::TestCaseGroup(rootGroup->getTestContext(), "draw"));
3359         for (const TestImageAspect *pLoopImageAspect = aspectRange; pLoopImageAspect != DE_ARRAY_END(aspectRange);
3360              ++pLoopImageAspect)
3361         {
3362             MovePtr<tcu::TestCaseGroup> aspectGroup(
3363                 new tcu::TestCaseGroup(drawGroup->getTestContext(), getString(*pLoopImageAspect)));
3364             for (const VkSampleCountFlagBits *pLoopNumSamples = sampleCountRange;
3365                  pLoopNumSamples < DE_ARRAY_END(sampleCountRange); ++pLoopNumSamples)
3366             {
3367                 MovePtr<tcu::TestCaseGroup> samplesGroup(
3368                     new tcu::TestCaseGroup(aspectGroup->getTestContext(), getString(*pLoopNumSamples).c_str()));
3369 
3370                 for (uint32_t loopDrawSetNdx = 0u; loopDrawSetNdx < DE_LENGTH_OF_ARRAY(drawClearSets); ++loopDrawSetNdx)
3371                     for (const uint32_t *pLoopOptions = optionSets; pLoopOptions != DE_ARRAY_END(optionSets);
3372                          ++pLoopOptions)
3373                     {
3374                         const TestParams params{
3375                             pipelineConstructionType,             // PipelineConstructionType pipelineConstructionType;
3376                             *pLoopNumSamples,                     // VkSampleCountFlagBits numSamples;
3377                             *pLoopOptions,                        // TestOptionFlags options;
3378                             drawClearSets[loopDrawSetNdx].drawIn, // TestDrawIn drawIn;
3379                             drawClearSets[loopDrawSetNdx].clears, // TestClears clears;
3380                             *pLoopImageAspect,                    // TestImageAspect imageAspect;
3381                         };
3382 
3383                         // Filter out incompatible parameter combinations
3384                         if (params.imageAspect != TEST_IMAGE_ASPECT_COLOR)
3385                         {
3386                             // If the sample pattern is changed, the D/S image must be cleared or the result is undefined
3387                             if (((params.options & TEST_OPTION_SAME_PATTERN_BIT) == 0u) &&
3388                                 (params.clears == TEST_CLEARS_NO_CLEAR))
3389                                 continue;
3390                         }
3391 
3392                         // We are using events to change image layout and this is only allowed outside a render pass
3393                         if (((params.options & TEST_OPTION_WAIT_EVENTS_BIT) != 0u) &&
3394                             (params.drawIn != TEST_DRAW_IN_RENDER_PASSES))
3395                             continue;
3396 
3397                         // Can't change image layout inside a subpass
3398                         if (((params.options & TEST_OPTION_GENERAL_LAYOUT_BIT) != 0u) &&
3399                             (params.drawIn == TEST_DRAW_IN_SAME_SUBPASS))
3400                             continue;
3401 
3402                         std::ostringstream caseName;
3403                         caseName << getString(params.drawIn) << "_" << getString(params.clears)
3404                                  << (params.options != 0 ? "_" : "") << getTestOptionFlagsString(params.options);
3405 
3406                         addInstanceTestCaseWithPrograms<DrawTest>(samplesGroup.get(), caseName.str().c_str(),
3407                                                                   checkSupportDrawTests, initPrograms, params);
3408                     }
3409                 aspectGroup->addChild(samplesGroup.release());
3410             }
3411             drawGroup->addChild(aspectGroup.release());
3412         }
3413         rootGroup->addChild(drawGroup.release());
3414     }
3415 }
3416 
3417 } // namespace
3418 
createMultisampleSampleLocationsExtTests(tcu::TestContext & testCtx,PipelineConstructionType pipelineConstructionType,bool useFragmentShadingRate)3419 tcu::TestCaseGroup *createMultisampleSampleLocationsExtTests(tcu::TestContext &testCtx,
3420                                                              PipelineConstructionType pipelineConstructionType,
3421                                                              bool useFragmentShadingRate)
3422 {
3423     return createTestGroup(testCtx, "sample_locations_ext", createTestsInGroup, pipelineConstructionType,
3424                            useFragmentShadingRate);
3425 }
3426 
3427 } // namespace pipeline
3428 } // namespace vkt
3429