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