1/*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2015 The Khronos Group Inc.
6 * Copyright (c) 2015 Imagination Technologies Ltd.
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 * \file
24 * \brief Input Assembly Tests
25 *//*--------------------------------------------------------------------*/
26
27#include "vktPipelineInputAssemblyTests.hpp"
28#include "vktPipelineClearUtil.hpp"
29#include "vktPipelineImageUtil.hpp"
30#include "vktPipelineVertexUtil.hpp"
31#include "vktPipelineReferenceRenderer.hpp"
32#include "vktAmberTestCase.hpp"
33#include "vktTestCase.hpp"
34#include "vkImageUtil.hpp"
35#include "vkMemUtil.hpp"
36#include "vkPrograms.hpp"
37#include "vkQueryUtil.hpp"
38#include "vkRef.hpp"
39#include "vkRefUtil.hpp"
40#include "vkTypeUtil.hpp"
41#include "vkCmdUtil.hpp"
42#include "vkObjUtil.hpp"
43#include "tcuImageCompare.hpp"
44#include "deMath.h"
45#include "deMemory.h"
46#include "deRandom.hpp"
47#include "deStringUtil.hpp"
48#include "deUniquePtr.hpp"
49
50#include <algorithm>
51#include <sstream>
52#include <vector>
53
54namespace vkt
55{
56namespace pipeline
57{
58
59using namespace vk;
60
61enum class RestartType
62{
63	NORMAL,
64	NONE,
65	ALL,
66};
67
68namespace
69{
70
71class InputAssemblyTest : public vkt::TestCase
72{
73public:
74	const static VkPrimitiveTopology	s_primitiveTopologies[];
75	const static deUint32				s_restartIndex32;
76	const static deUint16				s_restartIndex16;
77	const static deUint8				s_restartIndex8;
78
79										InputAssemblyTest		(tcu::TestContext&					testContext,
80																 const std::string&					name,
81																 const PipelineConstructionType		pipelineConstructionType,
82																 VkPrimitiveTopology				primitiveTopology,
83																 int								primitiveCount,
84																 bool								testPrimitiveRestart,
85																 VkIndexType						indexType);
86	virtual								~InputAssemblyTest		(void) {}
87	virtual void						initPrograms			(SourceCollections& sourceCollections) const;
88	virtual void						checkSupport			(Context& context) const;
89	virtual TestInstance*				createInstance			(Context& context) const;
90	static bool							isRestartIndex			(VkIndexType indexType, deUint32 indexValue);
91#ifndef CTS_USES_VULKANSC
92	static deUint32						getRestartIndex			(VkIndexType indexType);
93#endif // CTS_USES_VULKANSC
94
95protected:
96	virtual void						createBufferData		(VkPrimitiveTopology		topology,
97																 int						primitiveCount,
98																 VkIndexType				indexType,
99																 std::vector<deUint32>&		indexData,
100																 std::vector<Vertex4RGBA>&	vertexData) const = 0;
101	VkPrimitiveTopology					m_primitiveTopology;
102	const int							m_primitiveCount;
103
104private:
105	const PipelineConstructionType		m_pipelineConstructionType;
106	bool								m_testPrimitiveRestart;
107	VkIndexType							m_indexType;
108};
109
110class PrimitiveTopologyTest : public InputAssemblyTest
111{
112public:
113										PrimitiveTopologyTest	(tcu::TestContext&			testContext,
114																 const std::string&			name,
115																 PipelineConstructionType	pipelineConstructionType,
116																 VkPrimitiveTopology		primitiveTopology,
117																 VkIndexType				indexType);
118	virtual								~PrimitiveTopologyTest	(void) {}
119
120protected:
121	virtual void						createBufferData		(VkPrimitiveTopology		topology,
122																 int						primitiveCount,
123																 VkIndexType				indexType,
124																 std::vector<deUint32>&		indexData,
125																 std::vector<Vertex4RGBA>&	vertexData) const;
126
127private:
128};
129
130#ifndef CTS_USES_VULKANSC
131class PrimitiveRestartTest : public InputAssemblyTest
132{
133public:
134										PrimitiveRestartTest	(tcu::TestContext&					testContext,
135																 const std::string&					name,
136																 const PipelineConstructionType		pipelineConstructionType,
137																 VkPrimitiveTopology				primitiveTopology,
138																 VkIndexType						indexType,
139																 RestartType						restartType);
140	virtual								~PrimitiveRestartTest	(void) {}
141	virtual void						checkSupport			(Context& context) const;
142
143protected:
144	virtual void						createBufferData		(VkPrimitiveTopology		topology,
145																 int						primitiveCount,
146																 VkIndexType				indexType,
147																 std::vector<deUint32>&		indexData,
148																 std::vector<Vertex4RGBA>&	vertexData) const;
149
150private:
151	bool								isRestartPrimitive		(int primitiveIndex) const;
152	void								createListPrimitives	(int						primitiveCount,
153																 float						originX,
154																 float						originY,
155																 float						primitiveSizeX,
156																 float						primitiveSizeY,
157																 int						verticesPerPrimitive,
158																 VkIndexType				indexType,
159																 std::vector<deUint32>&		indexData,
160																 std::vector<Vertex4RGBA>&	vertexData,
161																 std::vector<deUint32>		adjacencies) const;
162
163	std::vector<deUint32>				m_restartPrimitives;
164	RestartType							m_restartType;
165};
166#endif // CTS_USES_VULKANSC
167
168
169class InputAssemblyInstance : public vkt::TestInstance
170{
171public:
172										InputAssemblyInstance	(Context&							context,
173																 const PipelineConstructionType		pipelineConstructionType,
174																 const VkPrimitiveTopology			primitiveTopology,
175																 bool								testPrimitiveRestart,
176																 VkIndexType						indexType,
177																 const std::vector<deUint32>&		indexBufferData,
178																 const std::vector<Vertex4RGBA>&	vertexBufferData);
179	virtual								~InputAssemblyInstance	(void);
180	virtual tcu::TestStatus				iterate					(void);
181
182private:
183	tcu::TestStatus						verifyImage				(void);
184	void								uploadIndexBufferData16	(deUint16* destPtr, const std::vector<deUint32>& indexBufferData);
185	void								uploadIndexBufferData8	(deUint8* destPtr, const std::vector<deUint32>& indexBufferData);
186
187	VkPrimitiveTopology					m_primitiveTopology;
188	bool								m_primitiveRestartEnable;
189	VkIndexType							m_indexType;
190
191	Move<VkBuffer>						m_vertexBuffer;
192	std::vector<Vertex4RGBA>			m_vertices;
193	de::MovePtr<Allocation>				m_vertexBufferAlloc;
194
195	Move<VkBuffer>						m_indexBuffer;
196	std::vector<deUint32>				m_indices;
197	de::MovePtr<Allocation>				m_indexBufferAlloc;
198
199	const tcu::UVec2					m_renderSize;
200
201	const VkFormat						m_colorFormat;
202	VkImageCreateInfo					m_colorImageCreateInfo;
203	Move<VkImage>						m_colorImage;
204	de::MovePtr<Allocation>				m_colorImageAlloc;
205	Move<VkImageView>					m_colorAttachmentView;
206	RenderPassWrapper					m_renderPass;
207	Move<VkFramebuffer>					m_framebuffer;
208
209	ShaderWrapper						m_vertexShaderModule;
210	ShaderWrapper						m_fragmentShaderModule;
211	ShaderWrapper						m_tcsShaderModule;
212	ShaderWrapper						m_tesShaderModule;
213
214	PipelineLayoutWrapper				m_pipelineLayout;
215	GraphicsPipelineWrapper				m_graphicsPipeline;
216
217	Move<VkCommandPool>					m_cmdPool;
218	Move<VkCommandBuffer>				m_cmdBuffer;
219};
220
221
222// InputAssemblyTest
223
224const VkPrimitiveTopology InputAssemblyTest::s_primitiveTopologies[] =
225{
226	VK_PRIMITIVE_TOPOLOGY_POINT_LIST,
227	VK_PRIMITIVE_TOPOLOGY_LINE_LIST,
228	VK_PRIMITIVE_TOPOLOGY_LINE_STRIP,
229	VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
230	VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP,
231	VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN,
232	VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY,
233	VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY,
234	VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY,
235	VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY
236};
237
238const deUint32 InputAssemblyTest::s_restartIndex32	= ~((deUint32)0u);
239const deUint16 InputAssemblyTest::s_restartIndex16	= ~((deUint16)0u);
240const deUint8 InputAssemblyTest::s_restartIndex8	= ~((deUint8)0u);
241
242InputAssemblyTest::InputAssemblyTest (tcu::TestContext&					testContext,
243									  const std::string&				name,
244									  const PipelineConstructionType	pipelineConstructionType,
245									  VkPrimitiveTopology				primitiveTopology,
246									  int								primitiveCount,
247									  bool								testPrimitiveRestart,
248									  VkIndexType						indexType)
249	: vkt::TestCase				(testContext, name)
250	, m_primitiveTopology		(primitiveTopology)
251	, m_primitiveCount(primitiveCount)
252	, m_pipelineConstructionType(pipelineConstructionType)
253	, m_testPrimitiveRestart	(testPrimitiveRestart)
254	, m_indexType				(indexType)
255{
256}
257
258void InputAssemblyTest::checkSupport (Context& context) const
259{
260	if (m_indexType == VK_INDEX_TYPE_UINT8_EXT)
261		context.requireDeviceFunctionality("VK_EXT_index_type_uint8");
262
263	switch (m_primitiveTopology)
264	{
265		case VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY:
266		case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY:
267		case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY:
268		case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY:
269			context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_GEOMETRY_SHADER);
270			break;
271
272		case VK_PRIMITIVE_TOPOLOGY_PATCH_LIST:
273			context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_TESSELLATION_SHADER);
274			break;
275
276		default:
277			break;
278	}
279
280	checkPipelineConstructionRequirements(context.getInstanceInterface(), context.getPhysicalDevice(), m_pipelineConstructionType);
281
282#ifndef CTS_USES_VULKANSC
283	if (m_primitiveTopology == VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN &&
284		context.isDeviceFunctionalitySupported("VK_KHR_portability_subset") &&
285		!context.getPortabilitySubsetFeatures().triangleFans)
286	{
287		TCU_THROW(NotSupportedError, "VK_KHR_portability_subset: Triangle fans are not supported by this implementation");
288	}
289#endif // CTS_USES_VULKANSC
290}
291
292TestInstance* InputAssemblyTest::createInstance (Context& context) const
293{
294	std::vector<deUint32>		indexBufferData;
295	std::vector<Vertex4RGBA>	vertexBufferData;
296
297	createBufferData(m_primitiveTopology, m_primitiveCount, m_indexType, indexBufferData, vertexBufferData);
298
299	return new InputAssemblyInstance(context, m_pipelineConstructionType, m_primitiveTopology, m_testPrimitiveRestart, m_indexType, indexBufferData, vertexBufferData);
300}
301
302void InputAssemblyTest::initPrograms (SourceCollections& sourceCollections) const
303{
304	std::ostringstream vertexSource;
305
306	vertexSource <<
307		"#version 310 es\n"
308		"layout(location = 0) in vec4 position;\n"
309		"layout(location = 1) in vec4 color;\n"
310		"layout(location = 0) out highp vec4 vtxColor;\n"
311		"void main (void)\n"
312		"{\n"
313		"	gl_Position = position;\n"
314		<< (m_primitiveTopology == VK_PRIMITIVE_TOPOLOGY_POINT_LIST ? "	gl_PointSize = 3.0;\n"
315																	: "" )
316		<< "	vtxColor = color;\n"
317		"}\n";
318
319	sourceCollections.glslSources.add("color_vert") << glu::VertexSource(vertexSource.str());
320
321	sourceCollections.glslSources.add("color_frag") << glu::FragmentSource(
322		"#version 310 es\n"
323		"layout(location = 0) in highp vec4 vtxColor;\n"
324		"layout(location = 0) out highp vec4 fragColor;\n"
325		"void main (void)\n"
326		"{\n"
327		"	fragColor = vtxColor;\n"
328		"}\n");
329
330	sourceCollections.glslSources.add("color_tcs") << glu::TessellationControlSource(
331		"#version 310 es\n"
332		"#extension GL_EXT_tessellation_shader : require\n"
333		"layout(vertices = 3) out;\n"
334		"layout(location = 0) in highp vec4 vtxColorIn[];\n"
335		"layout(location = 0) out highp vec4 vtxColorOut[];\n"
336		"#define ID gl_InvocationID\n"
337		"void main (void)\n"
338		"{\n"
339		"	vtxColorOut[ID] = vtxColorIn[ID];\n"
340		"	gl_out[ID].gl_Position = gl_in[ID].gl_Position;\n"
341		"	if (ID == 0)\n"
342		"	{\n"
343		"		gl_TessLevelInner[0] = 5.0;\n"
344		"		gl_TessLevelOuter[0] = 4.0;\n"
345		"		gl_TessLevelOuter[1] = 5.0;\n"
346		"		gl_TessLevelOuter[2] = 6.0;\n"
347		"	}\n"
348		"}\n");
349
350	sourceCollections.glslSources.add("color_tes") << glu::TessellationEvaluationSource(
351		"#version 310 es\n"
352		"#extension GL_EXT_tessellation_shader : require\n"
353		"layout(triangles) in;\n"
354		"layout(location = 0) in vec4 vtxColorIn[];\n"
355		"layout(location = 0) out vec4 vtxColorOut;\n"
356		"void main (void)\n"
357		"{\n"
358		"	vec4 p0 = gl_TessCoord.x * gl_in[0].gl_Position;\n"
359		"	vec4 p1 = gl_TessCoord.y * gl_in[1].gl_Position;\n"
360		"	vec4 p2 = gl_TessCoord.z * gl_in[2].gl_Position;\n"
361		"	gl_Position = p0 + p1 + p2;\n"
362		"	vec4 q0 = gl_TessCoord.x * vtxColorIn[0];\n"
363		"	vec4 q1 = gl_TessCoord.y * vtxColorIn[1];\n"
364		"	vec4 q2 = gl_TessCoord.z * vtxColorIn[2];\n"
365		"	vtxColorOut = q0 + q1 + q2;\n"
366		"}\n");
367}
368
369bool InputAssemblyTest::isRestartIndex (VkIndexType indexType, deUint32 indexValue)
370{
371	if (indexType == VK_INDEX_TYPE_UINT16)
372		return indexValue == s_restartIndex16;
373	else if (indexType == VK_INDEX_TYPE_UINT8_EXT)
374		return indexValue == s_restartIndex8;
375	else
376		return indexValue == s_restartIndex32;
377}
378
379#ifndef CTS_USES_VULKANSC
380deUint32 InputAssemblyTest::getRestartIndex (VkIndexType indexType)
381{
382	if (indexType == VK_INDEX_TYPE_UINT16)
383		return InputAssemblyTest::s_restartIndex16;
384	else if (indexType == VK_INDEX_TYPE_UINT8_EXT)
385		return InputAssemblyTest::s_restartIndex8;
386	else
387		return InputAssemblyTest::s_restartIndex32;
388}
389#endif // CTS_USES_VULKANSC
390
391// PrimitiveTopologyTest
392
393PrimitiveTopologyTest::PrimitiveTopologyTest (tcu::TestContext&			testContext,
394											  const std::string&		name,
395											  PipelineConstructionType	pipelineConstructionType,
396											  VkPrimitiveTopology		primitiveTopology,
397											  VkIndexType				indexType)
398	: InputAssemblyTest	(testContext, name, pipelineConstructionType, primitiveTopology, 10, false, indexType)
399{
400}
401
402void PrimitiveTopologyTest::createBufferData (VkPrimitiveTopology topology, int primitiveCount, VkIndexType indexType, std::vector<deUint32>& indexData, std::vector<Vertex4RGBA>& vertexData) const
403{
404	DE_ASSERT(primitiveCount > 0);
405	DE_UNREF(indexType);
406
407	const tcu::Vec4				red						(1.0f, 0.0f, 0.0f, 1.0f);
408	const tcu::Vec4				green					(0.0f, 1.0f, 0.0f, 1.0f);
409	const float					border					= 0.2f;
410	const float					originX					= -1.0f + border;
411	const float					originY					= -1.0f + border;
412	const Vertex4RGBA			defaultVertex			= { tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f), green };
413	float						primitiveSizeY			= (2.0f - 2.0f * border);
414	float						primitiveSizeX;
415	std::vector<deUint32>		indices;
416	std::vector<Vertex4RGBA>	vertices;
417
418
419	// Calculate primitive size
420	switch (topology)
421	{
422		case VK_PRIMITIVE_TOPOLOGY_POINT_LIST:
423			primitiveSizeX = (2.0f - 2.0f * border) / float(primitiveCount / 2 + primitiveCount % 2 - 1);
424			break;
425
426		case VK_PRIMITIVE_TOPOLOGY_LINE_LIST:
427		case VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY:
428			primitiveSizeX = (2.0f - 2.0f * border) / float(primitiveCount - 1);
429			break;
430
431		case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP:
432		case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY:
433			primitiveSizeX = (2.0f - 2.0f * border) / float(primitiveCount / 2);
434			break;
435
436		case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
437		case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY:
438			primitiveSizeX = (2.0f - 2.0f * border) / float(primitiveCount + primitiveCount / 2 + primitiveCount % 2 - 1);
439			break;
440
441		case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
442		case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY:
443			primitiveSizeX = (2.0f - 2.0f * border) / float(primitiveCount / 2 + primitiveCount % 2);
444			break;
445
446		case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN:
447			primitiveSizeX = 1.0f - border;
448			primitiveSizeY = 1.0f - border;
449			break;
450
451		default:
452			primitiveSizeX = 0.0f; // Garbage
453			DE_ASSERT(false);
454	}
455
456	switch (topology)
457	{
458		case VK_PRIMITIVE_TOPOLOGY_POINT_LIST:
459			for (int primitiveNdx = 0; primitiveNdx < primitiveCount; primitiveNdx++)
460			{
461				const Vertex4RGBA vertex =
462				{
463					tcu::Vec4(originX + float(primitiveNdx / 2) * primitiveSizeX, originY + float(primitiveNdx % 2) * primitiveSizeY, 0.0f, 1.0f),
464					red
465				};
466
467				vertices.push_back(vertex);
468				indices.push_back(primitiveNdx);
469			}
470			break;
471
472		case VK_PRIMITIVE_TOPOLOGY_LINE_LIST:
473			for (int primitiveNdx = 0; primitiveNdx < primitiveCount; primitiveNdx++)
474			{
475				for (int vertexNdx = 0; vertexNdx < 2; vertexNdx++)
476				{
477					const Vertex4RGBA vertex =
478					{
479						tcu::Vec4(originX + float((primitiveNdx * 2 + vertexNdx) / 2) * primitiveSizeX, originY + float(vertexNdx % 2) * primitiveSizeY, 0.0f, 1.0f),
480						red
481					};
482
483					vertices.push_back(vertex);
484					indices.push_back((primitiveNdx * 2 + vertexNdx));
485				}
486			}
487			break;
488
489		case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP:
490			for (int primitiveNdx = 0; primitiveNdx < primitiveCount; primitiveNdx++)
491			{
492				if (primitiveNdx == 0)
493				{
494					Vertex4RGBA vertex =
495					{
496						tcu::Vec4(originX, originY, 0.0f, 1.0f),
497						red
498					};
499
500					vertices.push_back(vertex);
501					indices.push_back(0);
502
503					vertex.position = tcu::Vec4(originX, originY + primitiveSizeY, 0.0f, 1.0f);
504					vertices.push_back(vertex);
505					indices.push_back(1);
506				}
507				else
508				{
509					const Vertex4RGBA vertex =
510					{
511						tcu::Vec4(originX + float((primitiveNdx + 1) / 2) * primitiveSizeX, originY + float((primitiveNdx + 1) % 2) * primitiveSizeY, 0.0f, 1.0f),
512						red
513					};
514
515					vertices.push_back(vertex);
516					indices.push_back(primitiveNdx + 1);
517				}
518			}
519			break;
520
521		case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
522			for (int primitiveNdx = 0; primitiveNdx < primitiveCount; primitiveNdx++)
523			{
524				for (int vertexNdx = 0; vertexNdx < 3; vertexNdx++)
525				{
526					const Vertex4RGBA vertex =
527					{
528						tcu::Vec4(originX + float((primitiveNdx * 3 + vertexNdx) / 2) * primitiveSizeX, originY + float((primitiveNdx * 3 + vertexNdx)% 2) * primitiveSizeY, 0.0f, 1.0f),
529						red
530					};
531
532					vertices.push_back(vertex);
533					indices.push_back(primitiveNdx * 3 + vertexNdx);
534				}
535			}
536			break;
537
538		case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
539			for (int primitiveNdx = 0; primitiveNdx < primitiveCount; primitiveNdx++)
540			{
541				if (primitiveNdx == 0)
542				{
543					for (int vertexNdx = 0; vertexNdx < 3; vertexNdx++)
544					{
545						const Vertex4RGBA vertex =
546						{
547							tcu::Vec4(originX + float(vertexNdx / 2) * primitiveSizeX, originY + float(vertexNdx % 2) * primitiveSizeY, 0.0f, 1.0f),
548							red
549						};
550
551						vertices.push_back(vertex);
552						indices.push_back(vertexNdx);
553					}
554				}
555				else
556				{
557					const Vertex4RGBA vertex =
558					{
559						tcu::Vec4(originX + float((primitiveNdx + 2) / 2) * primitiveSizeX, originY + float((primitiveNdx + 2) % 2) * primitiveSizeY, 0.0f, 1.0f),
560						red
561					};
562
563					vertices.push_back(vertex);
564					indices.push_back(primitiveNdx + 2);
565				}
566			}
567			break;
568
569		case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN:
570		{
571			const float stepAngle = de::min(DE_PI * 0.5f, (2 * DE_PI) / float(primitiveCount));
572
573			for (int primitiveNdx = 0; primitiveNdx < primitiveCount; primitiveNdx++)
574			{
575				if (primitiveNdx == 0)
576				{
577					Vertex4RGBA vertex =
578					{
579						tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f),
580						red
581					};
582
583					vertices.push_back(vertex);
584					indices.push_back(0);
585
586					vertex.position = tcu::Vec4(primitiveSizeX, 0.0f, 0.0f, 1.0f);
587					vertices.push_back(vertex);
588					indices.push_back(1);
589
590					vertex.position = tcu::Vec4(primitiveSizeX * deFloatCos(stepAngle), primitiveSizeY * deFloatSin(stepAngle), 0.0f, 1.0f);
591					vertices.push_back(vertex);
592					indices.push_back(2);
593				}
594				else
595				{
596					const Vertex4RGBA vertex =
597					{
598						tcu::Vec4(primitiveSizeX * deFloatCos(stepAngle * float(primitiveNdx + 1)), primitiveSizeY * deFloatSin(stepAngle * float(primitiveNdx + 1)), 0.0f, 1.0f),
599						red
600					};
601
602					vertices.push_back(vertex);
603					indices.push_back(primitiveNdx + 2);
604				}
605			}
606			break;
607		}
608
609		case VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY:
610			vertices.push_back(defaultVertex);
611
612			for (int primitiveNdx = 0; primitiveNdx < primitiveCount; primitiveNdx++)
613			{
614				indices.push_back(0);
615
616				for (int vertexNdx = 0; vertexNdx < 2; vertexNdx++)
617				{
618					const Vertex4RGBA vertex =
619					{
620						tcu::Vec4(originX + float((primitiveNdx * 2 + vertexNdx) / 2) * primitiveSizeX, originY + float(vertexNdx % 2) * primitiveSizeY, 0.0f, 1.0f),
621						red
622					};
623
624					vertices.push_back(vertex);
625					indices.push_back(primitiveNdx * 2 + vertexNdx + 1);
626				}
627
628				indices.push_back(0);
629			}
630			break;
631
632
633		case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY:
634			vertices.push_back(defaultVertex);
635			indices.push_back(0);
636
637			for (int primitiveNdx = 0; primitiveNdx < primitiveCount; primitiveNdx++)
638			{
639				if (primitiveNdx == 0)
640				{
641					Vertex4RGBA vertex =
642					{
643						tcu::Vec4(originX, originY, 0.0f, 1.0f),
644						red
645					};
646
647					vertices.push_back(vertex);
648					indices.push_back(1);
649
650					vertex.position = tcu::Vec4(originX, originY + primitiveSizeY, 0.0f, 1.0f);
651					vertices.push_back(vertex);
652					indices.push_back(2);
653				}
654				else
655				{
656					const Vertex4RGBA vertex =
657					{
658						tcu::Vec4(originX + float((primitiveNdx + 1) / 2) * primitiveSizeX, originY + float((primitiveNdx + 1) % 2) * primitiveSizeY, 0.0f, 1.0f),
659						red
660					};
661
662					vertices.push_back(vertex);
663					indices.push_back(primitiveNdx + 2);
664				}
665			}
666
667			indices.push_back(0);
668			break;
669
670		case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY:
671			vertices.push_back(defaultVertex);
672
673			for (int primitiveNdx = 0; primitiveNdx < primitiveCount; primitiveNdx++)
674			{
675				for (int vertexNdx = 0; vertexNdx < 3; vertexNdx++)
676				{
677					const Vertex4RGBA vertex =
678					{
679						tcu::Vec4(originX + float((primitiveNdx * 3 + vertexNdx) / 2) * primitiveSizeX, originY + float((primitiveNdx * 3 + vertexNdx)% 2) * primitiveSizeY, 0.0f, 1.0f),
680						red
681					};
682
683					vertices.push_back(vertex);
684					indices.push_back(primitiveNdx * 3 + vertexNdx + 1);
685					indices.push_back(0);
686				}
687			}
688			break;
689
690		case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY:
691			vertices.push_back(defaultVertex);
692
693			for (int primitiveNdx = 0; primitiveNdx < primitiveCount; primitiveNdx++)
694			{
695				if (primitiveNdx == 0)
696				{
697					for (int vertexNdx = 0; vertexNdx < 3; vertexNdx++)
698					{
699						const Vertex4RGBA vertex =
700						{
701							tcu::Vec4(originX + float(vertexNdx / 2) * primitiveSizeX, originY + float(vertexNdx % 2) * primitiveSizeY, 0.0f, 1.0f),
702							red
703						};
704
705						vertices.push_back(vertex);
706						indices.push_back(vertexNdx + 1);
707						indices.push_back(0);
708					}
709				}
710				else
711				{
712					const Vertex4RGBA vertex =
713					{
714						tcu::Vec4(originX + float((primitiveNdx + 2) / 2) * primitiveSizeX, originY + float((primitiveNdx + 2) % 2) * primitiveSizeY, 0.0f, 1.0f),
715						red
716					};
717
718					vertices.push_back(vertex);
719					indices.push_back(primitiveNdx + 2 + 1);
720					indices.push_back(0);
721				}
722			}
723			break;
724
725		default:
726			DE_ASSERT(false);
727			break;
728	}
729
730	vertexData	= vertices;
731	indexData	= indices;
732}
733
734#ifndef CTS_USES_VULKANSC
735// PrimitiveRestartTest
736
737PrimitiveRestartTest::PrimitiveRestartTest (tcu::TestContext&			testContext,
738											const std::string&			name,
739											PipelineConstructionType	pipelineConstructionType,
740											VkPrimitiveTopology			primitiveTopology,
741											VkIndexType					indexType,
742											RestartType					restartType)
743
744	: InputAssemblyTest	(testContext, name, pipelineConstructionType, primitiveTopology, 10, true, indexType)
745	, m_restartType(restartType)
746{
747	deUint32 restartPrimitives[] = { 1, 5 };
748
749	if (restartType == RestartType::NORMAL)
750	{
751		m_restartPrimitives = std::vector<deUint32>(restartPrimitives, restartPrimitives + sizeof(restartPrimitives) / sizeof(deUint32));
752	}
753	else if (restartType == RestartType::NONE)
754	{
755		m_restartPrimitives = std::vector<deUint32>{};
756	}
757	else
758	{
759		deUint32 count = 1;
760		switch (primitiveTopology)
761		{
762			case VK_PRIMITIVE_TOPOLOGY_LINE_LIST:
763			case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP:
764			case VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY:
765			case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY:
766				count = 2;
767				break;
768			case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
769			case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
770			case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN:
771			case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY:
772			case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY:
773				count = 3;
774				break;
775			default:
776				break;
777		}
778		for (deUint32 i = 0; i < (deUint32)m_primitiveCount; ++i)
779		{
780			if (i % count == count - 1)
781			{
782				m_restartPrimitives.push_back(i);
783			}
784		}
785	}
786}
787
788void PrimitiveRestartTest::checkSupport (Context& context) const
789{
790	switch (m_primitiveTopology)
791	{
792		case VK_PRIMITIVE_TOPOLOGY_PATCH_LIST:
793		case VK_PRIMITIVE_TOPOLOGY_POINT_LIST:
794		case VK_PRIMITIVE_TOPOLOGY_LINE_LIST:
795		case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
796		case VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY:
797		case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY:
798		{
799			context.requireDeviceFunctionality("VK_EXT_primitive_topology_list_restart");
800
801			const auto& features = context.getPrimitiveTopologyListRestartFeaturesEXT();
802			if (!features.primitiveTopologyListRestart)
803				TCU_THROW(NotSupportedError, "Primitive topology list restart feature not supported");
804			if (m_primitiveTopology == VK_PRIMITIVE_TOPOLOGY_PATCH_LIST && !features.primitiveTopologyPatchListRestart)
805				TCU_THROW(NotSupportedError, "Primitive topology patch list restart feature not supported");
806		}
807		break;
808
809		default:
810		break;
811	}
812
813	InputAssemblyTest::checkSupport(context);
814}
815
816void PrimitiveRestartTest::createBufferData (VkPrimitiveTopology topology, int primitiveCount, VkIndexType indexType, std::vector<deUint32>& indexData, std::vector<Vertex4RGBA>& vertexData) const
817{
818	DE_ASSERT(primitiveCount > 0);
819	DE_UNREF(indexType);
820
821	const tcu::Vec4				red						(1.0f, 0.0f, 0.0f, 1.0f);
822	const tcu::Vec4				green					(0.0f, 1.0f, 0.0f, 1.0f);
823	const float					border					= 0.2f;
824	const float					originX					= -1.0f + border;
825	const float					originY					= -1.0f + border;
826	const Vertex4RGBA			defaultVertex			= { tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f), green };
827	float						primitiveSizeY			= (2.0f - 2.0f * border);
828	float						primitiveSizeX;
829	bool						primitiveStart			= true;
830	std::vector<deUint32>		indices;
831	std::vector<Vertex4RGBA>	vertices;
832
833	// Calculate primitive size
834	switch (topology)
835	{
836		case VK_PRIMITIVE_TOPOLOGY_POINT_LIST:
837			primitiveSizeX = (2.0f - 2.0f * border) / float(primitiveCount / 2 + primitiveCount % 2 - 1);
838			break;
839
840		case VK_PRIMITIVE_TOPOLOGY_LINE_LIST:
841		case VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY:
842		case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP:
843		case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY:
844			primitiveSizeX = (2.0f - 2.0f * border) / float(primitiveCount / 2);
845			break;
846
847		case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
848		case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY:
849		case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
850		case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY:
851		case VK_PRIMITIVE_TOPOLOGY_PATCH_LIST:
852			primitiveSizeX = (2.0f - 2.0f * border) / float(primitiveCount / 2 + primitiveCount % 2);
853			break;
854
855		case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN:
856			primitiveSizeX = 1.0f - border;
857			primitiveSizeY = 1.0f - border;
858			break;
859
860		default:
861			primitiveSizeX = 0.0f; // Garbage
862			DE_ASSERT(false);
863	}
864
865	switch (topology)
866	{
867		case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP:
868			for (int primitiveNdx = 0; primitiveNdx < primitiveCount; primitiveNdx++)
869			{
870				if (isRestartPrimitive(primitiveNdx))
871				{
872					indices.push_back(InputAssemblyTest::getRestartIndex(indexType));
873					primitiveStart = true;
874				}
875				else
876				{
877					if (primitiveStart && m_restartType != RestartType::ALL)
878					{
879						const Vertex4RGBA vertex =
880						{
881							tcu::Vec4(originX + float(primitiveNdx / 2) * primitiveSizeX, originY + float(primitiveNdx % 2) * primitiveSizeY, 0.0f, 1.0f),
882							red
883						};
884
885						vertices.push_back(vertex);
886						indices.push_back((deUint32)vertices.size() - 1);
887
888						primitiveStart = false;
889					}
890
891					const Vertex4RGBA vertex =
892					{
893						tcu::Vec4(originX + float((primitiveNdx + 1) / 2) * primitiveSizeX, originY + float((primitiveNdx + 1) % 2) * primitiveSizeY, 0.0f, 1.0f),
894						red
895					};
896
897					vertices.push_back(vertex);
898					indices.push_back((deUint32)vertices.size() - 1);
899				}
900			}
901			break;
902
903		case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
904		{
905			for (int primitiveNdx = 0; primitiveNdx < primitiveCount; primitiveNdx++)
906			{
907				if (isRestartPrimitive(primitiveNdx))
908				{
909					indices.push_back(InputAssemblyTest::getRestartIndex(indexType));
910					primitiveStart = true;
911				}
912				else
913				{
914					if (primitiveStart && m_restartType != RestartType::ALL)
915					{
916						for (int vertexNdx = 0; vertexNdx < 2; vertexNdx++)
917						{
918							const Vertex4RGBA vertex =
919							{
920								tcu::Vec4(originX + float((primitiveNdx + vertexNdx) / 2) * primitiveSizeX, originY + float((primitiveNdx + vertexNdx) % 2) * primitiveSizeY, 0.0f, 1.0f),
921								red
922							};
923
924							vertices.push_back(vertex);
925							indices.push_back((deUint32)vertices.size() - 1);
926						}
927
928						primitiveStart = false;
929					}
930					const Vertex4RGBA vertex =
931					{
932						tcu::Vec4(originX + float((primitiveNdx + 2) / 2) * primitiveSizeX, originY + float((primitiveNdx + 2) % 2) * primitiveSizeY, 0.0f, 1.0f),
933						red
934					};
935
936					vertices.push_back(vertex);
937					indices.push_back((deUint32)vertices.size() - 1);
938				}
939			}
940			break;
941		}
942
943		case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN:
944		{
945			const float stepAngle = de::min(DE_PI * 0.5f, (2 * DE_PI) / float(primitiveCount));
946
947			for (int primitiveNdx = 0; primitiveNdx < primitiveCount; primitiveNdx++)
948			{
949				if (isRestartPrimitive(primitiveNdx))
950				{
951					indices.push_back(InputAssemblyTest::getRestartIndex(indexType));
952					primitiveStart = true;
953				}
954				else
955				{
956					if (primitiveStart && m_restartType != RestartType::ALL)
957					{
958						Vertex4RGBA vertex =
959						{
960							tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f),
961							red
962						};
963
964						vertices.push_back(vertex);
965						indices.push_back((deUint32)vertices.size() - 1);
966
967						vertex.position = tcu::Vec4(primitiveSizeX * deFloatCos(stepAngle * float(primitiveNdx)), primitiveSizeY * deFloatSin(stepAngle * float(primitiveNdx)), 0.0f, 1.0f);
968						vertices.push_back(vertex);
969						indices.push_back((deUint32)vertices.size() - 1);
970
971						primitiveStart = false;
972					}
973
974					const Vertex4RGBA vertex =
975					{
976						tcu::Vec4(primitiveSizeX * deFloatCos(stepAngle * float(primitiveNdx + 1)), primitiveSizeY * deFloatSin(stepAngle * float(primitiveNdx + 1)), 0.0f, 1.0f),
977						red
978					};
979
980					vertices.push_back(vertex);
981					indices.push_back((deUint32)vertices.size() - 1);
982				}
983			}
984			break;
985		}
986
987		case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY:
988			vertices.push_back(defaultVertex);
989
990			for (int primitiveNdx = 0; primitiveNdx < primitiveCount; primitiveNdx++)
991			{
992				if (isRestartPrimitive(primitiveNdx))
993				{
994					indices.push_back(0);
995					indices.push_back(InputAssemblyTest::getRestartIndex(indexType));
996					primitiveStart = true;
997				}
998				else
999				{
1000					if (primitiveStart && m_restartType != RestartType::ALL)
1001					{
1002						indices.push_back(0);
1003
1004						const Vertex4RGBA vertex =
1005						{
1006							tcu::Vec4(originX + float(primitiveNdx / 2) * primitiveSizeX, originY + float(primitiveNdx % 2) * primitiveSizeY, 0.0f, 1.0f),
1007							red
1008						};
1009
1010						vertices.push_back(vertex);
1011						indices.push_back((deUint32)vertices.size() - 1);
1012
1013						primitiveStart = false;
1014					}
1015
1016					const Vertex4RGBA vertex =
1017					{
1018						tcu::Vec4(originX + float((primitiveNdx + 1) / 2) * primitiveSizeX, originY + float((primitiveNdx + 1) % 2) * primitiveSizeY, 0.0f, 1.0f),
1019						red
1020					};
1021
1022					vertices.push_back(vertex);
1023					indices.push_back((deUint32)vertices.size() - 1);
1024				}
1025			}
1026
1027			indices.push_back(0);
1028			break;
1029
1030		case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY:
1031			vertices.push_back(defaultVertex);
1032
1033			for (int primitiveNdx = 0; primitiveNdx < primitiveCount; primitiveNdx++)
1034			{
1035				if (isRestartPrimitive(primitiveNdx))
1036				{
1037					indices.push_back(InputAssemblyTest::getRestartIndex(indexType));
1038					primitiveStart = true;
1039				}
1040				else
1041				{
1042					if (primitiveStart && m_restartType != RestartType::ALL)
1043					{
1044						for (int vertexNdx = 0; vertexNdx < 2; vertexNdx++)
1045						{
1046							const Vertex4RGBA vertex =
1047							{
1048								tcu::Vec4(originX + float((primitiveNdx + vertexNdx) / 2) * primitiveSizeX, originY + float((primitiveNdx + vertexNdx) % 2) * primitiveSizeY, 0.0f, 1.0f),
1049								red
1050							};
1051
1052							vertices.push_back(vertex);
1053							indices.push_back((deUint32)vertices.size() - 1);
1054							indices.push_back(0);
1055						}
1056
1057						primitiveStart = false;
1058					}
1059
1060					const Vertex4RGBA vertex =
1061					{
1062						tcu::Vec4(originX + float((primitiveNdx + 2) / 2) * primitiveSizeX, originY + float((primitiveNdx + 2) % 2) * primitiveSizeY, 0.0f, 1.0f),
1063						red
1064					};
1065
1066					vertices.push_back(vertex);
1067					indices.push_back((deUint32)vertices.size() - 1);
1068					indices.push_back(0);
1069				}
1070			}
1071			break;
1072
1073		case VK_PRIMITIVE_TOPOLOGY_POINT_LIST:
1074			createListPrimitives(primitiveCount, originX, originY, primitiveSizeX, primitiveSizeY,
1075								 1, indexType, indices, vertices, std::vector<deUint32>());
1076			break;
1077
1078		case VK_PRIMITIVE_TOPOLOGY_LINE_LIST:
1079			createListPrimitives(primitiveCount, originX, originY, primitiveSizeX, primitiveSizeY,
1080								 2, indexType, indices, vertices, std::vector<deUint32>());
1081			break;
1082
1083		case VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY:
1084		{
1085			std::vector<deUint32> adjacencies = { 0, 3 };
1086
1087			createListPrimitives(primitiveCount, originX, originY, primitiveSizeX, primitiveSizeY,
1088								 4, indexType, indices, vertices, adjacencies);
1089		}
1090		break;
1091
1092		case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
1093		case VK_PRIMITIVE_TOPOLOGY_PATCH_LIST:
1094			createListPrimitives(primitiveCount, originX, originY, primitiveSizeX, primitiveSizeY,
1095						3, indexType, indices, vertices, std::vector<deUint32>());
1096			break;
1097
1098		case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY:
1099		{
1100			std::vector<deUint32> adjacencies = { 1, 3, 5 };
1101
1102			createListPrimitives(primitiveCount, originX, originY, primitiveSizeX, primitiveSizeY,
1103								 6, indexType, indices, vertices, adjacencies);
1104		}
1105		break;
1106
1107		default:
1108			DE_ASSERT(false);
1109			break;
1110	}
1111
1112	vertexData	= vertices;
1113	indexData	= indices;
1114}
1115
1116void PrimitiveRestartTest::createListPrimitives (int						primitiveCount,
1117												 float						originX,
1118												 float						originY,
1119												 float						primitiveSizeX,
1120												 float						primitiveSizeY,
1121												 int						verticesPerPrimitive,
1122												 VkIndexType				indexType,
1123												 std::vector<deUint32>&		indexData,
1124												 std::vector<Vertex4RGBA>&	vertexData,
1125												 std::vector<deUint32>		adjacencies) const
1126{
1127	const tcu::Vec4	red		(1.0f, 0.0f, 0.0f, 1.0f);
1128	const tcu::Vec4	green	(0.0f, 1.0f, 0.0f, 1.0f);
1129	// Tells which vertex of a primitive is used as a restart index.
1130	// This is decreased each time a restart primitive is used.
1131	int restartVertexIndex = verticesPerPrimitive - 1;
1132
1133	for (int primitiveNdx = 0; primitiveNdx < primitiveCount; primitiveNdx++)
1134	{
1135		deUint32 nonAdjacentVertexNdx = 0;
1136
1137		for (int vertexNdx = 0; vertexNdx < verticesPerPrimitive; vertexNdx++)
1138		{
1139			if (isRestartPrimitive(primitiveNdx) && vertexNdx == restartVertexIndex)
1140			{
1141				indexData.push_back(InputAssemblyTest::getRestartIndex(indexType));
1142
1143				restartVertexIndex--;
1144				if (restartVertexIndex < 0) restartVertexIndex = verticesPerPrimitive - 1;
1145
1146				break;
1147			}
1148
1149			if (std::find(adjacencies.begin(), adjacencies.end(), vertexNdx) != adjacencies.end())
1150			{
1151				// This is an adjacency vertex index. Add a green vertex that should never end up to the framebuffer.
1152				const Vertex4RGBA vertex =
1153				{
1154					tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f),
1155					green
1156				};
1157				vertexData.push_back(vertex);
1158				indexData.push_back((deUint32) vertexData.size() - 1);
1159				continue;
1160			}
1161
1162			const Vertex4RGBA vertex =
1163			{
1164				tcu::Vec4(originX + float((primitiveNdx + nonAdjacentVertexNdx) / 2) * primitiveSizeX,
1165						  originY + float((primitiveNdx + nonAdjacentVertexNdx) % 2) * primitiveSizeY, 0.0f, 1.0f),
1166						  red
1167			};
1168
1169			vertexData.push_back(vertex);
1170			indexData.push_back((deUint32) vertexData.size() - 1);
1171			nonAdjacentVertexNdx++;
1172		}
1173	}
1174}
1175
1176bool PrimitiveRestartTest::isRestartPrimitive (int primitiveIndex) const
1177{
1178	return std::find(m_restartPrimitives.begin(), m_restartPrimitives.end(), primitiveIndex) != m_restartPrimitives.end();
1179}
1180#endif // CTS_USES_VULKANSC
1181
1182// InputAssemblyInstance
1183
1184InputAssemblyInstance::InputAssemblyInstance (Context&							context,
1185											  PipelineConstructionType			pipelineConstructionType,
1186											  VkPrimitiveTopology				primitiveTopology,
1187											  bool								testPrimitiveRestart,
1188											  VkIndexType						indexType,
1189											  const std::vector<deUint32>&		indexBufferData,
1190											  const std::vector<Vertex4RGBA>&	vertexBufferData)
1191
1192	: vkt::TestInstance			(context)
1193	, m_primitiveTopology		(primitiveTopology)
1194	, m_primitiveRestartEnable	(testPrimitiveRestart)
1195	, m_indexType				(indexType)
1196	, m_vertices				(vertexBufferData)
1197	, m_indices					(indexBufferData)
1198	, m_renderSize				((primitiveTopology == VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN) ? tcu::UVec2(32, 32) : tcu::UVec2(64, 16))
1199	, m_colorFormat				(VK_FORMAT_R8G8B8A8_UNORM)
1200	, m_graphicsPipeline		(context.getInstanceInterface(), context.getDeviceInterface(), context.getPhysicalDevice(), context.getDevice(), context.getDeviceExtensions(), pipelineConstructionType)
1201{
1202	const DeviceInterface&			vk						= context.getDeviceInterface();
1203	const VkDevice					vkDevice				= context.getDevice();
1204	const deUint32					queueFamilyIndex		= context.getUniversalQueueFamilyIndex();
1205	SimpleAllocator					memAlloc				(vk, vkDevice, getPhysicalDeviceMemoryProperties(context.getInstanceInterface(), context.getPhysicalDevice()));
1206	const VkComponentMapping		componentMappingRGBA	= { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A };
1207	const bool						patchList				= m_primitiveTopology == VK_PRIMITIVE_TOPOLOGY_PATCH_LIST;
1208
1209	// Create color image
1210	{
1211		const VkImageCreateInfo colorImageParams =
1212		{
1213			VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,										// VkStructureType			sType;
1214			DE_NULL,																	// const void*				pNext;
1215			0u,																			// VkImageCreateFlags		flags;
1216			VK_IMAGE_TYPE_2D,															// VkImageType				imageType;
1217			m_colorFormat,																// VkFormat					format;
1218			{ m_renderSize.x(), m_renderSize.y(), 1u },									// VkExtent3D				extent;
1219			1u,																			// deUint32					mipLevels;
1220			1u,																			// deUint32					arrayLayers;
1221			VK_SAMPLE_COUNT_1_BIT,														// VkSampleCountFlagBits	samples;
1222			VK_IMAGE_TILING_OPTIMAL,													// VkImageTiling			tiling;
1223			VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT,		// VkImageUsageFlags		usage;
1224			VK_SHARING_MODE_EXCLUSIVE,													// VkSharingMode			sharingMode;
1225			1u,																			// deUint32					queueFamilyIndexCount;
1226			&queueFamilyIndex,															// const deUint32*			pQueueFamilyIndices;
1227			VK_IMAGE_LAYOUT_UNDEFINED													// VkImageLayout			initialLayout;
1228		};
1229
1230		m_colorImageCreateInfo	= colorImageParams;
1231		m_colorImage			= createImage(vk, vkDevice, &m_colorImageCreateInfo);
1232
1233		// Allocate and bind color image memory
1234		m_colorImageAlloc		= memAlloc.allocate(getImageMemoryRequirements(vk, vkDevice, *m_colorImage), MemoryRequirement::Any);
1235		VK_CHECK(vk.bindImageMemory(vkDevice, *m_colorImage, m_colorImageAlloc->getMemory(), m_colorImageAlloc->getOffset()));
1236	}
1237
1238	// Create color attachment view
1239	{
1240		const VkImageViewCreateInfo colorAttachmentViewParams =
1241		{
1242			VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,			// VkStructureType			sType;
1243			DE_NULL,											// const void*				pNext;
1244			0u,													// VkImageViewCreateFlags	flags;
1245			*m_colorImage,										// VkImage					image;
1246			VK_IMAGE_VIEW_TYPE_2D,								// VkImageViewType			viewType;
1247			m_colorFormat,										// VkFormat					format;
1248			componentMappingRGBA,								// VkComponentMapping		components;
1249			{ VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u },		// VkImageSubresourceRange	subresourceRange;
1250		};
1251
1252		m_colorAttachmentView = createImageView(vk, vkDevice, &colorAttachmentViewParams);
1253	}
1254
1255	// Create render pass
1256	m_renderPass = RenderPassWrapper(pipelineConstructionType, vk, vkDevice, m_colorFormat);
1257
1258	// Create framebuffer
1259	{
1260		const VkFramebufferCreateInfo framebufferParams =
1261		{
1262			VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,			// VkStructureType			sType;
1263			DE_NULL,											// const void*				pNext;
1264			0u,													// VkFramebufferCreateFlags	flags;
1265			*m_renderPass,										// VkRenderPass				renderPass;
1266			1u,													// deUint32					attachmentCount;
1267			&m_colorAttachmentView.get(),						// const VkImageView*		pAttachments;
1268			(deUint32)m_renderSize.x(),							// deUint32					width;
1269			(deUint32)m_renderSize.y(),							// deUint32					height;
1270			1u													// deUint32					layers;
1271		};
1272
1273		m_renderPass.createFramebuffer(vk, vkDevice, &framebufferParams, *m_colorImage);
1274	}
1275
1276	// Create pipeline layout
1277	{
1278		const VkPipelineLayoutCreateInfo pipelineLayoutParams =
1279		{
1280			VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,		// VkStructureType					sType;
1281			DE_NULL,											// const void*						pNext;
1282			0u,													// VkPipelineLayoutCreateFlags		flags;
1283			0u,													// deUint32							setLayoutCount;
1284			DE_NULL,											// const VkDescriptorSetLayout*		pSetLayouts;
1285			0u,													// deUint32							pushConstantRangeCount;
1286			DE_NULL												// const VkPushConstantRange*		pPushConstantRanges;
1287		};
1288
1289		m_pipelineLayout = PipelineLayoutWrapper(pipelineConstructionType, vk, vkDevice, &pipelineLayoutParams);
1290	}
1291
1292	m_vertexShaderModule	= ShaderWrapper(vk, vkDevice, m_context.getBinaryCollection().get("color_vert"), 0);
1293	m_fragmentShaderModule	= ShaderWrapper(vk, vkDevice, m_context.getBinaryCollection().get("color_frag"), 0);
1294
1295	if (patchList)
1296	{
1297		m_tcsShaderModule = ShaderWrapper(vk, vkDevice, m_context.getBinaryCollection().get("color_tcs"), 0);
1298		m_tesShaderModule = ShaderWrapper(vk, vkDevice, m_context.getBinaryCollection().get("color_tes"), 0);
1299	}
1300
1301	// Create pipeline
1302	{
1303		const VkVertexInputBindingDescription vertexInputBindingDescription =
1304		{
1305			0u,								// deUint32					binding;
1306			sizeof(Vertex4RGBA),			// deUint32					stride;
1307			VK_VERTEX_INPUT_RATE_VERTEX		// VkVertexInputRate		inputRate;
1308		};
1309
1310		const VkVertexInputAttributeDescription vertexInputAttributeDescriptions[2] =
1311		{
1312			{
1313				0u,									// deUint32	location;
1314				0u,									// deUint32	binding;
1315				VK_FORMAT_R32G32B32A32_SFLOAT,		// VkFormat	format;
1316				0u									// deUint32	offset;
1317			},
1318			{
1319				1u,									// deUint32	location;
1320				0u,									// deUint32	binding;
1321				VK_FORMAT_R32G32B32A32_SFLOAT,		// VkFormat	format;
1322				DE_OFFSET_OF(Vertex4RGBA, color),	// deUint32	offset;
1323			}
1324		};
1325
1326		const VkPipelineVertexInputStateCreateInfo vertexInputStateParams =
1327		{
1328			VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,		// VkStructureType								sType;
1329			DE_NULL,														// const void*									pNext;
1330			0u,																// VkPipelineVertexInputStateCreateFlags		flags;
1331			1u,																// deUint32										vertexBindingDescriptionCount;
1332			&vertexInputBindingDescription,									// const VkVertexInputBindingDescription*		pVertexBindingDescriptions;
1333			2u,																// deUint32										vertexAttributeDescriptionCount;
1334			vertexInputAttributeDescriptions								// const VkVertexInputAttributeDescription*		pVertexAttributeDescriptions;
1335		};
1336
1337		const VkPipelineInputAssemblyStateCreateInfo inputAssemblyStateParams =
1338		{
1339			VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,	// VkStructureType							sType;
1340			DE_NULL,														// const void*								pNext;
1341			0u,																// VkPipelineInputAssemblyStateCreateFlags	flags;
1342			m_primitiveTopology,											// VkPrimitiveTopology						topology;
1343			m_primitiveRestartEnable										// VkBool32									primitiveRestartEnable;
1344		};
1345
1346		const std::vector<VkViewport>	viewport	{ makeViewport(m_renderSize) };
1347		const std::vector<VkRect2D>		scissor		{ makeRect2D(m_renderSize) };
1348
1349		const VkPipelineColorBlendAttachmentState colorBlendAttachmentState =
1350		{
1351			false,															// VkBool32					blendEnable;
1352			VK_BLEND_FACTOR_ONE,											// VkBlendFactor			srcColorBlendFactor;
1353			VK_BLEND_FACTOR_ZERO,											// VkBlendFactor			dstColorBlendFactor;
1354			VK_BLEND_OP_ADD,												// VkBlendOp				colorBlendOp;
1355			VK_BLEND_FACTOR_ONE,											// VkBlendFactor			srcAlphaBlendFactor;
1356			VK_BLEND_FACTOR_ZERO,											// VkBlendFactor			dstAlphaBlendFactor;
1357			VK_BLEND_OP_ADD,												// VkBlendOp				alphaBlendOp;
1358			VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |			// VkColorComponentFlags	colorWriteMask;
1359				VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT
1360		};
1361
1362		const VkPipelineColorBlendStateCreateInfo colorBlendStateParams =
1363		{
1364			VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,	// VkStructureType								sType;
1365			DE_NULL,													// const void*									pNext;
1366			0u,															// VkPipelineColorBlendStateCreateFlags			flags;
1367			false,														// VkBool32										logicOpEnable;
1368			VK_LOGIC_OP_COPY,											// VkLogicOp									logicOp;
1369			1u,															// deUint32										attachmentCount;
1370			&colorBlendAttachmentState,									// const VkPipelineColorBlendAttachmentState*	pAttachments;
1371			{ 0.0f, 0.0f, 0.0f, 0.0f }									// float										blendConstants[4];
1372		};
1373
1374		VkPipelineDepthStencilStateCreateInfo depthStencilStateParams =
1375		{
1376			VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,	// VkStructureType							sType;
1377			DE_NULL,													// const void*								pNext;
1378			0u,															// VkPipelineDepthStencilStateCreateFlags	flags;
1379			false,														// VkBool32									depthTestEnable;
1380			false,														// VkBool32									depthWriteEnable;
1381			VK_COMPARE_OP_LESS,											// VkCompareOp								depthCompareOp;
1382			false,														// VkBool32									depthBoundsTestEnable;
1383			false,														// VkBool32									stencilTestEnable;
1384			// VkStencilOpState	front;
1385			{
1386				VK_STENCIL_OP_KEEP,		// VkStencilOp	failOp;
1387				VK_STENCIL_OP_KEEP,		// VkStencilOp	passOp;
1388				VK_STENCIL_OP_KEEP,		// VkStencilOp	depthFailOp;
1389				VK_COMPARE_OP_NEVER,	// VkCompareOp	compareOp;
1390				0u,						// deUint32		compareMask;
1391				0u,						// deUint32		writeMask;
1392				0u,						// deUint32		reference;
1393			},
1394			// VkStencilOpState	back;
1395			{
1396				VK_STENCIL_OP_KEEP,		// VkStencilOp	failOp;
1397				VK_STENCIL_OP_KEEP,		// VkStencilOp	passOp;
1398				VK_STENCIL_OP_KEEP,		// VkStencilOp	depthFailOp;
1399				VK_COMPARE_OP_NEVER,	// VkCompareOp	compareOp;
1400				0u,						// deUint32		compareMask;
1401				0u,						// deUint32		writeMask;
1402				0u,						// deUint32		reference;
1403			},
1404			0.0f,														// float			minDepthBounds;
1405			1.0f														// float			maxDepthBounds;
1406		};
1407
1408		m_graphicsPipeline.setDefaultRasterizationState()
1409						  .setDefaultMultisampleState()
1410						  .setupVertexInputState(&vertexInputStateParams, &inputAssemblyStateParams)
1411						  .setupPreRasterizationShaderState(viewport,
1412											scissor,
1413											m_pipelineLayout,
1414											*m_renderPass,
1415											0u,
1416											m_vertexShaderModule,
1417											DE_NULL,
1418											m_tcsShaderModule,
1419											m_tesShaderModule)
1420						  .setupFragmentShaderState(m_pipelineLayout,
1421											*m_renderPass,
1422											0u,
1423											m_fragmentShaderModule,
1424											&depthStencilStateParams)
1425						  .setupFragmentOutputState(*m_renderPass, 0u, &colorBlendStateParams)
1426						  .setMonolithicPipelineLayout(m_pipelineLayout)
1427						  .buildPipeline();
1428	}
1429
1430	// Create vertex and index buffer
1431	{
1432		const VkBufferCreateInfo indexBufferParams =
1433		{
1434			VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,		// VkStructureType		sType;
1435			DE_NULL,									// const void*			pNext;
1436			0u,											// VkBufferCreateFlags	flags;
1437			m_indices.size() * sizeof(deUint32),		// VkDeviceSize			size;
1438			VK_BUFFER_USAGE_INDEX_BUFFER_BIT,			// VkBufferUsageFlags	usage;
1439			VK_SHARING_MODE_EXCLUSIVE,					// VkSharingMode		sharingMode;
1440			1u,											// deUint32				queueFamilyIndexCount;
1441			&queueFamilyIndex							// const deUint32*		pQueueFamilyIndices;
1442		};
1443
1444		const VkBufferCreateInfo vertexBufferParams =
1445		{
1446			VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,		// VkStructureType		sType;
1447			DE_NULL,									// const void*			pNext;
1448			0u,											// VkBufferCreateFlags	flags;
1449			m_vertices.size() * sizeof(Vertex4RGBA),	// VkDeviceSize			size;
1450			VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,			// VkBufferUsageFlags	usage;
1451			VK_SHARING_MODE_EXCLUSIVE,					// VkSharingMode		sharingMode;
1452			1u,											// deUint32				queueFamilyIndexCount;
1453			&queueFamilyIndex							// const deUint32*		pQueueFamilyIndices;
1454		};
1455
1456		m_indexBuffer		= createBuffer(vk, vkDevice, &indexBufferParams);
1457		m_indexBufferAlloc	= memAlloc.allocate(getBufferMemoryRequirements(vk, vkDevice, *m_indexBuffer), MemoryRequirement::HostVisible);
1458
1459		VK_CHECK(vk.bindBufferMemory(vkDevice, *m_indexBuffer, m_indexBufferAlloc->getMemory(), m_indexBufferAlloc->getOffset()));
1460
1461		m_vertexBuffer		= createBuffer(vk, vkDevice, &vertexBufferParams);
1462		m_vertexBufferAlloc	= memAlloc.allocate(getBufferMemoryRequirements(vk, vkDevice, *m_vertexBuffer), MemoryRequirement::HostVisible);
1463
1464		VK_CHECK(vk.bindBufferMemory(vkDevice, *m_vertexBuffer, m_vertexBufferAlloc->getMemory(), m_vertexBufferAlloc->getOffset()));
1465
1466		// Load vertices into index buffer
1467		if (m_indexType == VK_INDEX_TYPE_UINT32)
1468		{
1469			deMemcpy(m_indexBufferAlloc->getHostPtr(), m_indices.data(), m_indices.size() * sizeof(deUint32));
1470		}
1471		else if (m_indexType == VK_INDEX_TYPE_UINT8_EXT)
1472		{
1473			uploadIndexBufferData8((deUint8*)m_indexBufferAlloc->getHostPtr(), m_indices);
1474		}
1475		else // m_indexType == VK_INDEX_TYPE_UINT16
1476		{
1477			uploadIndexBufferData16((deUint16*)m_indexBufferAlloc->getHostPtr(), m_indices);
1478		}
1479
1480		// Load vertices into vertex buffer
1481		deMemcpy(m_vertexBufferAlloc->getHostPtr(), m_vertices.data(), m_vertices.size() * sizeof(Vertex4RGBA));
1482
1483		flushAlloc(vk, vkDevice, *m_indexBufferAlloc);
1484		flushAlloc(vk, vkDevice, *m_vertexBufferAlloc);
1485	}
1486
1487	// Create command pool
1488	m_cmdPool = createCommandPool(vk, vkDevice, VK_COMMAND_POOL_CREATE_TRANSIENT_BIT, queueFamilyIndex);
1489
1490	// Create command buffer
1491	{
1492		const VkClearValue attachmentClearValue = defaultClearValue(m_colorFormat);
1493
1494		const VkImageMemoryBarrier attachmentLayoutBarrier =
1495		{
1496			VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,			// VkStructureType			sType;
1497			DE_NULL,										// const void*				pNext;
1498			0u,												// VkAccessFlags			srcAccessMask;
1499			VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,			// VkAccessFlags			dstAccessMask;
1500			VK_IMAGE_LAYOUT_UNDEFINED,						// VkImageLayout			oldLayout;
1501			VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,		// VkImageLayout			newLayout;
1502			VK_QUEUE_FAMILY_IGNORED,						// deUint32					srcQueueFamilyIndex;
1503			VK_QUEUE_FAMILY_IGNORED,						// deUint32					dstQueueFamilyIndex;
1504			*m_colorImage,									// VkImage					image;
1505			{ VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u },	// VkImageSubresourceRange	subresourceRange;
1506		};
1507
1508		m_cmdBuffer = allocateCommandBuffer(vk, vkDevice, *m_cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
1509
1510		beginCommandBuffer(vk, *m_cmdBuffer, 0u);
1511
1512		vk.cmdPipelineBarrier(*m_cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, (VkDependencyFlags)0,
1513			0u, DE_NULL, 0u, DE_NULL, 1u, &attachmentLayoutBarrier);
1514
1515		m_renderPass.begin(vk, *m_cmdBuffer, makeRect2D(0, 0, m_renderSize.x(), m_renderSize.y()), attachmentClearValue);
1516
1517		const VkDeviceSize vertexBufferOffset = 0;
1518
1519		m_graphicsPipeline.bind(*m_cmdBuffer);
1520		vk.cmdBindVertexBuffers(*m_cmdBuffer, 0, 1, &m_vertexBuffer.get(), &vertexBufferOffset);
1521		vk.cmdBindIndexBuffer(*m_cmdBuffer, *m_indexBuffer, 0, m_indexType);
1522		vk.cmdDrawIndexed(*m_cmdBuffer, (deUint32)m_indices.size(), 1, 0, 0, 0);
1523
1524		m_renderPass.end(vk, *m_cmdBuffer);
1525		endCommandBuffer(vk, *m_cmdBuffer);
1526	}
1527}
1528
1529InputAssemblyInstance::~InputAssemblyInstance (void)
1530{
1531}
1532
1533tcu::TestStatus InputAssemblyInstance::iterate (void)
1534{
1535	const DeviceInterface&		vk			= m_context.getDeviceInterface();
1536	const VkDevice				vkDevice	= m_context.getDevice();
1537	const VkQueue				queue		= m_context.getUniversalQueue();
1538
1539	submitCommandsAndWait(vk, vkDevice, queue, m_cmdBuffer.get());
1540
1541	return verifyImage();
1542}
1543
1544tcu::TestStatus InputAssemblyInstance::verifyImage (void)
1545{
1546	const tcu::TextureFormat	tcuColorFormat		= mapVkFormat(m_colorFormat);
1547	const tcu::TextureFormat	tcuStencilFormat	= tcu::TextureFormat();
1548	const ColorVertexShader		vertexShader;
1549	const ColorFragmentShader	fragmentShader		(tcuColorFormat, tcuStencilFormat);
1550	const rr::Program			program				(&vertexShader, &fragmentShader);
1551	ReferenceRenderer			refRenderer			(m_renderSize.x(), m_renderSize.y(), 1, tcuColorFormat, tcuStencilFormat, &program);
1552	bool						compareOk			= false;
1553
1554	// Render reference image
1555	{
1556		// The reference for tessellated patches are drawn using ordinary triangles.
1557		const rr::PrimitiveType		topology	= m_primitiveTopology == VK_PRIMITIVE_TOPOLOGY_PATCH_LIST ? rr::PrimitiveType::PRIMITIVETYPE_TRIANGLES : mapVkPrimitiveTopology(m_primitiveTopology);
1558		rr::RenderState				renderState	(refRenderer.getViewportState(), m_context.getDeviceProperties().limits.subPixelPrecisionBits);
1559
1560		if (m_primitiveTopology == VK_PRIMITIVE_TOPOLOGY_POINT_LIST)
1561			renderState.point.pointSize = 3.0f;
1562
1563		if (m_primitiveRestartEnable)
1564		{
1565			std::vector<deUint32> indicesRange;
1566
1567			for (size_t indexNdx = 0; indexNdx < m_indices.size(); indexNdx++)
1568			{
1569				const bool isRestart = InputAssemblyTest::isRestartIndex(m_indexType, m_indices[indexNdx]);
1570
1571				if (!isRestart)
1572					indicesRange.push_back(m_indices[indexNdx]);
1573
1574				if (isRestart || indexNdx == (m_indices.size() - 1))
1575				{
1576					// Draw the range of indices found so far
1577
1578					std::vector<Vertex4RGBA> nonIndexedVertices;
1579					for (size_t i = 0; i < indicesRange.size(); i++)
1580						nonIndexedVertices.push_back(m_vertices[indicesRange[i]]);
1581
1582					refRenderer.draw(renderState, topology, nonIndexedVertices);
1583					indicesRange.clear();
1584				}
1585			}
1586		}
1587		else
1588		{
1589			std::vector<Vertex4RGBA> nonIndexedVertices;
1590			for (size_t i = 0; i < m_indices.size(); i++)
1591				nonIndexedVertices.push_back(m_vertices[m_indices[i]]);
1592
1593			refRenderer.draw(renderState, topology, nonIndexedVertices);
1594		}
1595	}
1596
1597	// Compare result with reference image
1598	{
1599		const DeviceInterface&				vk					= m_context.getDeviceInterface();
1600		const VkDevice						vkDevice			= m_context.getDevice();
1601		const VkQueue						queue				= m_context.getUniversalQueue();
1602		const deUint32						queueFamilyIndex	= m_context.getUniversalQueueFamilyIndex();
1603		SimpleAllocator						allocator			(vk, vkDevice, getPhysicalDeviceMemoryProperties(m_context.getInstanceInterface(), m_context.getPhysicalDevice()));
1604		de::UniquePtr<tcu::TextureLevel>	result				(readColorAttachment(vk, vkDevice, queue, queueFamilyIndex, allocator, *m_colorImage, m_colorFormat, m_renderSize).release());
1605
1606		compareOk = tcu::intThresholdPositionDeviationCompare(m_context.getTestContext().getLog(),
1607															  "IntImageCompare",
1608															  "Image comparison",
1609															  refRenderer.getAccess(),
1610															  result->getAccess(),
1611															  tcu::UVec4(2, 2, 2, 2),
1612															  tcu::IVec3(1, 1, 0),
1613															  true,
1614															  tcu::COMPARE_LOG_RESULT);
1615	}
1616
1617	if (compareOk)
1618		return tcu::TestStatus::pass("Result image matches reference");
1619	else
1620		return tcu::TestStatus::fail("Image mismatch");
1621}
1622
1623void InputAssemblyInstance::uploadIndexBufferData16	(deUint16* destPtr, const std::vector<deUint32>& indexBufferData)
1624{
1625	for (size_t i = 0; i < indexBufferData.size(); i++)
1626	{
1627		DE_ASSERT(indexBufferData[i] <= 0xFFFF);
1628		destPtr[i] = (deUint16)indexBufferData[i];
1629	}
1630}
1631
1632void InputAssemblyInstance::uploadIndexBufferData8	(deUint8* destPtr, const std::vector<deUint32>& indexBufferData)
1633{
1634	for (size_t i = 0; i < indexBufferData.size(); i++)
1635	{
1636		DE_ASSERT(indexBufferData[i] <= 0xFF);
1637		destPtr[i] = (deUint8)indexBufferData[i];
1638	}
1639}
1640
1641
1642// Utilities for test names
1643
1644std::string getPrimitiveTopologyCaseName (VkPrimitiveTopology topology)
1645{
1646	const std::string  fullName = getPrimitiveTopologyName(topology);
1647
1648	DE_ASSERT(de::beginsWith(fullName, "VK_PRIMITIVE_TOPOLOGY_"));
1649
1650	return de::toLower(fullName.substr(22));
1651}
1652
1653de::MovePtr<tcu::TestCaseGroup> createPrimitiveTopologyTests (tcu::TestContext& testCtx, PipelineConstructionType pipelineConstructionType)
1654{
1655	de::MovePtr<tcu::TestCaseGroup> primitiveTopologyTests (new tcu::TestCaseGroup(testCtx, "primitive_topology"));
1656
1657	de::MovePtr<tcu::TestCaseGroup> indexUint16Tests (new tcu::TestCaseGroup(testCtx, "index_type_uint16"));
1658	de::MovePtr<tcu::TestCaseGroup> indexUint32Tests (new tcu::TestCaseGroup(testCtx, "index_type_uint32"));
1659	de::MovePtr<tcu::TestCaseGroup> indexUint8Tests (new tcu::TestCaseGroup(testCtx, "index_type_uint8"));
1660
1661	for (int topologyNdx = 0; topologyNdx < DE_LENGTH_OF_ARRAY(InputAssemblyTest::s_primitiveTopologies); topologyNdx++)
1662	{
1663		const VkPrimitiveTopology topology = InputAssemblyTest::s_primitiveTopologies[topologyNdx];
1664
1665		indexUint16Tests->addChild(new PrimitiveTopologyTest(testCtx,
1666															 getPrimitiveTopologyCaseName(topology),
1667															 pipelineConstructionType,
1668															 topology,
1669															 VK_INDEX_TYPE_UINT16));
1670
1671		indexUint32Tests->addChild(new PrimitiveTopologyTest(testCtx,
1672															 getPrimitiveTopologyCaseName(topology),
1673															 pipelineConstructionType,
1674															 topology,
1675															 VK_INDEX_TYPE_UINT32));
1676
1677		indexUint8Tests->addChild(new PrimitiveTopologyTest(testCtx,
1678															 getPrimitiveTopologyCaseName(topology),
1679															 pipelineConstructionType,
1680															 topology,
1681															 VK_INDEX_TYPE_UINT8_EXT));
1682	}
1683
1684	primitiveTopologyTests->addChild(indexUint16Tests.release());
1685	primitiveTopologyTests->addChild(indexUint32Tests.release());
1686	primitiveTopologyTests->addChild(indexUint8Tests.release());
1687
1688	return primitiveTopologyTests;
1689}
1690
1691#ifndef CTS_USES_VULKANSC
1692de::MovePtr<tcu::TestCaseGroup> createPrimitiveRestartTests (tcu::TestContext& testCtx, PipelineConstructionType pipelineConstructionType)
1693{
1694	const VkPrimitiveTopology primitiveRestartTopologies[] =
1695	{
1696		VK_PRIMITIVE_TOPOLOGY_LINE_STRIP,
1697		VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP,
1698		VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN,
1699		VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY,
1700		VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY,
1701
1702		// Supported with VK_EXT_primitive_topology_list_restart
1703		VK_PRIMITIVE_TOPOLOGY_POINT_LIST,
1704		VK_PRIMITIVE_TOPOLOGY_LINE_LIST,
1705		VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY,
1706		VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
1707		VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY,
1708		VK_PRIMITIVE_TOPOLOGY_PATCH_LIST
1709	};
1710
1711	de::MovePtr<tcu::TestCaseGroup> primitiveRestartTests (new tcu::TestCaseGroup(testCtx, "primitive_restart"));
1712
1713	de::MovePtr<tcu::TestCaseGroup> indexUint16Tests (new tcu::TestCaseGroup(testCtx, "index_type_uint16"));
1714	de::MovePtr<tcu::TestCaseGroup> indexUint32Tests (new tcu::TestCaseGroup(testCtx, "index_type_uint32"));
1715	de::MovePtr<tcu::TestCaseGroup> indexUint8Tests (new tcu::TestCaseGroup(testCtx, "index_type_uint8"));
1716
1717	constexpr struct RestartTest
1718	{
1719		RestartType	type;
1720		const char* name;
1721	} restartTypes[] =
1722	{
1723		{ RestartType::NORMAL,	"",					},
1724		{ RestartType::NONE,	"no_restart_",		},
1725		{ RestartType::ALL,		"restart_all_"		},
1726	};
1727
1728	for (int topologyNdx = 0; topologyNdx < DE_LENGTH_OF_ARRAY(primitiveRestartTopologies); topologyNdx++)
1729	{
1730		const VkPrimitiveTopology topology = primitiveRestartTopologies[topologyNdx];
1731
1732		for (int useRestartNdx = 0; useRestartNdx < DE_LENGTH_OF_ARRAY(restartTypes); useRestartNdx++)
1733		{
1734			if (topology == VK_PRIMITIVE_TOPOLOGY_POINT_LIST && restartTypes[useRestartNdx].type == RestartType::ALL) {
1735				continue;
1736			}
1737			indexUint16Tests->addChild(new PrimitiveRestartTest(testCtx,
1738																restartTypes[useRestartNdx].name + getPrimitiveTopologyCaseName(topology),
1739																pipelineConstructionType,
1740																topology,
1741																VK_INDEX_TYPE_UINT16,
1742																restartTypes[useRestartNdx].type));
1743
1744			indexUint32Tests->addChild(new PrimitiveRestartTest(testCtx,
1745																restartTypes[useRestartNdx].name + getPrimitiveTopologyCaseName(topology),
1746																pipelineConstructionType,
1747																topology,
1748																VK_INDEX_TYPE_UINT32,
1749																restartTypes[useRestartNdx].type));
1750
1751			indexUint8Tests->addChild(new PrimitiveRestartTest(testCtx,
1752																restartTypes[useRestartNdx].name + getPrimitiveTopologyCaseName(topology),
1753																pipelineConstructionType,
1754																topology,
1755																VK_INDEX_TYPE_UINT8_EXT,
1756																restartTypes[useRestartNdx].type));
1757		}
1758	}
1759
1760	// Tests that have primitive restart disabled, but have indices with restart index value.
1761	if (pipelineConstructionType == PIPELINE_CONSTRUCTION_TYPE_MONOLITHIC)
1762	{
1763		struct
1764		{
1765			std::string	name;
1766			std::vector<std::string> requirements;
1767		} tests[] =
1768		{
1769			{ "line_list", { "VK_EXT_primitive_topology_list_restart" } },
1770			{ "line_list_with_adjacency", { "Features.geometryShader", "VK_EXT_primitive_topology_list_restart" } },
1771			{ "line_strip", {} },
1772			{ "line_strip_with_adjacency", {"Features.geometryShader"} },
1773			{ "patch_list", { "VK_EXT_primitive_topology_list_restart", "Features.tessellationShader" } },
1774			{ "point_list", { "VK_EXT_primitive_topology_list_restart" } },
1775			{ "triangle_fan", {} },
1776			{ "triangle_list", { "VK_EXT_primitive_topology_list_restart" } },
1777			{ "triangle_list_with_adjacency", { "Features.geometryShader", "VK_EXT_primitive_topology_list_restart" } },
1778			{ "triangle_strip", {} },
1779			{ "triangle_strip_with_adjacency", {"Features.geometryShader"} }
1780		};
1781
1782		const std::string dataDir = "pipeline/input_assembly/primitive_restart";
1783
1784		for (auto& test : tests)
1785		{
1786			std::string testName = "restart_disabled_" + test.name;
1787			indexUint16Tests->addChild(cts_amber::createAmberTestCase(testCtx, testName.c_str(),  dataDir.c_str(), testName + "_uint16.amber", test.requirements));
1788			test.requirements.push_back("VK_EXT_index_type_uint8");
1789			indexUint8Tests->addChild(cts_amber::createAmberTestCase(testCtx, testName.c_str(), dataDir.c_str(), testName + "_uint8.amber", test.requirements));
1790		}
1791	}
1792
1793	primitiveRestartTests->addChild(indexUint16Tests.release());
1794	primitiveRestartTests->addChild(indexUint32Tests.release());
1795	primitiveRestartTests->addChild(indexUint8Tests.release());
1796
1797	return primitiveRestartTests;
1798}
1799#endif // CTS_USES_VULKANSC
1800
1801} // anonymous
1802
1803tcu::TestCaseGroup* createInputAssemblyTests (tcu::TestContext& testCtx, PipelineConstructionType pipelineConstructionType)
1804{
1805	de::MovePtr<tcu::TestCaseGroup>		inputAssemblyTests (new tcu::TestCaseGroup(testCtx, "input_assembly"));
1806
1807	inputAssemblyTests->addChild(createPrimitiveTopologyTests(testCtx, pipelineConstructionType).release());
1808#ifndef CTS_USES_VULKANSC
1809	inputAssemblyTests->addChild(createPrimitiveRestartTests(testCtx, pipelineConstructionType).release());
1810#endif // CTS_USES_VULKANSC
1811
1812	return inputAssemblyTests.release();
1813}
1814
1815} // pipeline
1816} // vkt
1817