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 ¶ms : imageCreateInfos)
502 {
503 auto image = createImage(vk, device, ¶ms);
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