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