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