1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2022 The Khronos Group Inc.
6  * Copyright (c) 2022 Google 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  * \brief Robustness1 vertex access out of range tests
24  *//*--------------------------------------------------------------------*/
25 
26 #include "vktRobustness1VertexAccessTests.hpp"
27 #include "deDefs.h"
28 #include "deMemory.h"
29 #include "gluShaderProgram.hpp"
30 #include "gluShaderUtil.hpp"
31 #include "image/vktImageLoadStoreUtil.hpp"
32 #include "pipeline/vktPipelineSpecConstantUtil.hpp"
33 #include "qpTestLog.h"
34 #include "tcuTestCase.hpp"
35 #include "tcuTestContext.hpp"
36 #include "tcuTexture.hpp"
37 #include "tcuTextureUtil.hpp"
38 #include "tcuVectorType.hpp"
39 #include "tcuVectorUtil.hpp"
40 #include "vkBarrierUtil.hpp"
41 #include "vkCmdUtil.hpp"
42 #include "vkDefs.hpp"
43 #include "vkObjUtil.hpp"
44 #include "vkShaderProgram.hpp"
45 #include "vktRobustnessUtil.hpp"
46 #include "vktTestCase.hpp"
47 #include "vktTestCaseUtil.hpp"
48 #include "vkBuilderUtil.hpp"
49 #include "vkImageUtil.hpp"
50 #include "vkMemUtil.hpp"
51 #include "vkPrograms.hpp"
52 #include "vkQueryUtil.hpp"
53 #include "vkRef.hpp"
54 #include "vkRefUtil.hpp"
55 #include "vkTypeUtil.hpp"
56 #include "tcuTestLog.hpp"
57 #include "deMath.h"
58 #include "deUniquePtr.hpp"
59 #include "vkRefUtil.hpp"
60 #include <algorithm>
61 #include <cstdint>
62 #include <cstdio>
63 #include <iterator>
64 #include <sstream>
65 #include <tuple>
66 #include <vector>
67 #include <array>
68 #include <functional>
69 #include <cmath>
70 #include <limits>
71 #include "pipeline/vktPipelineImageUtil.hpp"
72 
73 namespace vkt
74 {
75 namespace robustness
76 {
77 namespace
78 {
79 
80 using namespace vk;
81 using namespace de;
82 using namespace tcu;
83 
84 using std::fixed;
85 using std::function;
86 using std::numeric_limits;
87 using std::ostringstream;
88 using std::setprecision;
89 using std::string;
90 using std::vector;
91 
92 typedef function<uint32_t(Vec4, Vec4)> AllocateVertexFn;
93 typedef function<void(uint32_t)> WriteIndexFn;
94 struct ValidityInfo
95 {
96     bool color0;
97     bool color1;
98 };
99 
100 uint32_t GetVerticesCountForTriangles(uint32_t tilesX, uint32_t tilesY);
101 void GenerateTriangles(
102     uint32_t tilesX, uint32_t tilesY, vector<Vec4> colors, const vector<uint32_t> &invalidIndices,
__anoncd86cf3d0202(uint32_t) 103     AllocateVertexFn allocateVertex, WriteIndexFn writeIndex = [](uint32_t) {});
104 
105 typedef vector<VkVertexInputBindingDescription> VertexBindings;
106 typedef vector<VkVertexInputAttributeDescription> VertexAttributes;
107 struct AttributeData
108 {
109     const void *data;
110     uint32_t size;
111 };
112 
113 struct InputInfo
114 {
115     VertexBindings vertexBindings;
116     VertexAttributes vertexAttributes;
117     vector<AttributeData> data;
118     uint32_t vertexCount;
119     vector<uint32_t> indices;
120 };
121 typedef function<TestStatus(const ConstPixelBufferAccess &)> ValidationFn;
122 
123 static const auto expectedColor = Vec4(0.25f, 0.0f, 0.75f, 1.0f); // Expected color input
124 static const auto unusedColor   = Vec4(0.75f, 0.0f, 0.25f, 1.0f); // Unused color attributes
125 static const auto outOfRangeColor =
126     Vec4(0.2f, 0.2f, 0.2f, 1.0f);            // Padding, out of range accesses - never accepted as output
127 static const auto validColors = vector<Vec4> // Colors accepted as valid in verification shader
128     {expectedColor, unusedColor};
129 static const auto invalidColors = vector<Vec4> // Colors accepted as oob access in verification shader
130     {expectedColor, unusedColor, Vec4(0.0f), Vec4(0.0f, 0.0f, 0.0f, 1.0f)};
131 
132 static TestStatus robustness1TestFn(TestContext &testCtx, Context &context, const VkDevice device,
133                                     DeviceDriverPtr deviceDriver, const vector<InputInfo> &inputs,
134                                     const IVec2 &renderSize);
135 
136 template <typename T>
137 class PaddedAlloc
138 {
139     uint32_t m_count, m_paddingCount;
140     vector<T> m_data;
141 
142 public:
143     PaddedAlloc(uint32_t count, uint32_t paddingCount, const T &paddingValue);
144     PaddedAlloc(const PaddedAlloc<T> &) = delete;
145 
paddedSize() const146     uint32_t paddedSize() const
147     {
148         return static_cast<uint32_t>(m_data.size());
149     }
paddedStart() const150     uint32_t paddedStart() const
151     {
152         return m_paddingCount;
153     }
paddedData() const154     const T *paddedData() const
155     {
156         return m_data.data();
157     }
158 
size() const159     uint32_t size() const
160     {
161         return m_count;
162     }
data() const163     const T *data() const
164     {
165         return m_data.data() + m_paddingCount;
166     }
167 
operator [](const uint32_t index)168     T &operator[](const uint32_t index)
169     {
170         return m_data[m_paddingCount + index];
171     }
operator [](const uint32_t index) const172     const T &operator[](const uint32_t index) const
173     {
174         return m_data[m_paddingCount + index];
175     }
176 
177     PaddedAlloc &operator=(PaddedAlloc &) = delete;
178 };
179 
180 template <typename T>
PaddedAlloc(uint32_t count,uint32_t paddingCount,const T & paddingValue)181 PaddedAlloc<T>::PaddedAlloc(uint32_t count, uint32_t paddingCount, const T &paddingValue)
182     : m_count(count)
183     , m_paddingCount(paddingCount)
184 {
185     DE_ASSERT((count + 2 * paddingCount) * sizeof(T) <= numeric_limits<uint32_t>::max());
186     m_data.resize(count + 2 * paddingCount);
187     const auto end = m_data.size() - 1;
188     for (uint32_t i = 0; i < paddingCount; ++i)
189     {
190         m_data[i]       = paddingValue;
191         m_data[end - i] = paddingValue;
192     }
193 }
194 
195 typedef function<TestStatus(TestContext &, Context &, const VkDevice device, DeviceDriverPtr deviceDriver)> TestFn;
196 struct Robustness1TestInfo
197 {
198     string name;
199     TestFn testFn;
200 };
201 static const auto renderTargetSize = IVec2(12, 12);
202 static const auto robustness1Tests = vector<Robustness1TestInfo>{
203     /* Layout of generated vertices vs location invalid vertices always at middle,
204        (3x3 tiles = 4x4 vertices):
205              0     1     2     3    ->      0      1      2      3
206              4 * 5 * 6     7    ->      4      7      8     11
207              8 * 9 *10    11    ->     12     13     14     15
208             12    13    14    15    ->    * 5 * 6 * 9 *10
209     */
210     {"out_of_bounds_stride_0", // string            name
211      [](TestContext &testContext, Context &context, const VkDevice device, DeviceDriverPtr deviceDriver)
__anoncd86cf3d0302(TestContext &testContext, Context &context, const VkDevice device, DeviceDriverPtr deviceDriver) 212      {
213          struct Color
214          {
215              Vec4 unused;
216              Vec4 color;
217          };
218          const uint32_t totalCount = GetVerticesCountForTriangles(3, 3);
219          PaddedAlloc<Vec4> positions(totalCount, 8, outOfRangeColor);
220          PaddedAlloc<Color> colors(totalCount, 8, {outOfRangeColor, outOfRangeColor});
221          PaddedAlloc<Vec4> color0(1, 4, outOfRangeColor);
222          color0[0] = expectedColor;
223          vector<uint32_t> indices;
224          uint32_t writeIndex = 0;
225          GenerateTriangles(
226              3u, 3u, {unusedColor}, {5, 6, 9, 10},
227              [&positions, &colors, &writeIndex](Vec4 position, Vec4 color)
228              {
229                  positions[writeIndex] = position;
230                  colors[writeIndex]    = {color, color};
231                  return writeIndex++;
232              },
233              [&indices](uint32_t index) { indices.push_back(index); });
234          auto bindings   = {makeVertexInputBindingDescription(0u, sizeof(positions[0]), VK_VERTEX_INPUT_RATE_VERTEX),
235                             makeVertexInputBindingDescription(1u, 0u, VK_VERTEX_INPUT_RATE_VERTEX),
236                             makeVertexInputBindingDescription(2u, sizeof(colors[0]), VK_VERTEX_INPUT_RATE_VERTEX)};
237          auto attributes = {
238              makeVertexInputAttributeDescription(0u, 0u, VK_FORMAT_R32G32B32A32_SFLOAT, 0u),
239              makeVertexInputAttributeDescription(1u, 1u, VK_FORMAT_R32G32B32A32_SFLOAT, 0u),
240              makeVertexInputAttributeDescription(2u, 2u, VK_FORMAT_R32G32B32A32_SFLOAT, offsetof(Color, color))};
241          return robustness1TestFn(testContext, context, device, deviceDriver,
242                                   {{bindings,
243                                     attributes,
244                                     {{positions.data(), positions.size() * static_cast<uint32_t>(sizeof(positions[0]))},
245                                      {color0.data(), color0.size() * static_cast<uint32_t>(sizeof(color0[0]))},
246                                      {colors.data(), (colors.size() - 3) * static_cast<uint32_t>(sizeof(colors[0])) -
247                                                          static_cast<uint32_t>(sizeof(Color::color) / 2)}},
248                                     static_cast<uint32_t>(positions.size()),
249                                     indices}},
250                                   renderTargetSize);
251      }},
252     {"out_of_bounds_stride_16_single_buffer", // string            name
253      [](TestContext &testContext, Context &context, const VkDevice device, DeviceDriverPtr deviceDriver)
__anoncd86cf3d0602(TestContext &testContext, Context &context, const VkDevice device, DeviceDriverPtr deviceDriver) 254      {
255          struct Vertex
256          {
257              Vec4 position;
258              Vec4 unused1;
259              Vec4 color1;
260              Vec4 color2;
261          };
262          const uint32_t totalCount = GetVerticesCountForTriangles(3, 3);
263          PaddedAlloc<Vertex> vertices(totalCount, 8,
264                                       {outOfRangeColor, outOfRangeColor, outOfRangeColor, outOfRangeColor});
265          uint32_t writeIndex = 0;
266          vector<uint32_t> indices;
267          GenerateTriangles(
268              3u, 3u, {expectedColor}, {5, 6, 9, 10},
269              [&vertices, &writeIndex](Vec4 position, Vec4 color)
270              {
271                  vertices[writeIndex] = {position, unusedColor, color, color};
272                  return writeIndex++;
273              },
274              [&indices](uint32_t index) { indices.push_back(index); });
275          auto bindings   = {makeVertexInputBindingDescription(0u, sizeof(Vertex), VK_VERTEX_INPUT_RATE_VERTEX),
276                             makeVertexInputBindingDescription(1u, sizeof(Vertex), VK_VERTEX_INPUT_RATE_VERTEX)};
277          auto attributes = {
278              makeVertexInputAttributeDescription(0u, 0u, VK_FORMAT_R32G32B32A32_SFLOAT, offsetof(Vertex, position)),
279              makeVertexInputAttributeDescription(1u, 1u, VK_FORMAT_R32G32B32A32_SFLOAT, offsetof(Vertex, color1)),
280              makeVertexInputAttributeDescription(2u, 1u, VK_FORMAT_R32G32B32A32_SFLOAT, offsetof(Vertex, color2))};
281          return robustness1TestFn(
282              testContext, context, device, deviceDriver,
283              {{
284                  bindings,
285                  attributes,
286                  {{vertices.data(), static_cast<uint32_t>(vertices.size() * sizeof(vertices[0]))},
287                   {vertices.data(),
288                    static_cast<uint32_t>((vertices.size() - 3) * sizeof(vertices[0]) - sizeof(Vertex::color2))}},
289                  static_cast<uint32_t>(vertices.size()),
290                  indices,
291              }},
292              renderTargetSize);
293      }},
294     {"out_of_bounds_stride_30_middle_of_buffer", // string            name
295      [](TestContext &testContext, Context &context, const VkDevice device, DeviceDriverPtr deviceDriver)
__anoncd86cf3d0902(TestContext &testContext, Context &context, const VkDevice device, DeviceDriverPtr deviceDriver) 296      {
297          const vector<uint32_t> invalidIndices = {5, 6, 9, 10};
298          const uint32_t invalidCount           = static_cast<uint32_t>(invalidIndices.size());
299          const uint32_t totalCount             = GetVerticesCountForTriangles(3, 3);
300          struct Vertex
301          {
302              Vec4 position;
303              Vec4 color1;
304              Vec4 unused1;
305              Vec4 color2;
306              Vec4 unused2;
307          };
308          PaddedAlloc<Vertex> vertices(
309              totalCount, 8, {outOfRangeColor, outOfRangeColor, outOfRangeColor, outOfRangeColor, outOfRangeColor});
310          uint32_t writeIndex = 0;
311          vector<uint32_t> indices;
312          GenerateTriangles(
313              3u, 3u, {expectedColor}, invalidIndices,
314              [&vertices, &writeIndex](Vec4 position, Vec4 color)
315              {
316                  vertices[writeIndex] = {position, color, unusedColor, unusedColor, unusedColor};
317                  return writeIndex++;
318              },
319              [&indices](uint32_t index) { indices.push_back(index); });
320          const auto elementSize = static_cast<uint32_t>(sizeof(Vertex));
321          auto bindings          = {
322              makeVertexInputBindingDescription(0u, elementSize, VK_VERTEX_INPUT_RATE_VERTEX),
323              makeVertexInputBindingDescription(1u, elementSize, VK_VERTEX_INPUT_RATE_VERTEX),
324          };
325          auto attributes = {
326              makeVertexInputAttributeDescription(0u, 0u, VK_FORMAT_R32G32B32A32_SFLOAT,
327                                                  vertices.paddedStart() * elementSize +
328                                                      static_cast<uint32_t>(offsetof(Vertex, position))),
329              makeVertexInputAttributeDescription(1u, 1u, VK_FORMAT_R32G32B32A32_SFLOAT,
330                                                  vertices.paddedStart() * elementSize +
331                                                      static_cast<uint32_t>(offsetof(Vertex, color1))),
332              makeVertexInputAttributeDescription(2u, 1u, VK_FORMAT_R32G32B32A32_SFLOAT,
333                                                  vertices.paddedStart() * elementSize +
334                                                      static_cast<uint32_t>(offsetof(Vertex, color2))),
335          };
336          return robustness1TestFn(testContext, context, device, deviceDriver,
337                                   {{bindings,
338                                     attributes,
339                                     {
340                                         {vertices.paddedData(), vertices.paddedSize() * elementSize},
341                                         {vertices.paddedData(), (vertices.paddedSize() - invalidCount) * elementSize},
342                                     },
343                                     static_cast<uint32_t>(vertices.size()),
344                                     indices}},
345                                   renderTargetSize);
346      }},
347     {"out_of_bounds_stride_8_middle_of_buffer_separate", // string            name
348      [](TestContext &testContext, Context &context, const VkDevice device, DeviceDriverPtr deviceDriver)
__anoncd86cf3d0c02(TestContext &testContext, Context &context, const VkDevice device, DeviceDriverPtr deviceDriver) 349      {
350          /* NOTE: Out of range entries ('padding') need to be initialized with unusedColor as the spec
351             allows out of range to return any value from within the bound memory range. */
352          const vector<uint32_t> invalidIndices = {5, 6, 9, 10};
353          const uint32_t invalidCount           = static_cast<uint32_t>(invalidIndices.size());
354          const uint32_t totalCount             = GetVerticesCountForTriangles(3, 3);
355          PaddedAlloc<Vec4> vertices(totalCount, 8, unusedColor);
356          PaddedAlloc<Vec4> colors(2 * totalCount - invalidCount, 8, unusedColor);
357          uint32_t writeIndex = 0;
358          vector<uint32_t> indices;
359          GenerateTriangles(
360              3u, 3u, {expectedColor}, invalidIndices,
361              [&vertices, &colors, &writeIndex, totalCount](Vec4 position, Vec4 color)
362              {
363                  vertices[writeIndex] = position;
364                  colors[writeIndex]   = color;
365                  if (totalCount + writeIndex < colors.size())
366                  {
367                      colors[totalCount + writeIndex] = color;
368                  }
369                  return writeIndex++;
370              },
371              [&indices](uint32_t index) { indices.push_back(index); });
372          const auto elementSize = static_cast<uint32_t>(sizeof(Vec4));
373          auto bindings          = {makeVertexInputBindingDescription(0u, elementSize, VK_VERTEX_INPUT_RATE_VERTEX),
374                                    makeVertexInputBindingDescription(1u, elementSize, VK_VERTEX_INPUT_RATE_VERTEX)};
375          auto attributes        = {makeVertexInputAttributeDescription(0u, 0u, VK_FORMAT_R32G32B32A32_SFLOAT,
376                                                                        vertices.paddedStart() * elementSize),
377                                    makeVertexInputAttributeDescription(1u, 1u, VK_FORMAT_R32G32B32A32_SFLOAT,
378                                                                        colors.paddedStart() * elementSize),
379                                    makeVertexInputAttributeDescription(2u, 1u, VK_FORMAT_R32G32B32A32_SFLOAT,
380                                                                        (colors.paddedStart() + totalCount) * elementSize)};
381          return robustness1TestFn(testContext, context, device, deviceDriver,
382                                   {{bindings,
383                                     attributes,
384                                     {{vertices.paddedData(), vertices.paddedSize() * elementSize},
385                                      {colors.paddedData(), colors.paddedSize() * elementSize}},
386                                     static_cast<uint32_t>(vertices.size()),
387                                     indices}},
388                                   renderTargetSize);
389      }}};
390 
GetVerticesCountForTriangles(uint32_t tilesX,uint32_t tilesY)391 uint32_t GetVerticesCountForTriangles(uint32_t tilesX, uint32_t tilesY)
392 {
393     return (tilesX + 1) * (tilesY + 1);
394 }
395 
396 // Generate triangles with invalid vertices placed at end of buffer. NOTE: Assumes invalidIndices to be in ascending order!
GenerateTriangles(uint32_t tilesX,uint32_t tilesY,vector<Vec4> colors,const vector<uint32_t> & invalidIndices,AllocateVertexFn allocateVertex,WriteIndexFn writeIndex)397 void GenerateTriangles(uint32_t tilesX, uint32_t tilesY, vector<Vec4> colors, const vector<uint32_t> &invalidIndices,
398                        AllocateVertexFn allocateVertex, WriteIndexFn writeIndex)
399 {
400     const auto tilesStride    = (tilesX + 1);
401     const auto total          = tilesStride * (tilesY + 1);
402     const auto lastValidIndex = total - 1 - static_cast<uint32_t>(invalidIndices.size());
403     const Vec2 step(1.0f / static_cast<float>(tilesX), 1.0f / static_cast<float>(tilesY));
404 
405     vector<uint32_t> indexMappings(total);
406     uint32_t nextInvalid      = 0;
407     uint32_t writeOffset      = 0;
408     uint32_t nextInvalidValue = nextInvalid < invalidIndices.size() ? invalidIndices[nextInvalid] : total;
409     for (uint32_t i = 0; i < total; ++i)
410     {
411         if (i < nextInvalidValue)
412         {
413             indexMappings[writeOffset++] = i;
414         }
415         else
416         {
417             ++nextInvalid;
418             nextInvalidValue = nextInvalid < invalidIndices.size() ? invalidIndices[nextInvalid] : total;
419         }
420     }
421     for (uint32_t i = 0; i < static_cast<uint32_t>(invalidIndices.size()); ++i)
422     {
423         indexMappings[writeOffset++] = invalidIndices[i];
424     }
425     uint32_t count      = 0;
426     const auto vertexFn = [lastValidIndex, &step, allocateVertex, &count](uint32_t x, uint32_t y, Vec4 color)
427     {
428         const auto result = allocateVertex(Vec4(2.0f * static_cast<float>(x) * step.x() - 1.0f,
429                                                 2.0f * static_cast<float>(y) * step.y() - 1.0f,
430                                                 (count <= lastValidIndex) ? 1.0f : 0.0f, 1.0f),
431                                            color);
432         ++count;
433         return result;
434     };
435     vector<uint32_t> indices(total);
436     for (uint32_t index = 0; index < total; ++index)
437     {
438         const auto mapped            = indexMappings[index];
439         const auto x                 = mapped % tilesStride;
440         const auto y                 = mapped / tilesStride;
441         const auto color             = colors[(x + y) % colors.size()];
442         indices[y * tilesStride + x] = vertexFn(x, y, color);
443     }
444     for (uint32_t y = 0; y < tilesY; ++y)
445     {
446         for (uint32_t x = 0; x < tilesX; ++x)
447         {
448             writeIndex(indices[(y)*tilesStride + x]);
449             writeIndex(indices[(y + 1) * tilesStride + x]);
450             writeIndex(indices[(y)*tilesStride + x + 1]);
451             writeIndex(indices[(y)*tilesStride + x + 1]);
452             writeIndex(indices[(y + 1) * tilesStride + x + 1]);
453             writeIndex(indices[(y + 1) * tilesStride + x]);
454         }
455     }
456 }
457 
makeImageCreateInfo(const tcu::IVec2 & size,const VkFormat format,const VkImageUsageFlags usage)458 VkImageCreateInfo makeImageCreateInfo(const tcu::IVec2 &size, const VkFormat format, const VkImageUsageFlags usage)
459 {
460     const VkImageCreateInfo imageInfo = {
461         VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType          sType;
462         DE_NULL,                             // const void*              pNext;
463         (VkImageCreateFlags)0,               // VkImageCreateFlags       flags;
464         VK_IMAGE_TYPE_2D,                    // VkImageType              imageType;
465         format,                              // VkFormat                 format;
466         makeExtent3D(size.x(), size.y(), 1), // VkExtent3D               extent;
467         1u,                                  // uint32_t                 mipLevels;
468         1u,                                  // uint32_t                 arrayLayers;
469         VK_SAMPLE_COUNT_1_BIT,               // VkSampleCountFlagBits    samples;
470         VK_IMAGE_TILING_OPTIMAL,             // VkImageTiling            tiling;
471         usage,                               // VkImageUsageFlags        usage;
472         VK_SHARING_MODE_EXCLUSIVE,           // VkSharingMode            sharingMode;
473         0u,                                  // uint32_t                 queueFamilyIndexCount;
474         DE_NULL,                             // const uint32_t*          pQueueFamilyIndices;
475         VK_IMAGE_LAYOUT_UNDEFINED,           // VkImageLayout            initialLayout;
476     };
477     return imageInfo;
478 }
479 
robustness1TestFn(TestContext & testCtx,Context & context,const VkDevice device,DeviceDriverPtr deviceDriver,const vector<InputInfo> & inputs,const IVec2 & renderSize)480 static TestStatus robustness1TestFn(TestContext &testCtx, Context &context, const VkDevice device,
481                                     DeviceDriverPtr deviceDriver, const vector<InputInfo> &inputs,
482                                     const IVec2 &renderSize)
483 {
484     const auto colorFormat    = VK_FORMAT_R8G8B8A8_UNORM;
485     const DeviceInterface &vk = *deviceDriver;
486     auto allocator            = SimpleAllocator(
487         vk, device, getPhysicalDeviceMemoryProperties(context.getInstanceInterface(), context.getPhysicalDevice()));
488 
489     const auto queueFamilyIndex = context.getUniversalQueueFamilyIndex();
490     VkQueue queue;
491     vk.getDeviceQueue(device, queueFamilyIndex, 0, &queue);
492 
493     vector<Move<VkImage>> colorImages;
494     vector<MovePtr<Allocation>> colorImageAllocs;
495     vector<Move<VkImageView>> colorViews;
496     vector<VkImageView> attachmentViews;
497     VkImageCreateInfo imageCreateInfos[] = {
498         makeImageCreateInfo(renderSize, colorFormat,
499                             VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT),
500     };
501     for (const auto &params : imageCreateInfos)
502     {
503         auto image      = createImage(vk, device, &params);
504         auto imageAlloc = allocator.allocate(getImageMemoryRequirements(vk, device, *image), MemoryRequirement::Any);
505         VK_CHECK(vk.bindImageMemory(device, *image, imageAlloc->getMemory(), imageAlloc->getOffset()));
506         const auto createInfo = VkImageViewCreateInfo{
507             VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, // VkStructureType sType;
508             DE_NULL,                                  // const void* pNext;
509             0u,                                       // VkImageViewCreateFlags flags;
510             *image,                                   // VkImage image;
511             VK_IMAGE_VIEW_TYPE_2D,                    // VkImageViewType viewType;
512             colorFormat,                              // VkFormat format;
513             {VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY,
514              VK_COMPONENT_SWIZZLE_IDENTITY},            // VkComponentMapping components;
515             {VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u} // VkImageSubresourceRange subresourceRange;
516         };
517         auto imageView = createImageView(vk, device, &createInfo);
518         attachmentViews.push_back(*imageView);
519         colorImageAllocs.emplace_back(imageAlloc);
520         colorViews.emplace_back(imageView);
521         colorImages.emplace_back(image);
522     }
523 
524     const auto colorAttachmentDescs = vector<VkAttachmentDescription>{
525         {
526             (VkAttachmentDescriptionFlags)0,         // VkAttachmentDescriptionFlags        flags
527             colorFormat,                             // VkFormat                            format
528             VK_SAMPLE_COUNT_1_BIT,                   // VkSampleCountFlagBits            samples
529             VK_ATTACHMENT_LOAD_OP_CLEAR,             // VkAttachmentLoadOp                loadOp
530             VK_ATTACHMENT_STORE_OP_STORE,            // VkAttachmentStoreOp                storeOp
531             VK_ATTACHMENT_LOAD_OP_DONT_CARE,         // VkAttachmentLoadOp                stencilLoadOp
532             VK_ATTACHMENT_STORE_OP_DONT_CARE,        // VkAttachmentStoreOp                stencilStoreOp
533             VK_IMAGE_LAYOUT_UNDEFINED,               // VkImageLayout                    initialLayout
534             VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL // VkImageLayout                    finalLayout
535         },
536     };
537     const auto attachmentRefs = vector<vector<VkAttachmentReference>>{
538         {{0u, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}}, // pass 0 color
539     };
540     const auto subpassDescs = vector<VkSubpassDescription>{{
541         static_cast<VkSubpassDescriptionFlags>(0),       // VkSubpassDescriptionFlags flags;
542         VK_PIPELINE_BIND_POINT_GRAPHICS,                 // VkPipelineBindPoint pipelineBindPoint;
543         0u,                                              // uint32_t inputAttachmentCount;
544         DE_NULL,                                         // const VkAttachmentReference* pInputAttachments;
545         static_cast<uint32_t>(attachmentRefs[0].size()), // uint32_t colorAttachmentCount;
546         attachmentRefs[0].data(),                        // const VkAttachmentReference* pColorAttachments;
547         DE_NULL,                                         // const VkAttachmentReference* pResolveAttachments;
548         DE_NULL,                                         // const VkAttachmentReference* pDepthStencilAttachment;
549         0u,                                              // uint32_t preserveAttachmentCount;
550         DE_NULL                                          // const uint32_t* pPreserveAttachments;
551     }};
552     const auto subpassDeps  = vector<VkSubpassDependency>{
553         {
554             VK_SUBPASS_EXTERNAL,                           // uint32_t srcSubpass;
555             0u,                                            // uint32_t dstSubpass;
556             VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,             // VkPipelineStageFlags srcStageMask;
557             VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, // VkPipelineStageFlags dstStageMask;
558             0u,                                            // VkAccessFlags srcAccessMask;
559             VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,          // VkAccessFlags dstAccessMask;
560             VK_DEPENDENCY_BY_REGION_BIT                    // VkDependencyFlags dependencyFlags;
561         },
562         {
563             0u,                                            // uint32_t srcSubpass;
564             VK_SUBPASS_EXTERNAL,                           // uint32_t dstSubpass;
565             VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, // VkPipelineStageFlags srcStageMask;
566             VK_PIPELINE_STAGE_TRANSFER_BIT,                // VkPipelineStageFlags dstStageMask;
567             VK_ACCESS_COLOR_ATTACHMENT_READ_BIT,           // VkAccessFlags srcAccessMask;
568             VK_ACCESS_TRANSFER_READ_BIT,                   // VkAccessFlags dstAccessMask;
569             VK_DEPENDENCY_BY_REGION_BIT                    // VkDependencyFlags dependencyFlags;
570         }};
571     const auto renderPassInfo = VkRenderPassCreateInfo{
572         VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,          // VkStructureType                    sType
573         DE_NULL,                                            // const void*                        pNext
574         static_cast<VkRenderPassCreateFlags>(0),            // VkRenderPassCreateFlags            flags
575         static_cast<uint32_t>(colorAttachmentDescs.size()), // uint32_t                            attachmentCount
576         colorAttachmentDescs.data(),                        // const VkAttachmentDescription*    pAttachments
577         static_cast<uint32_t>(subpassDescs.size()),         // uint32_t                            subpassCount
578         subpassDescs.data(),                                // const VkSubpassDescription*        pSubpasses
579         static_cast<uint32_t>(subpassDeps.size()),          // uint32_t                            dependencyCount
580         subpassDeps.data()                                  // const VkSubpassDependency*        pDependencies
581     };
582     const Unique<VkRenderPass> pass(createRenderPass(vk, device, &renderPassInfo, DE_NULL));
583 
584     vector<Move<VkBuffer>> vertexBuffers;
585     vector<MovePtr<Allocation>> vertexBufferAllocs;
586     vector<vector<VkBuffer>> vertexBufferPtrs;
587     vector<vector<VkDeviceSize>> vertexBufferOffsets;
588     vector<Move<VkBuffer>> indexBuffers;
589     vector<MovePtr<Allocation>> indexBufferAllocs;
590     vector<Move<VkPipelineLayout>> pipelineLayouts;
591     vector<Move<VkPipeline>> pipelines;
592 
593     const auto descriptorPool =
594         DescriptorPoolBuilder()
595             .addType(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, static_cast<uint32_t>(inputs.size() * 4u))
596             .build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
597     vector<Move<VkDescriptorSetLayout>> descriptorSetLayouts;
598     vector<Move<VkDescriptorSet>> descriptorSets;
599     vector<vector<VkDescriptorSet>> descriptorSetPtrs;
600     vector<Move<VkShaderModule>> shaderModules;
601     const vector<VkViewport> viewports = {makeViewport(renderSize)};
602     const vector<VkRect2D> scissors    = {makeRect2D(renderSize)};
603     const vector<string> vertexNames   = {"vertex-test"};
604     const vector<string> fragmentNames = {"fragment-test"};
605     for (vector<InputInfo>::size_type i = 0; i < inputs.size(); ++i)
606     {
607         const auto &input = inputs[i];
608         vector<VkDescriptorSet> inputDescriptorSets;
609         vector<VkDescriptorSetLayout> setLayouts;
610         DescriptorSetLayoutBuilder builder;
611         for (size_t j = 0; j < input.vertexBindings.size(); ++j)
612         {
613             builder.addSingleBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_ALL);
614         }
615         auto descriptorSetLayout = builder.build(vk, device);
616         setLayouts.push_back(*descriptorSetLayout);
617         VkDescriptorSetAllocateInfo descriptorSetAllocateInfo = {
618             VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, // VkStructureType sType;
619             DE_NULL,                                        // const void* pNext;
620             *descriptorPool,                                // VkDescriptorPool descriptorPool;
621             1u,                                             // uint32_t setLayoutCount;
622             &*descriptorSetLayout                           // const VkDescriptorSetLayout* pSetLayouts;
623         };
624         auto descriptorSet = allocateDescriptorSet(vk, device, &descriptorSetAllocateInfo);
625         inputDescriptorSets.push_back(*descriptorSet);
626 
627         VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo = {
628             VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, // VkStructureType sType;
629             DE_NULL,                                       // const void* pNext;
630             0u,                                            // VkPipelineLayoutCreateFlags flags;
631             static_cast<uint32_t>(setLayouts.size()),      // uint32_t setLayoutCount;
632             setLayouts.data(),                             // const VkDescriptorSetLayout* pSetLayouts;
633             0u,                                            // uint32_t pushConstantRangeCount;
634             DE_NULL                                        // const VkPushConstantRange* pPushConstantRanges;
635         };
636         auto pipelineLayout = createPipelineLayout(vk, device, &pipelineLayoutCreateInfo);
637 
638         descriptorSetPtrs.push_back(inputDescriptorSets);
639         descriptorSetLayouts.emplace_back(descriptorSetLayout);
640         descriptorSets.emplace_back(descriptorSet);
641 
642         vector<VkBuffer> inputVertexBufferPtrs;
643         for (const auto &data : input.data)
644         {
645             const auto createInfo = makeBufferCreateInfo(data.size, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
646             auto buffer           = createBuffer(vk, device, &createInfo);
647             auto bufferAlloc =
648                 allocator.allocate(getBufferMemoryRequirements(vk, device, *buffer), MemoryRequirement::HostVisible);
649             VK_CHECK(vk.bindBufferMemory(device, *buffer, bufferAlloc->getMemory(), bufferAlloc->getOffset()));
650             deMemcpy(bufferAlloc->getHostPtr(), data.data, data.size);
651             flushMappedMemoryRange(vk, device, bufferAlloc->getMemory(), bufferAlloc->getOffset(), VK_WHOLE_SIZE);
652             inputVertexBufferPtrs.push_back(*buffer);
653             vertexBufferAllocs.emplace_back(bufferAlloc);
654             vertexBuffers.emplace_back(buffer);
655         }
656         vertexBufferOffsets.push_back(vector<VkDeviceSize>(inputVertexBufferPtrs.size(), 0ull));
657         vertexBufferPtrs.push_back(inputVertexBufferPtrs);
658 
659         if (input.indices.size() > 0u)
660         {
661             const auto indexDataSize = input.indices.size() * sizeof(input.indices[0]);
662             const auto createInfo    = makeBufferCreateInfo(indexDataSize, VK_BUFFER_USAGE_INDEX_BUFFER_BIT);
663             auto indexBuffer         = createBuffer(vk, device, &createInfo);
664             auto indexBufferAlloc    = allocator.allocate(getBufferMemoryRequirements(vk, device, *indexBuffer),
665                                                           MemoryRequirement::HostVisible);
666             VK_CHECK(vk.bindBufferMemory(device, *indexBuffer, indexBufferAlloc->getMemory(),
667                                          indexBufferAlloc->getOffset()));
668             deMemcpy(indexBufferAlloc->getHostPtr(), input.indices.data(), indexDataSize);
669             flushMappedMemoryRange(vk, device, indexBufferAlloc->getMemory(), indexBufferAlloc->getOffset(),
670                                    VK_WHOLE_SIZE);
671             indexBufferAllocs.emplace_back(indexBufferAlloc);
672             indexBuffers.emplace_back(indexBuffer);
673         }
674         const auto &bindings             = input.vertexBindings;
675         const auto &attributes           = input.vertexAttributes;
676         const auto vertexInputCreateInfo = VkPipelineVertexInputStateCreateInfo{
677             VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType sType;
678             DE_NULL,                                                   // const void* pNext;
679             0u,                                                        // VkPipelineVertexInputStateCreateFlags flags;
680             static_cast<uint32_t>(bindings.size()),                    // uint32_t vertexBindingDescriptionCount;
681             bindings.data(), // const VkVertexInputBindingDescription* pVertexBindingDescriptions;
682             static_cast<uint32_t>(attributes.size()), // uint32_t vertexAttributeDescriptionCount;
683             attributes.data() // const VkVertexInputAttributeDescription* pVertexAttributeDescriptions;
684         };
685         auto vertexShaderModule =
686             createShaderModule(vk, device, context.getBinaryCollection().get(vertexNames[i % vertexNames.size()]), 0u);
687         auto fragmentShaderModule = createShaderModule(
688             vk, device, context.getBinaryCollection().get(fragmentNames[i % fragmentNames.size()]), 0u);
689         auto graphicsPipeline = makeGraphicsPipeline(
690             vk,                  // const DeviceInterface&                            vk,
691             device,              // const VkDevice                                    device,
692             *pipelineLayout,     // const VkPipelineLayout                            pipelineLayout,
693             *vertexShaderModule, // const VkShaderModule                                vertexShaderModule,
694             DE_NULL,             // const VkShaderModule                                tessellationControlShaderModule,
695             DE_NULL,             // const VkShaderModule                                tessellationEvalShaderModule,
696             DE_NULL,             // const VkShaderModule                                geometryShaderModule,
697             *fragmentShaderModule, // const VkShaderModule                                fragmentShaderModule,
698             *pass,                 // const VkRenderPass                                renderPass,
699             viewports,             // const std::vector<VkViewport>&                    viewports,
700             scissors,              // const std::vector<VkRect2D>&                        scissors,
701             VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, // const VkPrimitiveTopology                        topology,
702             static_cast<uint32_t>(i),            // const uint32_t                                    subpass,
703             0u,                      // const uint32_t                                    patchControlPoints,
704             &vertexInputCreateInfo); // const VkPipelineVertexInputStateCreateInfo*        vertexInputStateCreateInfo,
705 
706         pipelineLayouts.emplace_back(pipelineLayout);
707         pipelines.emplace_back(graphicsPipeline);
708         shaderModules.emplace_back(vertexShaderModule);
709         shaderModules.emplace_back(fragmentShaderModule);
710     }
711 
712     const auto framebufferCreateInfo = VkFramebufferCreateInfo{
713         VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,     // VkStructureType sType;
714         DE_NULL,                                       // const void* pNext;
715         0u,                                            // VkFramebufferCreateFlags flags;
716         *pass,                                         // VkRenderPass renderPass;
717         static_cast<uint32_t>(attachmentViews.size()), // uint32_t attachmentCount;
718         attachmentViews.data(),                        // const VkImageView* pAttachments;
719         (uint32_t)renderSize.x(),                      // uint32_t width;
720         (uint32_t)renderSize.y(),                      // uint32_t height;
721         1u                                             // uint32_t layers;
722     };
723     const Unique<VkFramebuffer> framebuffer(createFramebuffer(vk, device, &framebufferCreateInfo));
724 
725     const Unique<VkCommandPool> commandPool(
726         createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_TRANSIENT_BIT, queueFamilyIndex));
727     const Unique<VkCommandBuffer> commandBuffer(
728         allocateCommandBuffer(vk, device, *commandPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
729     beginCommandBuffer(vk, *commandBuffer, 0u);
730     beginRenderPass(vk, *commandBuffer, *pass, *framebuffer, makeRect2D(renderSize), Vec4(0.0f));
731     uint32_t nextIndex = 0;
732     for (vector<InputInfo>::size_type i = 0; i < inputs.size(); ++i)
733     {
734         const auto &input = inputs[i];
735         vk.cmdBindPipeline(*commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipelines[i]);
736         vk.cmdBindDescriptorSets(*commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipelineLayouts[i], 0,
737                                  static_cast<uint32_t>(descriptorSetPtrs[i].size()), descriptorSetPtrs[i].data(), 0,
738                                  DE_NULL);
739         vk.cmdBindVertexBuffers(*commandBuffer, 0, (uint32_t)vertexBufferPtrs[i].size(), vertexBufferPtrs[i].data(),
740                                 vertexBufferOffsets[i].data());
741         if (!input.indices.empty())
742         {
743             vk.cmdBindIndexBuffer(*commandBuffer, *indexBuffers[nextIndex], 0u, VK_INDEX_TYPE_UINT32);
744             vk.cmdDrawIndexed(*commandBuffer, static_cast<uint32_t>(input.indices.size()), 1u, 0, 0, 0u);
745             ++nextIndex;
746         }
747         else
748         {
749             vk.cmdDraw(*commandBuffer, input.vertexCount, 1u, 0, 0);
750         }
751         if (i + 1 < inputs.size())
752         {
753             vk.cmdNextSubpass(*commandBuffer, VK_SUBPASS_CONTENTS_INLINE);
754         }
755     }
756     endRenderPass(vk, *commandBuffer);
757 
758     endCommandBuffer(vk, *commandBuffer);
759     submitCommandsAndWait(vk, device, queue, *commandBuffer);
760 
761     const auto texture0 = pipeline::readColorAttachment(vk, device, queue, queueFamilyIndex, allocator, *colorImages[0],
762                                                         colorFormat, UVec2(renderSize.x(), renderSize.y()));
763 
764     const auto tex1Access = texture0->getAccess();
765     for (int32_t y = 0; y < tex1Access.getHeight(); ++y)
766     {
767         for (int32_t x = 0; x < tex1Access.getWidth(); ++x)
768         {
769             if (tex1Access.getPixel(x, y) != Vec4(0.0f, 1.0f, 0.0f, 1.0f))
770             {
771                 testCtx.getLog() << TestLog::ImageSet("Result Images", "")
772                                  << TestLog::Image("Texture 0 (source)", "", texture0->getAccess())
773                                  << TestLog::EndImageSet;
774 
775                 return TestStatus::fail("Image comparison failed.");
776             }
777         }
778     }
779     return TestStatus::pass("OK");
780 }
781 } // namespace
782 
783 // Robustness1AccessInstance
784 
785 template <typename T>
786 class Robustness1AccessInstance : public vkt::TestInstance
787 {
788 public:
789     Robustness1AccessInstance(TestContext &testCtx, Context &context,
790 #ifdef CTS_USES_VULKANSC
791                               de::MovePtr<CustomInstance> customInstance,
792 #endif // CTS_USES_VULKANSC
793                               T device, DeviceDriverPtr deviceDriver, const Robustness1TestInfo &testInfo);
~Robustness1AccessInstance()794     virtual ~Robustness1AccessInstance()
795     {
796     }
797     virtual TestStatus iterate() override;
798 
799 private:
800     TestContext &m_testCtx;
801 #ifndef CTS_USES_VULKANSC
802     T m_device;
803     de::MovePtr<vk::DeviceDriver> m_deviceDriver;
804 #else
805     de::MovePtr<CustomInstance> m_customInstance;
806     T m_device;
807     de::MovePtr<vk::DeviceDriverSC, vk::DeinitDeviceDeleter> m_deviceDriver;
808 #endif // CTS_USES_VULKANSC
809     const Robustness1TestInfo &m_testInfo;
810 };
811 
812 template <typename T>
Robustness1AccessInstance(TestContext & testCtx,Context & context,de::MovePtr<CustomInstance> customInstance,T device,DeviceDriverPtr deviceDriver,const Robustness1TestInfo & testInfo)813 Robustness1AccessInstance<T>::Robustness1AccessInstance(TestContext &testCtx, Context &context,
814 #ifdef CTS_USES_VULKANSC
815                                                         de::MovePtr<CustomInstance> customInstance,
816 #endif // CTS_USES_VULKANSC
817                                                         T device, DeviceDriverPtr deviceDriver,
818                                                         const Robustness1TestInfo &testInfo)
819     : vkt::TestInstance(context)
820     , m_testCtx(testCtx)
821 #ifdef CTS_USES_VULKANSC
822     , m_customInstance(customInstance)
823 #endif // CTS_USES_VULKANSC
824     , m_device(device)
825     , m_deviceDriver(deviceDriver)
826     , m_testInfo(testInfo)
827 {
828 }
829 
830 template <typename T>
iterate()831 TestStatus Robustness1AccessInstance<T>::iterate()
832 {
833     return m_testInfo.testFn(m_testCtx, m_context, *m_device, m_deviceDriver);
834 }
835 
836 // Robustness1AccessTest
837 
838 class Robustness1AccessTest : public vkt::TestCase
839 {
840 public:
841     Robustness1AccessTest(TestContext &testContext, const Robustness1TestInfo &testInfo);
~Robustness1AccessTest()842     virtual ~Robustness1AccessTest()
843     {
844     }
845 
846     virtual TestInstance *createInstance(Context &context) const override;
847 
848 protected:
849     virtual void initPrograms(SourceCollections &programCollection) const override;
850 
851 private:
852     Robustness1TestInfo m_testInfo;
853 };
854 
Robustness1AccessTest(TestContext & testContext,const Robustness1TestInfo & testInfo)855 Robustness1AccessTest::Robustness1AccessTest(TestContext &testContext, const Robustness1TestInfo &testInfo)
856     : vkt::TestCase(testContext, testInfo.name)
857     , m_testInfo(testInfo)
858 {
859 }
860 
createInstance(Context & context) const861 TestInstance *Robustness1AccessTest::createInstance(Context &context) const
862 {
863 #ifndef CTS_USES_VULKANSC
864     Move<VkDevice> device = createRobustBufferAccessDevice(context);
865     DeviceDriverPtr deviceDriver =
866         DeviceDriverPtr(new DeviceDriver(context.getPlatformInterface(), context.getInstance(), *device,
867                                          context.getUsedApiVersion(), context.getTestContext().getCommandLine()));
868 #else
869     de::MovePtr<CustomInstance> customInstance =
870         de::MovePtr<CustomInstance>(new CustomInstance(createCustomInstanceFromContext(context)));
871     Move<VkDevice> device = createRobustBufferAccessDevice(context, *customInstance);
872     DeviceDriverPtr deviceDriver =
873         DeviceDriverPtr(new DeviceDriverSC(context.getPlatformInterface(), *customInstance, *device,
874                                            context.getTestContext().getCommandLine(), context.getResourceInterface(),
875                                            context.getDeviceVulkanSC10Properties(), context.getDeviceProperties(),
876                                            context.getUsedApiVersion()),
877                         vk::DeinitDeviceDeleter(context.getResourceInterface().get(), *device));
878 #endif // CTS_USES_VULKANSC
879 
880     return new Robustness1AccessInstance<Move<VkDevice>>(m_testCtx, context,
881 #ifdef CTS_USES_VULKANSC
882                                                          customInstance,
883 #endif // CTS_USES_VULKANSC
884                                                          device, deviceDriver, m_testInfo);
885 }
886 
initPrograms(SourceCollections & programCollection) const887 void Robustness1AccessTest::initPrograms(SourceCollections &programCollection) const
888 {
889     ostringstream vertexTestSource;
890     vertexTestSource << "#version 310 es\n"
891                      << "precision highp float;\n"
892                      << "layout(location = 0) in vec4 in_position;\n"
893                      << "layout(location = 1) in vec4 in_color0;\n"
894                      << "layout(location = 2) in vec4 in_color1;\n"
895                      << "layout(location = 0) out vec4 out_color;\n"
896                      << "bool is_valid(vec4 color)\n"
897                      << "{\n"
898                      << "  return\n";
899     const auto compare_color = [](ostringstream &out, const string &variable, const Vec4 &color)
900     {
901         out << setprecision(5) << fixed << "    (" << variable << ".r - " << color.x() << " < 0.00001 && " << variable
902             << ".g - " << color.y() << " < 0.00001 && " << variable << ".b - " << color.z() << " < 0.00001 && "
903             << variable << ".a - " << color.w() << " < 0.00001"
904             << ")";
905     };
906     for (vector<Vec4>::size_type i = 0; i < validColors.size(); ++i)
907     {
908         compare_color(vertexTestSource, "color", validColors[i]);
909         vertexTestSource << ((i < validColors.size() - 1) ? " ||\n" : ";\n");
910     }
911     vertexTestSource << "}\n"
912                      << "bool is_invalid(vec4 color)\n"
913                      << "{\n"
914                      << "  return\n";
915     for (vector<Vec4>::size_type i = 0; i < invalidColors.size(); ++i)
916     {
917         compare_color(vertexTestSource, "color", invalidColors[i]);
918         vertexTestSource << ((i < invalidColors.size() - 1) ? " ||\n" : ";\n");
919     }
920     vertexTestSource
921         << "}\n"
922         << "bool validate(bool should_be_valid, vec4 color0, vec4 color1)\n"
923         << "{\n"
924         << "  return (should_be_valid && is_valid(color0) && is_valid(color1)) || (is_invalid(color0) && "
925            "is_invalid(color1));\n"
926         << "}\n"
927         << "void main()\n"
928         << "{\n"
929         << "  out_color = validate(in_position.z >= 1.0, in_color0, in_color1) ? vec4(0,1,0,1) : in_color0;"
930         << "  gl_Position = vec4(in_position.xy, 0.0, 1.0);\n"
931         << "}\n";
932     programCollection.glslSources.add("vertex-test") << glu::VertexSource(vertexTestSource.str());
933     programCollection.glslSources.add("fragment-test")
934         << glu::FragmentSource("#version 310 es\n"
935                                "precision highp float;\n"
936                                "layout(location = 0) in vec4 in_color;\n"
937                                "layout(location = 0) out vec4 out_color;\n"
938                                "void main() {\n"
939                                "  out_color = in_color;\n"
940                                "}\n");
941 }
942 
createRobustness1VertexAccessTests(TestContext & testCtx)943 TestCaseGroup *createRobustness1VertexAccessTests(TestContext &testCtx)
944 {
945     MovePtr<TestCaseGroup> robustness1AccessTests(new TestCaseGroup(testCtx, "robustness1_vertex_access"));
946     for (const auto &info : robustness1Tests)
947     {
948         robustness1AccessTests->addChild(new Robustness1AccessTest(testCtx, info));
949     }
950 
951     return robustness1AccessTests.release();
952 }
953 
954 } // namespace robustness
955 } // namespace vkt
956