• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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, &params);
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