• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2014 The Android Open Source Project
6  * Copyright (c) 2016 The Khronos Group 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  * \file
22  * \brief Tessellation Coordinates Tests
23  *//*--------------------------------------------------------------------*/
24 
25 #include "vktTessellationCoordinatesTests.hpp"
26 #include "vktTestCaseUtil.hpp"
27 #include "vktTessellationUtil.hpp"
28 
29 #include "tcuTestLog.hpp"
30 #include "tcuRGBA.hpp"
31 #include "tcuSurface.hpp"
32 #include "tcuTextureUtil.hpp"
33 #include "tcuVectorUtil.hpp"
34 
35 #include "vkDefs.hpp"
36 #include "vkBarrierUtil.hpp"
37 #include "vkQueryUtil.hpp"
38 #include "vkBuilderUtil.hpp"
39 #include "vkTypeUtil.hpp"
40 #include "vkCmdUtil.hpp"
41 #include "vkObjUtil.hpp"
42 
43 #include "deUniquePtr.hpp"
44 
45 #include <string>
46 #include <vector>
47 
48 namespace vkt
49 {
50 namespace tessellation
51 {
52 
53 using namespace vk;
54 
55 namespace
56 {
57 
58 template <typename T>
59 class SizeLessThan
60 {
61 public:
operator ()(const T & a,const T & b) const62 	bool operator() (const T& a, const T& b) const { return a.size() < b.size(); }
63 };
64 
getCaseName(const TessPrimitiveType primitiveType,const SpacingMode spacingMode,bool executionModeInEvaluationShader)65 std::string getCaseName (const TessPrimitiveType primitiveType, const SpacingMode spacingMode, bool executionModeInEvaluationShader)
66 {
67 	std::ostringstream str;
68 	str << getTessPrimitiveTypeShaderName(primitiveType) << "_" << getSpacingModeShaderName(spacingMode);
69 	if (!executionModeInEvaluationShader)
70 		str << "_execution_mode_in_tesc";
71 	return str.str();
72 }
73 
genTessLevelCases(const TessPrimitiveType primitiveType,const SpacingMode spacingMode)74 std::vector<TessLevels> genTessLevelCases (const TessPrimitiveType	primitiveType,
75 										   const SpacingMode		spacingMode)
76 {
77 	static const TessLevels rawTessLevelCases[] =
78 	{
79 		{ { 1.0f,	1.0f	},	{ 1.0f,		1.0f,	1.0f,	1.0f	} },
80 		{ { 63.0f,	24.0f	},	{ 15.0f,	42.0f,	10.0f,	12.0f	} },
81 		{ { 3.0f,	2.0f	},	{ 6.0f,		8.0f,	7.0f,	9.0f	} },
82 		{ { 4.0f,	6.0f	},	{ 2.0f,		3.0f,	1.0f,	4.0f	} },
83 		{ { 2.0f,	2.0f	},	{ 6.0f,		8.0f,	7.0f,	9.0f	} },
84 		{ { 5.0f,	6.0f	},	{ 1.0f,		1.0f,	1.0f,	1.0f	} },
85 		{ { 1.0f,	6.0f	},	{ 2.0f,		3.0f,	1.0f,	4.0f	} },
86 		{ { 5.0f,	1.0f	},	{ 2.0f,		3.0f,	1.0f,	4.0f	} },
87 		{ { 5.2f,	1.6f	},	{ 2.9f,		3.4f,	1.5f,	4.1f	} }
88 	};
89 
90 	if (spacingMode == SPACINGMODE_EQUAL)
91 		return std::vector<TessLevels>(DE_ARRAY_BEGIN(rawTessLevelCases), DE_ARRAY_END(rawTessLevelCases));
92 	else
93 	{
94 		std::vector<TessLevels> result;
95 		result.reserve(DE_LENGTH_OF_ARRAY(rawTessLevelCases));
96 
97 		for (int tessLevelCaseNdx = 0; tessLevelCaseNdx < DE_LENGTH_OF_ARRAY(rawTessLevelCases); ++tessLevelCaseNdx)
98 		{
99 			TessLevels curTessLevelCase = rawTessLevelCases[tessLevelCaseNdx];
100 
101 			float* const inner = &curTessLevelCase.inner[0];
102 			float* const outer = &curTessLevelCase.outer[0];
103 
104 			for (int j = 0; j < 2; ++j) inner[j] = static_cast<float>(getClampedRoundedTessLevel(spacingMode, inner[j]));
105 			for (int j = 0; j < 4; ++j) outer[j] = static_cast<float>(getClampedRoundedTessLevel(spacingMode, outer[j]));
106 
107 			if (primitiveType == TESSPRIMITIVETYPE_TRIANGLES)
108 			{
109 				if (outer[0] > 1.0f || outer[1] > 1.0f || outer[2] > 1.0f)
110 				{
111 					if (inner[0] == 1.0f)
112 						inner[0] = static_cast<float>(getClampedRoundedTessLevel(spacingMode, inner[0] + 0.1f));
113 				}
114 			}
115 			else if (primitiveType == TESSPRIMITIVETYPE_QUADS)
116 			{
117 				if (outer[0] > 1.0f || outer[1] > 1.0f || outer[2] > 1.0f || outer[3] > 1.0f)
118 				{
119 					if (inner[0] == 1.0f) inner[0] = static_cast<float>(getClampedRoundedTessLevel(spacingMode, inner[0] + 0.1f));
120 					if (inner[1] == 1.0f) inner[1] = static_cast<float>(getClampedRoundedTessLevel(spacingMode, inner[1] + 0.1f));
121 				}
122 			}
123 
124 			result.push_back(curTessLevelCase);
125 		}
126 
127 		DE_ASSERT(static_cast<int>(result.size()) == DE_LENGTH_OF_ARRAY(rawTessLevelCases));
128 		return result;
129 	}
130 }
131 
generateReferenceTessCoords(const TessPrimitiveType primitiveType,const SpacingMode spacingMode,const float * innerLevels,const float * outerLevels)132 std::vector<tcu::Vec3> generateReferenceTessCoords (const TessPrimitiveType	primitiveType,
133 													const SpacingMode		spacingMode,
134 													const float*			innerLevels,
135 													const float*			outerLevels)
136 {
137 	if (isPatchDiscarded(primitiveType, outerLevels))
138 		return std::vector<tcu::Vec3>();
139 
140 	switch (primitiveType)
141 	{
142 		case TESSPRIMITIVETYPE_TRIANGLES:
143 		{
144 			int inner;
145 			int outer[3];
146 			getClampedRoundedTriangleTessLevels(spacingMode, innerLevels, outerLevels, &inner, &outer[0]);
147 
148 			if (spacingMode != SPACINGMODE_EQUAL)
149 			{
150 				// \note For fractional spacing modes, exact results are implementation-defined except in special cases.
151 				DE_ASSERT(de::abs(innerLevels[0] - static_cast<float>(inner)) < 0.001f);
152 				for (int i = 0; i < 3; ++i)
153 					DE_ASSERT(de::abs(outerLevels[i] - static_cast<float>(outer[i])) < 0.001f);
154 				DE_ASSERT(inner > 1 || (outer[0] == 1 && outer[1] == 1 && outer[2] == 1));
155 			}
156 
157 			return generateReferenceTriangleTessCoords(spacingMode, inner, outer[0], outer[1], outer[2]);
158 		}
159 
160 		case TESSPRIMITIVETYPE_QUADS:
161 		{
162 			int inner[2];
163 			int outer[4];
164 			getClampedRoundedQuadTessLevels(spacingMode, innerLevels, outerLevels, &inner[0], &outer[0]);
165 
166 			if (spacingMode != SPACINGMODE_EQUAL)
167 			{
168 				// \note For fractional spacing modes, exact results are implementation-defined except in special cases.
169 				for (int i = 0; i < 2; ++i)
170 					DE_ASSERT(de::abs(innerLevels[i] - static_cast<float>(inner[i])) < 0.001f);
171 				for (int i = 0; i < 4; ++i)
172 					DE_ASSERT(de::abs(outerLevels[i] - static_cast<float>(outer[i])) < 0.001f);
173 
174 				DE_ASSERT((inner[0] > 1 && inner[1] > 1) || (inner[0] == 1 && inner[1] == 1 && outer[0] == 1 && outer[1] == 1 && outer[2] == 1 && outer[3] == 1));
175 			}
176 
177 			return generateReferenceQuadTessCoords(spacingMode, inner[0], inner[1], outer[0], outer[1], outer[2], outer[3]);
178 		}
179 
180 		case TESSPRIMITIVETYPE_ISOLINES:
181 		{
182 			int outer[2];
183 			getClampedRoundedIsolineTessLevels(spacingMode, &outerLevels[0], &outer[0]);
184 
185 			if (spacingMode != SPACINGMODE_EQUAL)
186 			{
187 				// \note For fractional spacing modes, exact results are implementation-defined except in special cases.
188 				DE_ASSERT(de::abs(outerLevels[1] - static_cast<float>(outer[1])) < 0.001f);
189 			}
190 
191 			return generateReferenceIsolineTessCoords(outer[0], outer[1]);
192 		}
193 
194 		default:
195 			DE_ASSERT(false);
196 			return std::vector<tcu::Vec3>();
197 	}
198 }
199 
drawPoint(tcu::Surface & dst,const int centerX,const int centerY,const tcu::RGBA & color,const int size)200 void drawPoint (tcu::Surface& dst, const int centerX, const int centerY, const tcu::RGBA& color, const int size)
201 {
202 	const int width		= dst.getWidth();
203 	const int height	= dst.getHeight();
204 	DE_ASSERT(de::inBounds(centerX, 0, width) && de::inBounds(centerY, 0, height));
205 	DE_ASSERT(size > 0);
206 
207 	for (int yOff = -((size-1)/2); yOff <= size/2; ++yOff)
208 	for (int xOff = -((size-1)/2); xOff <= size/2; ++xOff)
209 	{
210 		const int pixX = centerX + xOff;
211 		const int pixY = centerY + yOff;
212 		if (de::inBounds(pixX, 0, width) && de::inBounds(pixY, 0, height))
213 			dst.setPixel(pixX, pixY, color);
214 	}
215 }
216 
drawTessCoordPoint(tcu::Surface & dst,const TessPrimitiveType primitiveType,const tcu::Vec3 & pt,const tcu::RGBA & color,const int size)217 void drawTessCoordPoint (tcu::Surface& dst, const TessPrimitiveType primitiveType, const tcu::Vec3& pt, const tcu::RGBA& color, const int size)
218 {
219 	// \note These coordinates should match the description in the log message in TessCoordTestInstance::iterate.
220 
221 	static const tcu::Vec2 triangleCorners[3] =
222 	{
223 		tcu::Vec2(0.95f, 0.95f),
224 		tcu::Vec2(0.5f,  0.95f - 0.9f*deFloatSqrt(3.0f/4.0f)),
225 		tcu::Vec2(0.05f, 0.95f)
226 	};
227 
228 	static const float quadIsolineLDRU[4] =
229 	{
230 		0.1f, 0.9f, 0.9f, 0.1f
231 	};
232 
233 	const tcu::Vec2 dstPos = primitiveType == TESSPRIMITIVETYPE_TRIANGLES ? pt.x()*triangleCorners[0]
234 																		  + pt.y()*triangleCorners[1]
235 																		  + pt.z()*triangleCorners[2]
236 
237 					  : primitiveType == TESSPRIMITIVETYPE_QUADS ||
238 						primitiveType == TESSPRIMITIVETYPE_ISOLINES ? tcu::Vec2((1.0f - pt.x())*quadIsolineLDRU[0] + pt.x()*quadIsolineLDRU[2],
239 																			    (1.0f - pt.y())*quadIsolineLDRU[1] + pt.y()*quadIsolineLDRU[3])
240 
241 					  : tcu::Vec2(-1.0f);
242 
243 	drawPoint(dst,
244 			  static_cast<int>(dstPos.x() * (float)dst.getWidth()),
245 			  static_cast<int>(dstPos.y() * (float)dst.getHeight()),
246 			  color,
247 			  size);
248 }
249 
drawTessCoordVisualization(tcu::Surface & dst,const TessPrimitiveType primitiveType,const std::vector<tcu::Vec3> & coords)250 void drawTessCoordVisualization (tcu::Surface& dst, const TessPrimitiveType primitiveType, const std::vector<tcu::Vec3>& coords)
251 {
252 	const int imageWidth  = 256;
253 	const int imageHeight = 256;
254 	dst.setSize(imageWidth, imageHeight);
255 
256 	tcu::clear(dst.getAccess(), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
257 
258 	for (int i = 0; i < static_cast<int>(coords.size()); ++i)
259 		drawTessCoordPoint(dst, primitiveType, coords[i], tcu::RGBA::white(), 2);
260 }
261 
vec3XLessThan(const tcu::Vec3 & a,const tcu::Vec3 & b)262 inline bool vec3XLessThan (const tcu::Vec3& a, const tcu::Vec3& b)
263 {
264 	return a.x() < b.x();
265 }
266 
binarySearchFirstVec3WithXAtLeast(const std::vector<tcu::Vec3> & sorted,float x)267 int binarySearchFirstVec3WithXAtLeast (const std::vector<tcu::Vec3>& sorted, float x)
268 {
269 	const tcu::Vec3 ref(x, 0.0f, 0.0f);
270 	const std::vector<tcu::Vec3>::const_iterator first = std::lower_bound(sorted.begin(), sorted.end(), ref, vec3XLessThan);
271 	if (first == sorted.end())
272 		return -1;
273 	return static_cast<int>(std::distance(sorted.begin(), first));
274 }
275 
276 // Check that all points in subset are (approximately) present also in superset.
oneWayComparePointSets(tcu::TestLog & log,tcu::Surface & errorDst,const TessPrimitiveType primitiveType,const std::vector<tcu::Vec3> & subset,const std::vector<tcu::Vec3> & superset,const char * subsetName,const char * supersetName,const tcu::RGBA & errorColor)277 bool oneWayComparePointSets (tcu::TestLog&					log,
278 							 tcu::Surface&					errorDst,
279 							 const TessPrimitiveType		primitiveType,
280 							 const std::vector<tcu::Vec3>&	subset,
281 							 const std::vector<tcu::Vec3>&	superset,
282 							 const char*					subsetName,
283 							 const char*					supersetName,
284 							 const tcu::RGBA&				errorColor)
285 {
286 	const std::vector<tcu::Vec3> supersetSorted		 = sorted(superset, vec3XLessThan);
287 	const float					 epsilon			 = 0.01f;
288 	const int					 maxNumFailurePrints = 5;
289 	int							 numFailuresDetected = 0;
290 
291 	for (int subNdx = 0; subNdx < static_cast<int>(subset.size()); ++subNdx)
292 	{
293 		const tcu::Vec3& subPt = subset[subNdx];
294 
295 		bool matchFound = false;
296 
297 		{
298 			// Binary search the index of the first point in supersetSorted with x in the [subPt.x() - epsilon, subPt.x() + epsilon] range.
299 			const tcu::Vec3	matchMin			= subPt - epsilon;
300 			const tcu::Vec3	matchMax			= subPt + epsilon;
301 			const int		firstCandidateNdx	= binarySearchFirstVec3WithXAtLeast(supersetSorted, matchMin.x());
302 
303 			if (firstCandidateNdx >= 0)
304 			{
305 				// Compare subPt to all points in supersetSorted with x in the [subPt.x() - epsilon, subPt.x() + epsilon] range.
306 				for (int superNdx = firstCandidateNdx; superNdx < static_cast<int>(supersetSorted.size()) && supersetSorted[superNdx].x() <= matchMax.x(); ++superNdx)
307 				{
308 					const tcu::Vec3& superPt = supersetSorted[superNdx];
309 
310 					if (tcu::boolAll(tcu::greaterThanEqual	(superPt, matchMin)) &&
311 						tcu::boolAll(tcu::lessThanEqual		(superPt, matchMax)))
312 					{
313 						matchFound = true;
314 						break;
315 					}
316 				}
317 			}
318 		}
319 
320 		if (!matchFound)
321 		{
322 			++numFailuresDetected;
323 			if (numFailuresDetected < maxNumFailurePrints)
324 				log << tcu::TestLog::Message << "Failure: no matching " << supersetName << " point found for " << subsetName << " point " << subPt << tcu::TestLog::EndMessage;
325 			else if (numFailuresDetected == maxNumFailurePrints)
326 				log << tcu::TestLog::Message << "Note: More errors follow" << tcu::TestLog::EndMessage;
327 
328 			drawTessCoordPoint(errorDst, primitiveType, subPt, errorColor, 4);
329 		}
330 	}
331 
332 	return numFailuresDetected == 0;
333 }
334 
335 //! Returns true on matching coordinate sets.
compareTessCoords(tcu::TestLog & log,TessPrimitiveType primitiveType,const std::vector<tcu::Vec3> & refCoords,const std::vector<tcu::Vec3> & resCoords)336 bool compareTessCoords (tcu::TestLog&					log,
337 						TessPrimitiveType				primitiveType,
338 						const std::vector<tcu::Vec3>&	refCoords,
339 						const std::vector<tcu::Vec3>&	resCoords)
340 {
341 	tcu::Surface	refVisual;
342 	tcu::Surface	resVisual;
343 	bool			success = true;
344 
345 	drawTessCoordVisualization(refVisual, primitiveType, refCoords);
346 	drawTessCoordVisualization(resVisual, primitiveType, resCoords);
347 
348 	// Check that all points in reference also exist in result.
349 	success = oneWayComparePointSets(log, refVisual, primitiveType, refCoords, resCoords, "reference", "result", tcu::RGBA::blue()) && success;
350 	// Check that all points in result also exist in reference.
351 	success = oneWayComparePointSets(log, resVisual, primitiveType, resCoords, refCoords, "result", "reference", tcu::RGBA::red()) && success;
352 
353 	if (!success)
354 	{
355 		log << tcu::TestLog::Message << "Note: in the following reference visualization, points that are missing in result point set are blue (if any)" << tcu::TestLog::EndMessage
356 			<< tcu::TestLog::Image("RefTessCoordVisualization", "Reference tessCoord visualization", refVisual)
357 			<< tcu::TestLog::Message << "Note: in the following result visualization, points that are missing in reference point set are red (if any)" << tcu::TestLog::EndMessage;
358 	}
359 
360 	log << tcu::TestLog::Image("ResTessCoordVisualization", "Result tessCoord visualization", resVisual);
361 
362 	return success;
363 }
364 
365 class TessCoordTest : public TestCase
366 {
367 public:
368 								TessCoordTest	(tcu::TestContext&			testCtx,
369 												 const TessPrimitiveType	primitiveType,
370 												 const SpacingMode			spacingMode,
371 												 const bool					executionModeInEvaluationShader = true);
372 
373 	void						initPrograms	(SourceCollections&			programCollection) const;
374 	void						checkSupport	(Context&					context) const;
375 	TestInstance*				createInstance	(Context&					context) const;
376 
377 private:
378 	const TessPrimitiveType		m_primitiveType;
379 	const SpacingMode			m_spacingMode;
380 	const bool					m_executionModeInEvaluationShader;
381 };
382 
TessCoordTest(tcu::TestContext & testCtx,const TessPrimitiveType primitiveType,const SpacingMode spacingMode,const bool executionModeInEvaluationShader)383 TessCoordTest::TessCoordTest (tcu::TestContext&			testCtx,
384 							  const TessPrimitiveType	primitiveType,
385 							  const SpacingMode			spacingMode,
386 							  const bool				executionModeInEvaluationShader)
387 	: TestCase							(testCtx, getCaseName(primitiveType, spacingMode, executionModeInEvaluationShader), "")
388 	, m_primitiveType					(primitiveType)
389 	, m_spacingMode						(spacingMode)
390 	, m_executionModeInEvaluationShader	(executionModeInEvaluationShader)
391 {
392 }
393 
checkSupport(Context & context) const394 void TessCoordTest::checkSupport (Context& context) const
395 {
396 	if (const vk::VkPhysicalDevicePortabilitySubsetFeaturesKHR* const features = getPortability(context))
397 	{
398 		checkPointMode(*features);
399 		checkPrimitive(*features, m_primitiveType);
400 	}
401 }
402 
initPrograms(SourceCollections & programCollection) const403 void TessCoordTest::initPrograms (SourceCollections& programCollection) const
404 {
405 	if (m_executionModeInEvaluationShader)
406 	{
407 		// Vertex shader - no inputs
408 		{
409 			std::ostringstream src;
410 			src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
411 				<< "\n"
412 				<< "void main (void)\n"
413 				<< "{\n"
414 				<< "}\n";
415 
416 			programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
417 		}
418 
419 		// Tessellation control shader
420 		{
421 			std::ostringstream src;
422 			src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
423 				<< "#extension GL_EXT_tessellation_shader : require\n"
424 				<< "\n"
425 				<< "layout(vertices = 1) out;\n"
426 				<< "\n"
427 				<< "layout(set = 0, binding = 0, std430) readonly restrict buffer TessLevels {\n"
428 				<< "    float inner0;\n"
429 				<< "    float inner1;\n"
430 				<< "    float outer0;\n"
431 				<< "    float outer1;\n"
432 				<< "    float outer2;\n"
433 				<< "    float outer3;\n"
434 				<< "} sb_levels;\n"
435 				<< "\n"
436 				<< "void main (void)\n"
437 				<< "{\n"
438 				<< "    gl_TessLevelInner[0] = sb_levels.inner0;\n"
439 				<< "    gl_TessLevelInner[1] = sb_levels.inner1;\n"
440 				<< "\n"
441 				<< "    gl_TessLevelOuter[0] = sb_levels.outer0;\n"
442 				<< "    gl_TessLevelOuter[1] = sb_levels.outer1;\n"
443 				<< "    gl_TessLevelOuter[2] = sb_levels.outer2;\n"
444 				<< "    gl_TessLevelOuter[3] = sb_levels.outer3;\n"
445 				<< "}\n";
446 
447 			programCollection.glslSources.add("tesc") << glu::TessellationControlSource(src.str());
448 		}
449 
450 		// Tessellation evaluation shader
451 		{
452 			std::ostringstream src;
453 			src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
454 				<< "#extension GL_EXT_tessellation_shader : require\n"
455 				<< "\n"
456 				<< "layout(" << getTessPrimitiveTypeShaderName(m_primitiveType) << ", "
457 				<< getSpacingModeShaderName(m_spacingMode) << ", point_mode) in;\n" << "\n"
458 				<< "layout(set = 0, binding = 1, std430) coherent restrict buffer Output {\n"
459 				<< "    int  numInvocations;\n"
460 				<< "    vec3 tessCoord[];\n"		// alignment is 16 bytes, same as vec4
461 				<< "} sb_out;\n"
462 				<< "\n"
463 				<< "void main (void)\n"
464 				<< "{\n"
465 				<< "    int index = atomicAdd(sb_out.numInvocations, 1);\n"
466 				<< "    sb_out.tessCoord[index] = gl_TessCoord;\n"
467 				<< "}\n";
468 
469 			programCollection.glslSources.add("tese") << glu::TessellationEvaluationSource(src.str());
470 		}
471 	}
472 	else
473 	{
474 		// note: spirv code for all stages coresponds to glsl version above
475 
476 		programCollection.spirvAsmSources.add("vert")
477 			<< "OpCapability Shader\n"
478 			   "%glsl_ext_inst = OpExtInstImport \"GLSL.std.450\"\n"
479 			   "OpMemoryModel Logical GLSL450\n"
480 			   "OpEntryPoint Vertex %main_fun \"main\"\n"
481 			   "%type_void       = OpTypeVoid\n"
482 			   "%type_void_f     = OpTypeFunction %type_void\n"
483 			   "%main_fun        = OpFunction %type_void None %type_void_f\n"
484 			   "%main_label      = OpLabel\n"
485 			   "OpReturn\n"
486 			   "OpFunctionEnd\n";
487 
488 		// glsl requires primitive_mode, vertex_spacing, ordering and point_mode layout qualifiers to be defined in
489 		// tessellation evaluation shader while spirv allows corresponding execution modes to be defined in TES and/or
490 		// TCS; here we test using execution modes only in TCS as TES is tested with glsl version of tests
491 
492 		const std::string executionMode =
493 			std::string("OpExecutionMode %main_fun ") + getTessPrimitiveTypeShaderName(m_primitiveType, true) + "\n"
494 			"OpExecutionMode %main_fun " + getSpacingModeShaderName(m_spacingMode, true) + "\n" +
495 			"OpExecutionMode %main_fun PointMode\n"
496 			"OpExecutionMode %main_fun VertexOrderCcw\n";
497 
498 		std::string tescSrc =
499 			   "OpCapability Tessellation\n"
500 			   "%glsl_ext_inst = OpExtInstImport \"GLSL.std.450\"\n"
501 			   "OpMemoryModel Logical GLSL450\n"
502 			   "OpEntryPoint TessellationControl %main_fun \"main\" %var_tess_level_inner %var_tess_level_outer\n"
503 			   "OpExecutionMode %main_fun OutputVertices 1\n";
504 		tescSrc += executionMode +
505 			   "OpDecorate %var_tess_level_inner Patch\n"
506 			   "OpDecorate %var_tess_level_inner BuiltIn TessLevelInner\n"
507 			   "OpMemberDecorate %type_struct_sb_levels 0 NonWritable\n"
508 			   "OpMemberDecorate %type_struct_sb_levels 0 Offset 0\n"
509 			   "OpMemberDecorate %type_struct_sb_levels 1 NonWritable\n"
510 			   "OpMemberDecorate %type_struct_sb_levels 1 Offset 4\n"
511 			   "OpMemberDecorate %type_struct_sb_levels 2 NonWritable\n"
512 			   "OpMemberDecorate %type_struct_sb_levels 2 Offset 8\n"
513 			   "OpMemberDecorate %type_struct_sb_levels 3 NonWritable\n"
514 			   "OpMemberDecorate %type_struct_sb_levels 3 Offset 12\n"
515 			   "OpMemberDecorate %type_struct_sb_levels 4 NonWritable\n"
516 			   "OpMemberDecorate %type_struct_sb_levels 4 Offset 16\n"
517 			   "OpMemberDecorate %type_struct_sb_levels 5 NonWritable\n"
518 			   "OpMemberDecorate %type_struct_sb_levels 5 Offset 20\n"
519 			   "OpDecorate %type_struct_sb_levels BufferBlock\n"
520 			   "OpDecorate %var_struct_sb_levels DescriptorSet 0\n"
521 			   "OpDecorate %var_struct_sb_levels Binding 0\n"
522 			   "OpDecorate %var_struct_sb_levels Restrict\n"
523 			   "OpDecorate %var_tess_level_outer Patch\n"
524 			   "OpDecorate %var_tess_level_outer BuiltIn TessLevelOuter\n"
525 			   "%type_void                 = OpTypeVoid\n"
526 			   "%type_void_f               = OpTypeFunction %type_void\n"
527 			   "%type_f32                  = OpTypeFloat 32\n"
528 			   "%type_u32                  = OpTypeInt 32 0\n"
529 			   "%c_u32_2                   = OpConstant %type_u32 2\n"
530 			   "%type_arr_f32_2            = OpTypeArray %type_f32 %c_u32_2\n"
531 			   "%type_arr_f32_2_ptr        = OpTypePointer Output %type_arr_f32_2\n"
532 			   "%type_i32                  = OpTypeInt 32 1\n"
533 			   "%type_struct_sb_levels     = OpTypeStruct %type_f32 %type_f32 %type_f32 %type_f32 %type_f32 %type_f32\n"
534 			   "%type_struct_sb_levels_ptr = OpTypePointer Uniform %type_struct_sb_levels\n"
535 			   "%var_struct_sb_levels      = OpVariable %type_struct_sb_levels_ptr Uniform\n"
536 			   "%type_uni_f32_ptr          = OpTypePointer Uniform %type_f32\n"
537 			   "%type_out_f32_ptr          = OpTypePointer Output %type_f32\n"
538 			   "%c_i32_0                   = OpConstant %type_i32 0\n"
539 			   "%c_i32_1                   = OpConstant %type_i32 1\n"
540 			   "%c_u32_4                   = OpConstant %type_u32 4\n"
541 			   "%c_i32_2                   = OpConstant %type_i32 2\n"
542 			   "%c_i32_3                   = OpConstant %type_i32 3\n"
543 			   "%c_i32_4                   = OpConstant %type_i32 4\n"
544 			   "%c_i32_5                   = OpConstant %type_i32 5\n"
545 			   "%type_arr_f32_4            = OpTypeArray %type_f32 %c_u32_4\n"
546 			   "%type_arr_f32_4_ptr        = OpTypePointer Output %type_arr_f32_4\n"
547 			   "%var_tess_level_inner      = OpVariable %type_arr_f32_2_ptr Output\n"
548 			   "%var_tess_level_outer      = OpVariable %type_arr_f32_4_ptr Output\n"
549 			   "%main_fun                  = OpFunction %type_void None %type_void_f\n"
550 			   "%main_label                = OpLabel\n"
551 			   "%tess_inner_0_ptr          = OpAccessChain %type_uni_f32_ptr %var_struct_sb_levels %c_i32_0\n"
552 			   "%tess_inner_0              = OpLoad %type_f32 %tess_inner_0_ptr\n"
553 			   "%gl_tess_inner_0           = OpAccessChain %type_out_f32_ptr %var_tess_level_inner %c_i32_0\n"
554 			   "                             OpStore %gl_tess_inner_0 %tess_inner_0\n"
555 			   "%tess_inner_1_ptr          = OpAccessChain %type_uni_f32_ptr %var_struct_sb_levels %c_i32_1\n"
556 			   "%tess_inner_1              = OpLoad %type_f32 %tess_inner_1_ptr\n"
557 			   "%gl_tess_inner_1           = OpAccessChain %type_out_f32_ptr %var_tess_level_inner %c_i32_1\n"
558 			   "                             OpStore %gl_tess_inner_1 %tess_inner_1\n"
559 			   "%tess_outer_0_ptr          = OpAccessChain %type_uni_f32_ptr %var_struct_sb_levels %c_i32_2\n"
560 			   "%tess_outer_0              = OpLoad %type_f32 %tess_outer_0_ptr\n"
561 			   "%gl_tess_outer_0           = OpAccessChain %type_out_f32_ptr %var_tess_level_outer %c_i32_0\n"
562 			   "                             OpStore %gl_tess_outer_0 %tess_outer_0\n"
563 			   "%tess_outer_1_ptr          = OpAccessChain %type_uni_f32_ptr %var_struct_sb_levels %c_i32_3\n"
564 			   "%tess_outer_1              = OpLoad %type_f32 %tess_outer_1_ptr\n"
565 			   "%gl_tess_outer_1           = OpAccessChain %type_out_f32_ptr %var_tess_level_outer %c_i32_1\n"
566 			   "                             OpStore %gl_tess_outer_1 %tess_outer_1\n"
567 			   "%tess_outer_2_ptr          = OpAccessChain %type_uni_f32_ptr %var_struct_sb_levels %c_i32_4\n"
568 			   "%tess_outer_2              = OpLoad %type_f32 %tess_outer_2_ptr\n"
569 			   "%gl_tess_outer_2           = OpAccessChain %type_out_f32_ptr %var_tess_level_outer %c_i32_2\n"
570 			   "                             OpStore %gl_tess_outer_2 %tess_outer_2\n"
571 			   "%tess_outer_3_ptr          = OpAccessChain %type_uni_f32_ptr %var_struct_sb_levels %c_i32_5\n"
572 			   "%tess_outer_3              = OpLoad %type_f32 %tess_outer_3_ptr\n"
573 			   "%gl_tess_outer_3           = OpAccessChain %type_out_f32_ptr %var_tess_level_outer %c_i32_3\n"
574 			   "                             OpStore %gl_tess_outer_3 %tess_outer_3\n"
575 			   "OpReturn\n"
576 			   "OpFunctionEnd\n";
577 		programCollection.spirvAsmSources.add("tesc") << tescSrc;
578 
579 		std::string teseSrc =
580 			   "OpCapability Tessellation\n"
581 			   "%glsl_ext_inst = OpExtInstImport \"GLSL.std.450\"\n"
582 			   "OpMemoryModel Logical GLSL450\n"
583 			   "OpEntryPoint TessellationEvaluation %main_fun \"main\" %var_gl_tess_coord\n"
584 			   "OpDecorate %type_run_arr_v3_f32 ArrayStride 16\n"
585 			   "OpMemberDecorate %type_struct 0 Coherent\n"
586 			   "OpMemberDecorate %type_struct 0 Offset 0\n"
587 			   "OpMemberDecorate %type_struct 1 Coherent\n"
588 			   "OpMemberDecorate %type_struct 1 Offset 16\n"
589 			   "OpDecorate %type_struct BufferBlock\n"
590 			   "OpDecorate %var_struct_ptr DescriptorSet 0\n"
591 			   "OpDecorate %var_struct_ptr Restrict\n"
592 			   "OpDecorate %var_struct_ptr Binding 1\n"
593 			   "OpDecorate %var_gl_tess_coord BuiltIn TessCoord\n"
594 			   "%type_void             = OpTypeVoid\n"
595 			   "%type_void_f           = OpTypeFunction %type_void\n"
596 			   "%type_i32              = OpTypeInt 32 1\n"
597 			   "%type_u32              = OpTypeInt 32 0\n"
598 			   "%type_i32_fp           = OpTypePointer Function %type_i32\n"
599 			   "%type_f32              = OpTypeFloat 32\n"
600 			   "%type_v3_f32           = OpTypeVector %type_f32 3\n"
601 			   "%type_run_arr_v3_f32   = OpTypeRuntimeArray %type_v3_f32\n"
602 			   "%type_struct           = OpTypeStruct %type_i32 %type_run_arr_v3_f32\n"
603 			   "%type_uni_struct_ptr   = OpTypePointer Uniform %type_struct\n"
604 			   "%type_uni_i32_ptr      = OpTypePointer Uniform %type_i32\n"
605 			   "%type_uni_v3_f32_ptr   = OpTypePointer Uniform %type_v3_f32\n"
606 			   "%type_in_v3_f32_ptr    = OpTypePointer Input %type_v3_f32\n"
607 			   "%c_i32_0               = OpConstant %type_i32 0\n"
608 			   "%c_i32_1               = OpConstant %type_i32 1\n"
609 			   "%c_u32_0               = OpConstant %type_u32 1\n"
610 			   "%c_u32_1               = OpConstant %type_u32 0\n"
611 			   "%var_struct_ptr        = OpVariable %type_uni_struct_ptr Uniform\n"
612 			   "%var_gl_tess_coord     = OpVariable %type_in_v3_f32_ptr Input\n"
613 			   "%main_fun              = OpFunction %type_void None %type_void_f\n"
614 			   "%main_label            = OpLabel\n"
615 			   "%var_i32_ptr           = OpVariable %type_i32_fp Function\n"
616 			   "%num_invocations       = OpAccessChain %type_uni_i32_ptr %var_struct_ptr %c_i32_0\n"
617 			   "%index_0               = OpAtomicIAdd %type_i32 %num_invocations %c_u32_0 %c_u32_1 %c_i32_1\n"
618 			   "                         OpStore %var_i32_ptr %index_0\n"
619 			   "%index_1               = OpLoad %type_i32 %var_i32_ptr\n"
620 			   "%gl_tess_coord         = OpLoad %type_v3_f32 %var_gl_tess_coord\n"
621 			   "%out_tess_coord        = OpAccessChain %type_uni_v3_f32_ptr %var_struct_ptr %c_i32_1 %index_1\n"
622 			   "                         OpStore %out_tess_coord %gl_tess_coord\n"
623 			   "OpReturn\n"
624 			   "OpFunctionEnd\n";
625 		programCollection.spirvAsmSources.add("tese") << teseSrc;
626 	}
627 }
628 
629 class TessCoordTestInstance : public TestInstance
630 {
631 public:
632 								TessCoordTestInstance (Context&					context,
633 													   const TessPrimitiveType	primitiveType,
634 													   const SpacingMode		spacingMode);
635 
636 	tcu::TestStatus				iterate				  (void);
637 
638 private:
639 	const TessPrimitiveType		m_primitiveType;
640 	const SpacingMode			m_spacingMode;
641 };
642 
TessCoordTestInstance(Context & context,const TessPrimitiveType primitiveType,const SpacingMode spacingMode)643 TessCoordTestInstance::TessCoordTestInstance (Context&					context,
644 											  const TessPrimitiveType	primitiveType,
645 											  const SpacingMode			spacingMode)
646 	: TestInstance		(context)
647 	, m_primitiveType	(primitiveType)
648 	, m_spacingMode		(spacingMode)
649 {
650 }
651 
iterate(void)652 tcu::TestStatus TessCoordTestInstance::iterate (void)
653 {
654 	const DeviceInterface&	vk					= m_context.getDeviceInterface();
655 	const VkDevice			device				= m_context.getDevice();
656 	const VkQueue			queue				= m_context.getUniversalQueue();
657 	const deUint32			queueFamilyIndex	= m_context.getUniversalQueueFamilyIndex();
658 	Allocator&				allocator			= m_context.getDefaultAllocator();
659 
660 	// Test data
661 
662 	const std::vector<TessLevels>		 tessLevelCases			= genTessLevelCases(m_primitiveType, m_spacingMode);
663 	std::vector<std::vector<tcu::Vec3> > allReferenceTessCoords	(tessLevelCases.size());
664 
665 	for (deUint32 i = 0; i < tessLevelCases.size(); ++i)
666 		allReferenceTessCoords[i] = generateReferenceTessCoords(m_primitiveType, m_spacingMode, &tessLevelCases[i].inner[0], &tessLevelCases[i].outer[0]);
667 
668 	const size_t maxNumVertices = static_cast<int>(std::max_element(allReferenceTessCoords.begin(), allReferenceTessCoords.end(), SizeLessThan<std::vector<tcu::Vec3> >())->size());
669 
670 	// Input buffer: tessellation levels. Data is filled in later.
671 
672 	const Buffer tessLevelsBuffer(vk, device, allocator,
673 		makeBufferCreateInfo(sizeof(TessLevels), VK_BUFFER_USAGE_STORAGE_BUFFER_BIT), MemoryRequirement::HostVisible);
674 
675 	// Output buffer: number of invocations + padding + tessellation coordinates. Initialized later.
676 
677 	const int          resultBufferTessCoordsOffset	 = 4 * (int)sizeof(deInt32);
678 	const int          extraneousVertices			 = 16;	// allow some room for extraneous vertices from duplicate shader invocations (number is arbitrary)
679 	const VkDeviceSize resultBufferSizeBytes		 = resultBufferTessCoordsOffset + (maxNumVertices + extraneousVertices)*sizeof(tcu::Vec4);
680 	const Buffer       resultBuffer					 (vk, device, allocator, makeBufferCreateInfo(resultBufferSizeBytes, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT), MemoryRequirement::HostVisible);
681 
682 	// Descriptors
683 
684 	const Unique<VkDescriptorSetLayout> descriptorSetLayout(DescriptorSetLayoutBuilder()
685 		.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT)
686 		.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT)
687 		.build(vk, device));
688 
689 	const Unique<VkDescriptorPool> descriptorPool(DescriptorPoolBuilder()
690 		.addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)
691 		.addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)
692 		.build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u));
693 
694 	const Unique<VkDescriptorSet> descriptorSet(makeDescriptorSet(vk, device, *descriptorPool, *descriptorSetLayout));
695 
696 	const VkDescriptorBufferInfo tessLevelsBufferInfo = makeDescriptorBufferInfo(tessLevelsBuffer.get(), 0ull, sizeof(TessLevels));
697 	const VkDescriptorBufferInfo resultBufferInfo     = makeDescriptorBufferInfo(resultBuffer.get(), 0ull, resultBufferSizeBytes);
698 
699 	DescriptorSetUpdateBuilder()
700 		.writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &tessLevelsBufferInfo)
701 		.writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(1u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &resultBufferInfo)
702 		.update(vk, device);
703 
704 	// Pipeline: set up vertex processing without rasterization
705 
706 	const Unique<VkRenderPass>		renderPass		(makeRenderPassWithoutAttachments (vk, device));
707 	const Unique<VkFramebuffer>		framebuffer		(makeFramebuffer(vk, device, *renderPass, 0u, DE_NULL, 1u, 1u));
708 	const Unique<VkPipelineLayout>	pipelineLayout	(makePipelineLayout(vk, device, *descriptorSetLayout));
709 	const Unique<VkCommandPool>		cmdPool			(makeCommandPool(vk, device, queueFamilyIndex));
710 	const Unique<VkCommandBuffer>	cmdBuffer		(allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
711 
712 	const Unique<VkPipeline> pipeline(GraphicsPipelineBuilder()
713 		.setShader(vk, device, VK_SHADER_STAGE_VERTEX_BIT,					m_context.getBinaryCollection().get("vert"), DE_NULL)
714 		.setShader(vk, device, VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT,	m_context.getBinaryCollection().get("tesc"), DE_NULL)
715 		.setShader(vk, device, VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, m_context.getBinaryCollection().get("tese"), DE_NULL)
716 		.build    (vk, device, *pipelineLayout, *renderPass));
717 
718 	deUint32 numPassedCases = 0;
719 
720 	// Repeat the test for all tessellation coords cases
721 	for (deUint32 tessLevelCaseNdx = 0; tessLevelCaseNdx < tessLevelCases.size(); ++tessLevelCaseNdx)
722 	{
723 		m_context.getTestContext().getLog()
724 			<< tcu::TestLog::Message
725 			<< "Tessellation levels: " << getTessellationLevelsString(tessLevelCases[tessLevelCaseNdx], m_primitiveType)
726 			<< tcu::TestLog::EndMessage;
727 
728 		// Upload tessellation levels data to the input buffer
729 		{
730 			const Allocation& alloc				= tessLevelsBuffer.getAllocation();
731 			TessLevels* const bufferTessLevels	= static_cast<TessLevels*>(alloc.getHostPtr());
732 
733 			*bufferTessLevels = tessLevelCases[tessLevelCaseNdx];
734 			flushAlloc(vk, device, alloc);
735 		}
736 
737 		// Clear the results buffer
738 		{
739 			const Allocation& alloc = resultBuffer.getAllocation();
740 
741 			deMemset(alloc.getHostPtr(), 0, static_cast<std::size_t>(resultBufferSizeBytes));
742 			flushAlloc(vk, device, alloc);
743 		}
744 
745 		// Reset the command buffer and begin recording.
746 		beginCommandBuffer(vk, *cmdBuffer);
747 		beginRenderPassWithRasterizationDisabled(vk, *cmdBuffer, *renderPass, *framebuffer);
748 
749 		vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline);
750 		vk.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipelineLayout, 0u, 1u, &descriptorSet.get(), 0u, DE_NULL);
751 
752 		// Process a single abstract vertex.
753 		vk.cmdDraw(*cmdBuffer, 1u, 1u, 0u, 0u);
754 		endRenderPass(vk, *cmdBuffer);
755 
756 		{
757 			const VkBufferMemoryBarrier shaderWriteBarrier = makeBufferMemoryBarrier(
758 				VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT, *resultBuffer, 0ull, resultBufferSizeBytes);
759 
760 			vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u,
761 				0u, DE_NULL, 1u, &shaderWriteBarrier, 0u, DE_NULL);
762 		}
763 
764 		endCommandBuffer(vk, *cmdBuffer);
765 		submitCommandsAndWait(vk, device, queue, *cmdBuffer);
766 
767 		// Verify results
768 		{
769 			const Allocation&				resultAlloc			= resultBuffer.getAllocation();
770 
771 			invalidateAlloc(vk, device, resultAlloc);
772 
773 			const deInt32					numResults			= *static_cast<deInt32*>(resultAlloc.getHostPtr());
774 			const std::vector<tcu::Vec3>	resultTessCoords	= readInterleavedData<tcu::Vec3>(numResults, resultAlloc.getHostPtr(), resultBufferTessCoordsOffset, sizeof(tcu::Vec4));
775 			const std::vector<tcu::Vec3>&	referenceTessCoords	= allReferenceTessCoords[tessLevelCaseNdx];
776 			const int						numExpectedResults	= static_cast<int>(referenceTessCoords.size());
777 			tcu::TestLog&					log					= m_context.getTestContext().getLog();
778 
779 			if (numResults < numExpectedResults)
780 			{
781 				log << tcu::TestLog::Message
782 					<< "Failure: generated " << numResults << " coordinates, but the expected reference value is " << numExpectedResults
783 					<< tcu::TestLog::EndMessage;
784 			}
785 			else if (numResults == numExpectedResults)
786 				log << tcu::TestLog::Message << "Note: generated " << numResults << " tessellation coordinates" << tcu::TestLog::EndMessage;
787 			else
788 			{
789 				log << tcu::TestLog::Message
790 					<< "Note: generated " << numResults << " coordinates (out of which " << numExpectedResults << " must be unique)"
791 					<< tcu::TestLog::EndMessage;
792 			}
793 
794 			if (m_primitiveType == TESSPRIMITIVETYPE_TRIANGLES)
795 				log << tcu::TestLog::Message << "Note: in the following visualization(s), the u=1, v=1, w=1 corners are at the right, top, and left corners, respectively" << tcu::TestLog::EndMessage;
796 			else if (m_primitiveType == TESSPRIMITIVETYPE_QUADS || m_primitiveType == TESSPRIMITIVETYPE_ISOLINES)
797 				log << tcu::TestLog::Message << "Note: in the following visualization(s), u and v coordinate go left-to-right and bottom-to-top, respectively" << tcu::TestLog::EndMessage;
798 			else
799 				DE_ASSERT(false);
800 
801 			if (compareTessCoords(log, m_primitiveType, referenceTessCoords, resultTessCoords) && (numResults >= numExpectedResults))
802 				++numPassedCases;
803 		}
804 	}  // for tessLevelCaseNdx
805 
806 	return (numPassedCases == tessLevelCases.size() ? tcu::TestStatus::pass("OK") : tcu::TestStatus::fail("Some cases have failed"));
807 }
808 
createInstance(Context & context) const809 TestInstance* TessCoordTest::createInstance (Context& context) const
810 {
811 	requireFeatures(context.getInstanceInterface(), context.getPhysicalDevice(), FEATURE_TESSELLATION_SHADER | FEATURE_VERTEX_PIPELINE_STORES_AND_ATOMICS);
812 
813 	return new TessCoordTestInstance(context, m_primitiveType, m_spacingMode);
814 }
815 
816 } // anonymous
817 
818 //! Based on dEQP-GLES31.functional.tessellation.tesscoord.*
819 //! \note Transform feedback is replaced with SSBO. Because of that, this version allows duplicate coordinates from shader invocations.
820 //! The test still fails if not enough coordinates are generated, or if coordinates don't match the reference data.
createCoordinatesTests(tcu::TestContext & testCtx)821 tcu::TestCaseGroup* createCoordinatesTests (tcu::TestContext& testCtx)
822 {
823 	de::MovePtr<tcu::TestCaseGroup> group (new tcu::TestCaseGroup(testCtx, "tesscoord", "Tessellation coordinates tests"));
824 
825 	for (int primitiveTypeNdx = 0; primitiveTypeNdx < TESSPRIMITIVETYPE_LAST; ++primitiveTypeNdx)
826 		for (int spacingModeNdx = 0; spacingModeNdx < SPACINGMODE_LAST; ++spacingModeNdx)
827 		{
828 			group->addChild(new TessCoordTest(testCtx, (TessPrimitiveType)primitiveTypeNdx, (SpacingMode)spacingModeNdx));
829 
830 			// test if TessCoord builtin has correct value in Evaluation shader when execution mode is set only in Control shader
831 			group->addChild(new TessCoordTest(testCtx, (TessPrimitiveType)primitiveTypeNdx, (SpacingMode)spacingModeNdx, false));
832 		}
833 
834 	return group.release();
835 }
836 
837 } // tessellation
838 } // vkt
839