1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program OpenGL ES 3.1 Module
3  * -------------------------------------------------
4  *
5  * Copyright 2014 The Android Open Source Project
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  *//*!
20  * \file
21  * \brief Tessellation Tests.
22  *//*--------------------------------------------------------------------*/
23 
24 #include "es31fTessellationTests.hpp"
25 #include "glsTextureTestUtil.hpp"
26 #include "glsShaderLibrary.hpp"
27 #include "glsStateQueryUtil.hpp"
28 #include "gluShaderProgram.hpp"
29 #include "gluRenderContext.hpp"
30 #include "gluPixelTransfer.hpp"
31 #include "gluDrawUtil.hpp"
32 #include "gluObjectWrapper.hpp"
33 #include "gluStrUtil.hpp"
34 #include "gluContextInfo.hpp"
35 #include "gluVarType.hpp"
36 #include "gluVarTypeUtil.hpp"
37 #include "gluCallLogWrapper.hpp"
38 #include "tcuTestLog.hpp"
39 #include "tcuRenderTarget.hpp"
40 #include "tcuStringTemplate.hpp"
41 #include "tcuSurface.hpp"
42 #include "tcuTextureUtil.hpp"
43 #include "tcuVectorUtil.hpp"
44 #include "tcuImageIO.hpp"
45 #include "tcuResource.hpp"
46 #include "tcuImageCompare.hpp"
47 #include "deRandom.hpp"
48 #include "deStringUtil.hpp"
49 #include "deSharedPtr.hpp"
50 #include "deUniquePtr.hpp"
51 #include "deString.h"
52 #include "deMath.h"
53 
54 #include "glwEnums.hpp"
55 #include "glwDefs.hpp"
56 #include "glwFunctions.hpp"
57 
58 #include <vector>
59 #include <string>
60 #include <algorithm>
61 #include <functional>
62 #include <set>
63 #include <limits>
64 
65 using glu::ShaderProgram;
66 using glu::RenderContext;
67 using tcu::RenderTarget;
68 using tcu::TestLog;
69 using tcu::Vec2;
70 using tcu::Vec3;
71 using tcu::Vec4;
72 using de::Random;
73 using de::SharedPtr;
74 
75 using std::vector;
76 using std::string;
77 
78 using namespace glw; // For GL types.
79 
80 namespace deqp
81 {
82 
83 using gls::TextureTestUtil::RandomViewport;
84 
85 namespace gles31
86 {
87 namespace Functional
88 {
89 
90 using namespace gls::StateQueryUtil;
91 
92 enum
93 {
94 	MINIMUM_MAX_TESS_GEN_LEVEL = 64 //!< GL-defined minimum for GL_MAX_TESS_GEN_LEVEL.
95 };
96 
vec3XLessThan(const Vec3 & a,const Vec3 & b)97 static inline bool vec3XLessThan (const Vec3& a, const Vec3& b) { return a.x() < b.x(); }
98 
99 template <typename IterT>
elemsStr(const IterT & begin,const IterT & end,int wrapLengthParam=0,int numIndentationSpaces=0)100 static string elemsStr (const IterT& begin, const IterT& end, int wrapLengthParam = 0, int numIndentationSpaces = 0)
101 {
102 	const string	baseIndentation	= string(numIndentationSpaces, ' ');
103 	const string	deepIndentation	= baseIndentation + string(4, ' ');
104 	const int		wrapLength		= wrapLengthParam > 0 ? wrapLengthParam : std::numeric_limits<int>::max();
105 	const int		length			= (int)std::distance(begin, end);
106 	string			result;
107 
108 	if (length > wrapLength)
109 		result += "(amount: " + de::toString(length) + ") ";
110 	result += string() + "{" + (length > wrapLength ? "\n"+deepIndentation : " ");
111 
112 	{
113 		int index = 0;
114 		for (IterT it = begin; it != end; ++it)
115 		{
116 			if (it != begin)
117 				result += string() + ", " + (index % wrapLength == 0 ? "\n"+deepIndentation : "");
118 			result += de::toString(*it);
119 			index++;
120 		}
121 
122 		result += length > wrapLength ? "\n"+baseIndentation : " ";
123 	}
124 
125 	result += "}";
126 	return result;
127 }
128 
129 template <typename ContainerT>
containerStr(const ContainerT & c,int wrapLengthParam=0,int numIndentationSpaces=0)130 static string containerStr (const ContainerT& c, int wrapLengthParam = 0, int numIndentationSpaces = 0)
131 {
132 	return elemsStr(c.begin(), c.end(), wrapLengthParam, numIndentationSpaces);
133 }
134 
135 template <typename T, int N>
arrayStr(const T (& arr)[N],int wrapLengthParam=0,int numIndentationSpaces=0)136 static string arrayStr (const T (&arr)[N], int wrapLengthParam = 0, int numIndentationSpaces = 0)
137 {
138 	return elemsStr(DE_ARRAY_BEGIN(arr), DE_ARRAY_END(arr), wrapLengthParam, numIndentationSpaces);
139 }
140 
141 template <typename T, int N>
arrayMax(const T (& arr)[N])142 static T arrayMax (const T (&arr)[N])
143 {
144 	return *std::max_element(DE_ARRAY_BEGIN(arr), DE_ARRAY_END(arr));
145 }
146 
147 template <typename T, typename MembT>
members(const vector<T> & objs,MembT T::* membP)148 static vector<MembT> members (const vector<T>& objs, MembT T::* membP)
149 {
150 	vector<MembT> result(objs.size());
151 	for (int i = 0; i < (int)objs.size(); i++)
152 		result[i] = objs[i].*membP;
153 	return result;
154 }
155 
156 template <typename T, int N>
arrayToVector(const T (& arr)[N])157 static vector<T> arrayToVector (const T (&arr)[N])
158 {
159 	return vector<T>(DE_ARRAY_BEGIN(arr), DE_ARRAY_END(arr));
160 }
161 
162 template <typename ContainerT, typename T>
contains(const ContainerT & c,const T & key)163 static inline bool contains (const ContainerT& c, const T& key)
164 {
165 	return c.find(key) != c.end();
166 }
167 
168 template <int Size>
singleTrueMask(int index)169 static inline tcu::Vector<bool, Size> singleTrueMask (int index)
170 {
171 	DE_ASSERT(de::inBounds(index, 0, Size));
172 	tcu::Vector<bool, Size> result;
173 	result[index] = true;
174 	return result;
175 }
176 
intPow(int base,int exp)177 static int intPow (int base, int exp)
178 {
179 	DE_ASSERT(exp >= 0);
180 	if (exp == 0)
181 		return 1;
182 	else
183 	{
184 		const int sub = intPow(base, exp/2);
185 		if (exp % 2 == 0)
186 			return sub*sub;
187 		else
188 			return sub*sub*base;
189 	}
190 }
191 
getPixels(const glu::RenderContext & rCtx,int x,int y,int width,int height)192 tcu::Surface getPixels (const glu::RenderContext& rCtx, int x, int y, int width, int height)
193 {
194 	tcu::Surface result(width, height);
195 	glu::readPixels(rCtx, x, y, result.getAccess());
196 	return result;
197 }
198 
getPixels(const glu::RenderContext & rCtx,const RandomViewport & vp)199 tcu::Surface getPixels (const glu::RenderContext& rCtx, const RandomViewport& vp)
200 {
201 	return getPixels(rCtx, vp.x, vp.y, vp.width, vp.height);
202 }
203 
checkRenderTargetSize(const RenderTarget & renderTarget,int minSize)204 static inline void checkRenderTargetSize (const RenderTarget& renderTarget, int minSize)
205 {
206 	if (renderTarget.getWidth() < minSize || renderTarget.getHeight() < minSize)
207 		throw tcu::NotSupportedError("Render target width and height must be at least " + de::toString(minSize));
208 }
209 
getPNG(const tcu::Archive & archive,const string & filename)210 tcu::TextureLevel getPNG (const tcu::Archive& archive, const string& filename)
211 {
212 	tcu::TextureLevel result;
213 	tcu::ImageIO::loadPNG(result, archive, filename.c_str());
214 	return result;
215 }
216 
numBasicSubobjects(const glu::VarType & type)217 static int numBasicSubobjects (const glu::VarType& type)
218 {
219 	if (type.isBasicType())
220 		return 1;
221 	else if (type.isArrayType())
222 		return type.getArraySize()*numBasicSubobjects(type.getElementType());
223 	else if (type.isStructType())
224 	{
225 		const glu::StructType&	structType	= *type.getStructPtr();
226 		int						result		= 0;
227 		for (int i = 0; i < structType.getNumMembers(); i++)
228 			result += numBasicSubobjects(structType.getMember(i).getType());
229 		return result;
230 	}
231 	else
232 	{
233 		DE_ASSERT(false);
234 		return -1;
235 	}
236 }
237 
numVerticesPerPrimitive(deUint32 primitiveTypeGL)238 static inline int numVerticesPerPrimitive (deUint32 primitiveTypeGL)
239 {
240 	switch (primitiveTypeGL)
241 	{
242 		case GL_POINTS:		return 1;
243 		case GL_TRIANGLES:	return 3;
244 		case GL_LINES:		return 2;
245 		default:
246 			DE_ASSERT(false);
247 			return -1;
248 	}
249 }
250 
setViewport(const glw::Functions & gl,const RandomViewport & vp)251 static inline void setViewport (const glw::Functions& gl, const RandomViewport& vp)
252 {
253 	gl.viewport(vp.x, vp.y, vp.width, vp.height);
254 }
255 
getQueryResult(const glw::Functions & gl,deUint32 queryObject)256 static inline deUint32 getQueryResult (const glw::Functions& gl, deUint32 queryObject)
257 {
258 	deUint32 result = (deUint32)-1;
259 	gl.getQueryObjectuiv(queryObject, GL_QUERY_RESULT, &result);
260 	TCU_CHECK(result != (deUint32)-1);
261 	return result;
262 }
263 
264 template <typename T>
readDataMapped(const glw::Functions & gl,deUint32 bufferTarget,int numElems,T * dst)265 static void readDataMapped (const glw::Functions& gl, deUint32 bufferTarget, int numElems, T* dst)
266 {
267 	const int							numBytes	= numElems*(int)sizeof(T);
268 	const T* const						mappedData	= (const T*)gl.mapBufferRange(bufferTarget, 0, numBytes, GL_MAP_READ_BIT);
269 	GLU_EXPECT_NO_ERROR(gl.getError(), (string() + "glMapBufferRange(" + glu::getBufferTargetName((int)bufferTarget) + ", 0, " + de::toString(numBytes) + ", GL_MAP_READ_BIT)").c_str());
270 	TCU_CHECK(mappedData != DE_NULL);
271 
272 	for (int i = 0; i < numElems; i++)
273 		dst[i] = mappedData[i];
274 
275 	gl.unmapBuffer(bufferTarget);
276 }
277 
278 template <typename T>
readDataMapped(const glw::Functions & gl,deUint32 bufferTarget,int numElems)279 static vector<T> readDataMapped (const glw::Functions& gl, deUint32 bufferTarget, int numElems)
280 {
281 	vector<T> result(numElems);
282 	readDataMapped(gl, bufferTarget, numElems, &result[0]);
283 	return result;
284 }
285 
286 namespace
287 {
288 
289 template <typename ArgT, bool res>
290 struct ConstantUnaryPredicate
291 {
operator ()deqp::gles31::Functional::__anon4a9088cf0211::ConstantUnaryPredicate292 	bool operator() (const ArgT&) const { return res; }
293 };
294 
295 //! Helper for handling simple, one-varying transform feedbacks.
296 template <typename VaryingT>
297 class TransformFeedbackHandler
298 {
299 public:
300 	struct Result
301 	{
302 		int					numPrimitives;
303 		vector<VaryingT>	varying;
304 
Resultdeqp::gles31::Functional::__anon4a9088cf0211::TransformFeedbackHandler::Result305 		Result (void)								: numPrimitives(-1) {}
Resultdeqp::gles31::Functional::__anon4a9088cf0211::TransformFeedbackHandler::Result306 		Result (int n, const vector<VaryingT>& v)	: numPrimitives(n), varying(v) {}
307 	};
308 
309 									TransformFeedbackHandler	(const glu::RenderContext& renderCtx, int maxNumVertices);
310 
311 	Result							renderAndGetPrimitives		(deUint32 programGL, deUint32 tfPrimTypeGL, int numBindings, const glu::VertexArrayBinding* bindings, int numVertices) const;
312 
313 private:
314 	const glu::RenderContext&		m_renderCtx;
315 	const glu::TransformFeedback	m_tf;
316 	const glu::Buffer				m_tfBuffer;
317 	const glu::Query				m_tfPrimQuery;
318 };
319 
320 template <typename AttribType>
TransformFeedbackHandler(const glu::RenderContext & renderCtx,int maxNumVertices)321 TransformFeedbackHandler<AttribType>::TransformFeedbackHandler (const glu::RenderContext& renderCtx, int maxNumVertices)
322 	: m_renderCtx		(renderCtx)
323 	, m_tf				(renderCtx)
324 	, m_tfBuffer		(renderCtx)
325 	, m_tfPrimQuery		(renderCtx)
326 {
327 	const glw::Functions&	gl			= m_renderCtx.getFunctions();
328 	// \note Room for 1 extra triangle, to detect if GL returns too many primitives.
329 	const int				bufferSize	= (maxNumVertices + 3) * (int)sizeof(AttribType);
330 
331 	gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, *m_tfBuffer);
332 	gl.bufferData(GL_TRANSFORM_FEEDBACK_BUFFER, bufferSize, DE_NULL, GL_DYNAMIC_READ);
333 }
334 
335 template <typename AttribType>
renderAndGetPrimitives(deUint32 programGL,deUint32 tfPrimTypeGL,int numBindings,const glu::VertexArrayBinding * bindings,int numVertices) const336 typename TransformFeedbackHandler<AttribType>::Result TransformFeedbackHandler<AttribType>::renderAndGetPrimitives (deUint32 programGL, deUint32 tfPrimTypeGL, int numBindings, const glu::VertexArrayBinding* bindings, int numVertices) const
337 {
338 	DE_ASSERT(tfPrimTypeGL == GL_POINTS || tfPrimTypeGL == GL_LINES || tfPrimTypeGL == GL_TRIANGLES);
339 
340 	const glw::Functions& gl = m_renderCtx.getFunctions();
341 
342 	gl.bindTransformFeedback(GL_TRANSFORM_FEEDBACK, *m_tf);
343 	gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, *m_tfBuffer);
344 	gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, *m_tfBuffer);
345 
346 	gl.beginQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, *m_tfPrimQuery);
347 	gl.beginTransformFeedback(tfPrimTypeGL);
348 
349 	glu::draw(m_renderCtx, programGL, numBindings, bindings, glu::pr::Patches(numVertices));
350 	GLU_EXPECT_NO_ERROR(gl.getError(), "Draw failed");
351 
352 	gl.endTransformFeedback();
353 	gl.endQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN);
354 
355 	{
356 		const int numPrimsWritten = (int)getQueryResult(gl, *m_tfPrimQuery);
357 		return Result(numPrimsWritten, readDataMapped<AttribType>(gl, GL_TRANSFORM_FEEDBACK_BUFFER, numPrimsWritten * numVerticesPerPrimitive(tfPrimTypeGL)));
358 	}
359 }
360 
361 template <typename T>
362 class SizeLessThan
363 {
364 public:
operator ()(const T & a,const T & b) const365 	bool operator() (const T& a, const T& b) const { return a.size() < b.size(); }
366 };
367 
368 //! Predicate functor for comparing structs by their members.
369 template <typename Pred, typename T, typename MembT>
370 class MemberPred
371 {
372 public:
MemberPred(MembT T::* membP)373 				MemberPred	(MembT T::* membP) : m_membP(membP), m_pred(Pred()) {}
operator ()(const T & a,const T & b) const374 	bool		operator()	(const T& a, const T& b) const { return m_pred(a.*m_membP, b.*m_membP); }
375 
376 private:
377 	MembT T::*	m_membP;
378 	Pred		m_pred;
379 };
380 
381 //! Convenience wrapper for MemberPred, because class template arguments aren't deduced based on constructor arguments.
382 template <template <typename> class Pred, typename T, typename MembT>
memberPred(MembT T::* membP)383 static MemberPred<Pred<MembT>, T, MembT> memberPred (MembT T::* membP) { return MemberPred<Pred<MembT>, T, MembT>(membP); }
384 
385 template <typename SeqT, int Size, typename Pred>
386 class LexCompare
387 {
388 public:
LexCompare(void)389 	LexCompare (void) : m_pred(Pred()) {}
390 
operator ()(const SeqT & a,const SeqT & b) const391 	bool operator() (const SeqT& a, const SeqT& b) const
392 	{
393 		for (int i = 0; i < Size; i++)
394 		{
395 			if (m_pred(a[i], b[i]))
396 				return true;
397 			if (m_pred(b[i], a[i]))
398 				return false;
399 		}
400 		return false;
401 	}
402 
403 private:
404 	Pred m_pred;
405 };
406 
407 template <int Size>
408 class VecLexLessThan : public LexCompare<tcu::Vector<float, Size>, Size, std::less<float> >
409 {
410 };
411 
412 enum TessPrimitiveType
413 {
414 	TESSPRIMITIVETYPE_TRIANGLES = 0,
415 	TESSPRIMITIVETYPE_QUADS,
416 	TESSPRIMITIVETYPE_ISOLINES,
417 
418 	TESSPRIMITIVETYPE_LAST
419 };
420 
421 enum SpacingMode
422 {
423 	SPACINGMODE_EQUAL,
424 	SPACINGMODE_FRACTIONAL_ODD,
425 	SPACINGMODE_FRACTIONAL_EVEN,
426 
427 	SPACINGMODE_LAST
428 };
429 
430 enum Winding
431 {
432 	WINDING_CCW = 0,
433 	WINDING_CW,
434 
435 	WINDING_LAST
436 };
437 
getTessPrimitiveTypeShaderName(TessPrimitiveType type)438 static inline const char* getTessPrimitiveTypeShaderName (TessPrimitiveType type)
439 {
440 	switch (type)
441 	{
442 		case TESSPRIMITIVETYPE_TRIANGLES:	return "triangles";
443 		case TESSPRIMITIVETYPE_QUADS:		return "quads";
444 		case TESSPRIMITIVETYPE_ISOLINES:	return "isolines";
445 		default:
446 			DE_ASSERT(false);
447 			return DE_NULL;
448 	}
449 }
450 
getSpacingModeShaderName(SpacingMode mode)451 static inline const char* getSpacingModeShaderName (SpacingMode mode)
452 {
453 	switch (mode)
454 	{
455 		case SPACINGMODE_EQUAL:				return "equal_spacing";
456 		case SPACINGMODE_FRACTIONAL_ODD:	return "fractional_odd_spacing";
457 		case SPACINGMODE_FRACTIONAL_EVEN:	return "fractional_even_spacing";
458 		default:
459 			DE_ASSERT(false);
460 			return DE_NULL;
461 	}
462 }
463 
getWindingShaderName(Winding winding)464 static inline const char* getWindingShaderName (Winding winding)
465 {
466 	switch (winding)
467 	{
468 		case WINDING_CCW:	return "ccw";
469 		case WINDING_CW:	return "cw";
470 		default:
471 			DE_ASSERT(false);
472 			return DE_NULL;
473 	}
474 }
475 
getTessellationEvaluationInLayoutString(TessPrimitiveType primType,SpacingMode spacing,Winding winding,bool usePointMode=false)476 static inline string getTessellationEvaluationInLayoutString (TessPrimitiveType primType, SpacingMode spacing, Winding winding, bool usePointMode=false)
477 {
478 	return string() + "layout (" + getTessPrimitiveTypeShaderName(primType)
479 								 + ", " + getSpacingModeShaderName(spacing)
480 								 + ", " + getWindingShaderName(winding)
481 								 + (usePointMode ? ", point_mode" : "")
482 								 + ") in;\n";
483 }
484 
getTessellationEvaluationInLayoutString(TessPrimitiveType primType,SpacingMode spacing,bool usePointMode=false)485 static inline string getTessellationEvaluationInLayoutString (TessPrimitiveType primType, SpacingMode spacing, bool usePointMode=false)
486 {
487 	return string() + "layout (" + getTessPrimitiveTypeShaderName(primType)
488 								 + ", " + getSpacingModeShaderName(spacing)
489 								 + (usePointMode ? ", point_mode" : "")
490 								 + ") in;\n";
491 }
492 
getTessellationEvaluationInLayoutString(TessPrimitiveType primType,Winding winding,bool usePointMode=false)493 static inline string getTessellationEvaluationInLayoutString (TessPrimitiveType primType, Winding winding, bool usePointMode=false)
494 {
495 	return string() + "layout (" + getTessPrimitiveTypeShaderName(primType)
496 								 + ", " + getWindingShaderName(winding)
497 								 + (usePointMode ? ", point_mode" : "")
498 								 + ") in;\n";
499 }
500 
getTessellationEvaluationInLayoutString(TessPrimitiveType primType,bool usePointMode=false)501 static inline string getTessellationEvaluationInLayoutString (TessPrimitiveType primType, bool usePointMode=false)
502 {
503 	return string() + "layout (" + getTessPrimitiveTypeShaderName(primType)
504 								 + (usePointMode ? ", point_mode" : "")
505 								 + ") in;\n";
506 }
507 
outputPrimitiveTypeGL(TessPrimitiveType tessPrimType,bool usePointMode)508 static inline deUint32 outputPrimitiveTypeGL (TessPrimitiveType tessPrimType, bool usePointMode)
509 {
510 	if (usePointMode)
511 		return GL_POINTS;
512 	else
513 	{
514 		switch (tessPrimType)
515 		{
516 			case TESSPRIMITIVETYPE_TRIANGLES:	return GL_TRIANGLES;
517 			case TESSPRIMITIVETYPE_QUADS:		return GL_TRIANGLES;
518 			case TESSPRIMITIVETYPE_ISOLINES:	return GL_LINES;
519 			default:
520 				DE_ASSERT(false);
521 				return (deUint32)-1;
522 		}
523 	}
524 }
525 
numInnerTessellationLevels(TessPrimitiveType primType)526 static inline int numInnerTessellationLevels (TessPrimitiveType primType)
527 {
528 	switch (primType)
529 	{
530 		case TESSPRIMITIVETYPE_TRIANGLES:	return 1;
531 		case TESSPRIMITIVETYPE_QUADS:		return 2;
532 		case TESSPRIMITIVETYPE_ISOLINES:	return 0;
533 		default: DE_ASSERT(false); return -1;
534 	}
535 }
536 
numOuterTessellationLevels(TessPrimitiveType primType)537 static inline int numOuterTessellationLevels (TessPrimitiveType primType)
538 {
539 	switch (primType)
540 	{
541 		case TESSPRIMITIVETYPE_TRIANGLES:	return 3;
542 		case TESSPRIMITIVETYPE_QUADS:		return 4;
543 		case TESSPRIMITIVETYPE_ISOLINES:	return 2;
544 		default: DE_ASSERT(false); return -1;
545 	}
546 }
547 
tessellationLevelsString(const float * inner,int numInner,const float * outer,int numOuter)548 static string tessellationLevelsString (const float* inner, int numInner, const float* outer, int numOuter)
549 {
550 	DE_ASSERT(numInner >= 0 && numOuter >= 0);
551 	return "inner: " + elemsStr(inner, inner+numInner) + ", outer: " + elemsStr(outer, outer+numOuter);
552 }
553 
tessellationLevelsString(const float * inner,const float * outer,TessPrimitiveType primType)554 static string tessellationLevelsString (const float* inner, const float* outer, TessPrimitiveType primType)
555 {
556 	return tessellationLevelsString(inner, numInnerTessellationLevels(primType), outer, numOuterTessellationLevels(primType));
557 }
558 
tessellationLevelsString(const float * inner,const float * outer)559 static string tessellationLevelsString (const float* inner, const float* outer)
560 {
561 	return tessellationLevelsString(inner, 2, outer, 4);
562 }
563 
getClampedTessLevel(SpacingMode mode,float tessLevel)564 static inline float getClampedTessLevel (SpacingMode mode, float tessLevel)
565 {
566 	switch (mode)
567 	{
568 		case SPACINGMODE_EQUAL:				return de::max(1.0f, tessLevel);
569 		case SPACINGMODE_FRACTIONAL_ODD:	return de::max(1.0f, tessLevel);
570 		case SPACINGMODE_FRACTIONAL_EVEN:	return de::max(2.0f, tessLevel);
571 		default:
572 			DE_ASSERT(false);
573 			return -1.0f;
574 	}
575 }
576 
getRoundedTessLevel(SpacingMode mode,float clampedTessLevel)577 static inline int getRoundedTessLevel (SpacingMode mode, float clampedTessLevel)
578 {
579 	int result = (int)deFloatCeil(clampedTessLevel);
580 
581 	switch (mode)
582 	{
583 		case SPACINGMODE_EQUAL:											break;
584 		case SPACINGMODE_FRACTIONAL_ODD:	result += 1 - result % 2;	break;
585 		case SPACINGMODE_FRACTIONAL_EVEN:	result += result % 2;		break;
586 		default:
587 			DE_ASSERT(false);
588 	}
589 	DE_ASSERT(de::inRange<int>(result, 1, MINIMUM_MAX_TESS_GEN_LEVEL));
590 
591 	return result;
592 }
593 
getClampedRoundedTessLevel(SpacingMode mode,float tessLevel)594 static int getClampedRoundedTessLevel (SpacingMode mode, float tessLevel)
595 {
596 	return getRoundedTessLevel(mode, getClampedTessLevel(mode, tessLevel));
597 }
598 
599 //! A description of an outer edge of a triangle, quad or isolines.
600 //! An outer edge can be described by the index of a u/v/w coordinate
601 //! and the coordinate's value along that edge.
602 struct OuterEdgeDescription
603 {
604 	int		constantCoordinateIndex;
605 	float	constantCoordinateValueChoices[2];
606 	int		numConstantCoordinateValueChoices;
607 
OuterEdgeDescriptiondeqp::gles31::Functional::__anon4a9088cf0211::OuterEdgeDescription608 	OuterEdgeDescription (int i, float c0)			: constantCoordinateIndex(i), numConstantCoordinateValueChoices(1) { constantCoordinateValueChoices[0] = c0; }
OuterEdgeDescriptiondeqp::gles31::Functional::__anon4a9088cf0211::OuterEdgeDescription609 	OuterEdgeDescription (int i, float c0, float c1)	: constantCoordinateIndex(i), numConstantCoordinateValueChoices(2) { constantCoordinateValueChoices[0] = c0; constantCoordinateValueChoices[1] = c1; }
610 
descriptiondeqp::gles31::Functional::__anon4a9088cf0211::OuterEdgeDescription611 	string description (void) const
612 	{
613 		static const char* const	coordinateNames[] = { "u", "v", "w" };
614 		string						result;
615 		for (int i = 0; i < numConstantCoordinateValueChoices; i++)
616 			result += string() + (i > 0 ? " or " : "") + coordinateNames[constantCoordinateIndex] + "=" + de::toString(constantCoordinateValueChoices[i]);
617 		return result;
618 	}
619 
containsdeqp::gles31::Functional::__anon4a9088cf0211::OuterEdgeDescription620 	bool contains (const Vec3& v) const
621 	{
622 		for (int i = 0; i < numConstantCoordinateValueChoices; i++)
623 			if (v[constantCoordinateIndex] == constantCoordinateValueChoices[i])
624 				return true;
625 		return false;
626 	}
627 };
628 
outerEdgeDescriptions(TessPrimitiveType primType)629 static vector<OuterEdgeDescription> outerEdgeDescriptions (TessPrimitiveType primType)
630 {
631 	static const OuterEdgeDescription triangleOuterEdgeDescriptions[3] =
632 	{
633 		OuterEdgeDescription(0, 0.0f),
634 		OuterEdgeDescription(1, 0.0f),
635 		OuterEdgeDescription(2, 0.0f)
636 	};
637 
638 	static const OuterEdgeDescription quadOuterEdgeDescriptions[4] =
639 	{
640 		OuterEdgeDescription(0, 0.0f),
641 		OuterEdgeDescription(1, 0.0f),
642 		OuterEdgeDescription(0, 1.0f),
643 		OuterEdgeDescription(1, 1.0f)
644 	};
645 
646 	static const OuterEdgeDescription isolinesOuterEdgeDescriptions[1] =
647 	{
648 		OuterEdgeDescription(0, 0.0f, 1.0f),
649 	};
650 
651 	switch (primType)
652 	{
653 		case TESSPRIMITIVETYPE_TRIANGLES:	return arrayToVector(triangleOuterEdgeDescriptions);
654 		case TESSPRIMITIVETYPE_QUADS:		return arrayToVector(quadOuterEdgeDescriptions);
655 		case TESSPRIMITIVETYPE_ISOLINES:	return arrayToVector(isolinesOuterEdgeDescriptions);
656 		default: DE_ASSERT(false); return vector<OuterEdgeDescription>();
657 	}
658 }
659 
660 // \note The tessellation coordinates generated by this function could break some of the rules given in the spec (e.g. it may not exactly hold that u+v+w == 1.0f, or [uvw] + (1.0f-[uvw]) == 1.0f).
generateReferenceTriangleTessCoords(SpacingMode spacingMode,int inner,int outer0,int outer1,int outer2)661 static vector<Vec3> generateReferenceTriangleTessCoords (SpacingMode spacingMode, int inner, int outer0, int outer1, int outer2)
662 {
663 	vector<Vec3> tessCoords;
664 
665 	if (inner == 1)
666 	{
667 		if (outer0 == 1 && outer1 == 1 && outer2 == 1)
668 		{
669 			tessCoords.push_back(Vec3(1.0f, 0.0f, 0.0f));
670 			tessCoords.push_back(Vec3(0.0f, 1.0f, 0.0f));
671 			tessCoords.push_back(Vec3(0.0f, 0.0f, 1.0f));
672 			return tessCoords;
673 		}
674 		else
675 			return generateReferenceTriangleTessCoords(spacingMode, spacingMode == SPACINGMODE_FRACTIONAL_ODD ? 3 : 2,
676 																	outer0, outer1, outer2);
677 	}
678 	else
679 	{
680 		for (int i = 0; i < outer0; i++) { const float v = (float)i / (float)outer0; tessCoords.push_back(Vec3(	   0.0f,		   v,	1.0f - v)); }
681 		for (int i = 0; i < outer1; i++) { const float v = (float)i / (float)outer1; tessCoords.push_back(Vec3(1.0f - v,		0.0f,		   v)); }
682 		for (int i = 0; i < outer2; i++) { const float v = (float)i / (float)outer2; tessCoords.push_back(Vec3(		  v,	1.0f - v,		0.0f)); }
683 
684 		const int numInnerTriangles = inner/2;
685 		for (int innerTriangleNdx = 0; innerTriangleNdx < numInnerTriangles; innerTriangleNdx++)
686 		{
687 			const int curInnerTriangleLevel = inner - 2*(innerTriangleNdx+1);
688 
689 			if (curInnerTriangleLevel == 0)
690 				tessCoords.push_back(Vec3(1.0f/3.0f));
691 			else
692 			{
693 				const float		minUVW		= (float)(2 * (innerTriangleNdx + 1)) / (float)(3 * inner);
694 				const float		maxUVW		= 1.0f - 2.0f*minUVW;
695 				const Vec3		corners[3]	=
696 				{
697 					Vec3(maxUVW, minUVW, minUVW),
698 					Vec3(minUVW, maxUVW, minUVW),
699 					Vec3(minUVW, minUVW, maxUVW)
700 				};
701 
702 				for (int i = 0; i < curInnerTriangleLevel; i++)
703 				{
704 					const float f = (float)i / (float)curInnerTriangleLevel;
705 					for (int j = 0; j < 3; j++)
706 						tessCoords.push_back((1.0f - f)*corners[j] + f*corners[(j+1)%3]);
707 				}
708 			}
709 		}
710 
711 		return tessCoords;
712 	}
713 }
714 
referenceTriangleNonPointModePrimitiveCount(SpacingMode spacingMode,int inner,int outer0,int outer1,int outer2)715 static int referenceTriangleNonPointModePrimitiveCount (SpacingMode spacingMode, int inner, int outer0, int outer1, int outer2)
716 {
717 	if (inner == 1)
718 	{
719 		if (outer0 == 1 && outer1 == 1 && outer2 == 1)
720 			return 1;
721 		else
722 			return referenceTriangleNonPointModePrimitiveCount(spacingMode, spacingMode == SPACINGMODE_FRACTIONAL_ODD ? 3 : 2,
723 																			outer0, outer1, outer2);
724 	}
725 	else
726 	{
727 		int result = outer0 + outer1 + outer2;
728 
729 		const int numInnerTriangles = inner/2;
730 		for (int innerTriangleNdx = 0; innerTriangleNdx < numInnerTriangles; innerTriangleNdx++)
731 		{
732 			const int curInnerTriangleLevel = inner - 2*(innerTriangleNdx+1);
733 
734 			if (curInnerTriangleLevel == 1)
735 				result += 4;
736 			else
737 				result += 2*3*curInnerTriangleLevel;
738 		}
739 
740 		return result;
741 	}
742 }
743 
744 // \note The tessellation coordinates generated by this function could break some of the rules given in the spec (e.g. it may not exactly hold that [uv] + (1.0f-[uv]) == 1.0f).
generateReferenceQuadTessCoords(SpacingMode spacingMode,int inner0,int inner1,int outer0,int outer1,int outer2,int outer3)745 static vector<Vec3> generateReferenceQuadTessCoords (SpacingMode spacingMode, int inner0, int inner1, int outer0, int outer1, int outer2, int outer3)
746 {
747 	vector<Vec3> tessCoords;
748 
749 	if (inner0 == 1 || inner1 == 1)
750 	{
751 		if (inner0 == 1 && inner1 == 1 && outer0 == 1 && outer1 == 1 && outer2 == 1 && outer3 == 1)
752 		{
753 			tessCoords.push_back(Vec3(0.0f, 0.0f, 0.0f));
754 			tessCoords.push_back(Vec3(1.0f, 0.0f, 0.0f));
755 			tessCoords.push_back(Vec3(0.0f, 1.0f, 0.0f));
756 			tessCoords.push_back(Vec3(1.0f, 1.0f, 0.0f));
757 			return tessCoords;
758 		}
759 		else
760 			return generateReferenceQuadTessCoords(spacingMode, inner0 > 1 ? inner0 : spacingMode == SPACINGMODE_FRACTIONAL_ODD ? 3 : 2,
761 																inner1 > 1 ? inner1 : spacingMode == SPACINGMODE_FRACTIONAL_ODD ? 3 : 2,
762 																outer0, outer1, outer2, outer3);
763 	}
764 	else
765 	{
766 		for (int i = 0; i < outer0; i++) { const float v = (float)i / (float)outer0; tessCoords.push_back(Vec3(0.0f,	v,			0.0f)); }
767 		for (int i = 0; i < outer1; i++) { const float v = (float)i / (float)outer1; tessCoords.push_back(Vec3(1.0f-v,	0.0f,		0.0f)); }
768 		for (int i = 0; i < outer2; i++) { const float v = (float)i / (float)outer2; tessCoords.push_back(Vec3(1.0f,	1.0f-v,		0.0f)); }
769 		for (int i = 0; i < outer3; i++) { const float v = (float)i / (float)outer3; tessCoords.push_back(Vec3(v,		1.0f,		0.0f)); }
770 
771 		for (int innerVtxY = 0; innerVtxY < inner1-1; innerVtxY++)
772 		for (int innerVtxX = 0; innerVtxX < inner0-1; innerVtxX++)
773 			tessCoords.push_back(Vec3((float)(innerVtxX + 1) / (float)inner0,
774 									  (float)(innerVtxY + 1) / (float)inner1,
775 									  0.0f));
776 
777 		return tessCoords;
778 	}
779 }
780 
referenceQuadNonPointModePrimitiveCount(SpacingMode spacingMode,int inner0,int inner1,int outer0,int outer1,int outer2,int outer3)781 static int referenceQuadNonPointModePrimitiveCount (SpacingMode spacingMode, int inner0, int inner1, int outer0, int outer1, int outer2, int outer3)
782 {
783 	vector<Vec3> tessCoords;
784 
785 	if (inner0 == 1 || inner1 == 1)
786 	{
787 		if (inner0 == 1 && inner1 == 1 && outer0 == 1 && outer1 == 1 && outer2 == 1 && outer3 == 1)
788 			return 2;
789 		else
790 			return referenceQuadNonPointModePrimitiveCount(spacingMode, inner0 > 1 ? inner0 : spacingMode == SPACINGMODE_FRACTIONAL_ODD ? 3 : 2,
791 																		inner1 > 1 ? inner1 : spacingMode == SPACINGMODE_FRACTIONAL_ODD ? 3 : 2,
792 																		outer0, outer1, outer2, outer3);
793 	}
794 	else
795 		return 2*(inner0-2)*(inner1-2) + 2*(inner0-2) + 2*(inner1-2) + outer0+outer1+outer2+outer3;
796 }
797 
798 // \note The tessellation coordinates generated by this function could break some of the rules given in the spec (e.g. it may not exactly hold that [uv] + (1.0f-[uv]) == 1.0f).
generateReferenceIsolineTessCoords(int outer0,int outer1)799 static vector<Vec3> generateReferenceIsolineTessCoords (int outer0, int outer1)
800 {
801 	vector<Vec3> tessCoords;
802 
803 	for (int y = 0; y < outer0;		y++)
804 	for (int x = 0; x < outer1+1;	x++)
805 		tessCoords.push_back(Vec3((float)x / (float)outer1,
806 												  (float)y / (float)outer0,
807 												  0.0f));
808 
809 	return tessCoords;
810 }
811 
referenceIsolineNonPointModePrimitiveCount(int outer0,int outer1)812 static int referenceIsolineNonPointModePrimitiveCount (int outer0, int outer1)
813 {
814 	return outer0*outer1;
815 }
816 
getClampedRoundedTriangleTessLevels(SpacingMode spacingMode,const float * innerSrc,const float * outerSrc,int * innerDst,int * outerDst)817 static void getClampedRoundedTriangleTessLevels (SpacingMode spacingMode, const float* innerSrc, const float* outerSrc, int* innerDst, int *outerDst)
818 {
819 	innerDst[0] = getClampedRoundedTessLevel(spacingMode, innerSrc[0]);
820 	for (int i = 0; i < 3; i++)
821 		outerDst[i] = getClampedRoundedTessLevel(spacingMode, outerSrc[i]);
822 }
823 
getClampedRoundedQuadTessLevels(SpacingMode spacingMode,const float * innerSrc,const float * outerSrc,int * innerDst,int * outerDst)824 static void getClampedRoundedQuadTessLevels (SpacingMode spacingMode, const float* innerSrc, const float* outerSrc, int* innerDst, int *outerDst)
825 {
826 	for (int i = 0; i < 2; i++)
827 		innerDst[i] = getClampedRoundedTessLevel(spacingMode, innerSrc[i]);
828 	for (int i = 0; i < 4; i++)
829 		outerDst[i] = getClampedRoundedTessLevel(spacingMode, outerSrc[i]);
830 }
831 
getClampedRoundedIsolineTessLevels(SpacingMode spacingMode,const float * outerSrc,int * outerDst)832 static void getClampedRoundedIsolineTessLevels (SpacingMode spacingMode, const float* outerSrc, int* outerDst)
833 {
834 	outerDst[0] = getClampedRoundedTessLevel(SPACINGMODE_EQUAL,	outerSrc[0]);
835 	outerDst[1] = getClampedRoundedTessLevel(spacingMode,		outerSrc[1]);
836 }
837 
isPatchDiscarded(TessPrimitiveType primitiveType,const float * outerLevels)838 static inline bool isPatchDiscarded (TessPrimitiveType primitiveType, const float* outerLevels)
839 {
840 	const int numOuterLevels = numOuterTessellationLevels(primitiveType);
841 	for (int i = 0; i < numOuterLevels; i++)
842 		if (outerLevels[i] <= 0.0f)
843 			return true;
844 	return false;
845 }
846 
generateReferenceTessCoords(TessPrimitiveType primitiveType,SpacingMode spacingMode,const float * innerLevels,const float * outerLevels)847 static vector<Vec3> generateReferenceTessCoords (TessPrimitiveType primitiveType, SpacingMode spacingMode, const float* innerLevels, const float* outerLevels)
848 {
849 	if (isPatchDiscarded(primitiveType, outerLevels))
850 		return vector<Vec3>();
851 
852 	switch (primitiveType)
853 	{
854 		case TESSPRIMITIVETYPE_TRIANGLES:
855 		{
856 			int inner;
857 			int outer[3];
858 			getClampedRoundedTriangleTessLevels(spacingMode, innerLevels, outerLevels, &inner, &outer[0]);
859 
860 			if (spacingMode != SPACINGMODE_EQUAL)
861 			{
862 				// \note For fractional spacing modes, exact results are implementation-defined except in special cases.
863 				DE_ASSERT(de::abs(innerLevels[0] - (float)inner) < 0.001f);
864 				for (int i = 0; i < 3; i++)
865 					DE_ASSERT(de::abs(outerLevels[i] - (float)outer[i]) < 0.001f);
866 				DE_ASSERT(inner > 1 || (outer[0] == 1 && outer[1] == 1 && outer[2] == 1));
867 			}
868 
869 			return generateReferenceTriangleTessCoords(spacingMode, inner, outer[0], outer[1], outer[2]);
870 		}
871 
872 		case TESSPRIMITIVETYPE_QUADS:
873 		{
874 			int inner[2];
875 			int outer[4];
876 			getClampedRoundedQuadTessLevels(spacingMode, innerLevels, outerLevels, &inner[0], &outer[0]);
877 
878 			if (spacingMode != SPACINGMODE_EQUAL)
879 			{
880 				// \note For fractional spacing modes, exact results are implementation-defined except in special cases.
881 				for (int i = 0; i < 2; i++)
882 					DE_ASSERT(de::abs(innerLevels[i] - (float)inner[i]) < 0.001f);
883 				for (int i = 0; i < 4; i++)
884 					DE_ASSERT(de::abs(outerLevels[i] - (float)outer[i]) < 0.001f);
885 
886 				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));
887 			}
888 
889 			return generateReferenceQuadTessCoords(spacingMode, inner[0], inner[1], outer[0], outer[1], outer[2], outer[3]);
890 		}
891 
892 		case TESSPRIMITIVETYPE_ISOLINES:
893 		{
894 			int outer[2];
895 			getClampedRoundedIsolineTessLevels(spacingMode, &outerLevels[0], &outer[0]);
896 
897 			if (spacingMode != SPACINGMODE_EQUAL)
898 			{
899 				// \note For fractional spacing modes, exact results are implementation-defined except in special cases.
900 				DE_ASSERT(de::abs(outerLevels[1] - (float)outer[1]) < 0.001f);
901 			}
902 
903 			return generateReferenceIsolineTessCoords(outer[0], outer[1]);
904 		}
905 
906 		default:
907 			DE_ASSERT(false);
908 			return vector<Vec3>();
909 	}
910 }
911 
referencePointModePrimitiveCount(TessPrimitiveType primitiveType,SpacingMode spacingMode,const float * innerLevels,const float * outerLevels)912 static int referencePointModePrimitiveCount (TessPrimitiveType primitiveType, SpacingMode spacingMode, const float* innerLevels, const float* outerLevels)
913 {
914 	if (isPatchDiscarded(primitiveType, outerLevels))
915 		return 0;
916 
917 	switch (primitiveType)
918 	{
919 		case TESSPRIMITIVETYPE_TRIANGLES:
920 		{
921 			int inner;
922 			int outer[3];
923 			getClampedRoundedTriangleTessLevels(spacingMode, innerLevels, outerLevels, &inner, &outer[0]);
924 			return (int)generateReferenceTriangleTessCoords(spacingMode, inner, outer[0], outer[1], outer[2]).size();
925 		}
926 
927 		case TESSPRIMITIVETYPE_QUADS:
928 		{
929 			int inner[2];
930 			int outer[4];
931 			getClampedRoundedQuadTessLevels(spacingMode, innerLevels, outerLevels, &inner[0], &outer[0]);
932 			return (int)generateReferenceQuadTessCoords(spacingMode, inner[0], inner[1], outer[0], outer[1], outer[2], outer[3]).size();
933 		}
934 
935 		case TESSPRIMITIVETYPE_ISOLINES:
936 		{
937 			int outer[2];
938 			getClampedRoundedIsolineTessLevels(spacingMode, &outerLevels[0], &outer[0]);
939 			return (int)generateReferenceIsolineTessCoords(outer[0], outer[1]).size();
940 		}
941 
942 		default:
943 			DE_ASSERT(false);
944 			return -1;
945 	}
946 }
947 
referenceNonPointModePrimitiveCount(TessPrimitiveType primitiveType,SpacingMode spacingMode,const float * innerLevels,const float * outerLevels)948 static int referenceNonPointModePrimitiveCount (TessPrimitiveType primitiveType, SpacingMode spacingMode, const float* innerLevels, const float* outerLevels)
949 {
950 	if (isPatchDiscarded(primitiveType, outerLevels))
951 		return 0;
952 
953 	switch (primitiveType)
954 	{
955 		case TESSPRIMITIVETYPE_TRIANGLES:
956 		{
957 			int inner;
958 			int outer[3];
959 			getClampedRoundedTriangleTessLevels(spacingMode, innerLevels, outerLevels, &inner, &outer[0]);
960 			return referenceTriangleNonPointModePrimitiveCount(spacingMode, inner, outer[0], outer[1], outer[2]);
961 		}
962 
963 		case TESSPRIMITIVETYPE_QUADS:
964 		{
965 			int inner[2];
966 			int outer[4];
967 			getClampedRoundedQuadTessLevels(spacingMode, innerLevels, outerLevels, &inner[0], &outer[0]);
968 			return referenceQuadNonPointModePrimitiveCount(spacingMode, inner[0], inner[1], outer[0], outer[1], outer[2], outer[3]);
969 		}
970 
971 		case TESSPRIMITIVETYPE_ISOLINES:
972 		{
973 			int outer[2];
974 			getClampedRoundedIsolineTessLevels(spacingMode, &outerLevels[0], &outer[0]);
975 			return referenceIsolineNonPointModePrimitiveCount(outer[0], outer[1]);
976 		}
977 
978 		default:
979 			DE_ASSERT(false);
980 			return -1;
981 	}
982 }
983 
referencePrimitiveCount(TessPrimitiveType primitiveType,SpacingMode spacingMode,bool usePointMode,const float * innerLevels,const float * outerLevels)984 static int referencePrimitiveCount (TessPrimitiveType primitiveType, SpacingMode spacingMode, bool usePointMode, const float* innerLevels, const float* outerLevels)
985 {
986 	return usePointMode ? referencePointModePrimitiveCount		(primitiveType, spacingMode, innerLevels, outerLevels)
987 						: referenceNonPointModePrimitiveCount	(primitiveType, spacingMode, innerLevels, outerLevels);
988 }
989 
referenceVertexCount(TessPrimitiveType primitiveType,SpacingMode spacingMode,bool usePointMode,const float * innerLevels,const float * outerLevels)990 static int referenceVertexCount (TessPrimitiveType primitiveType, SpacingMode spacingMode, bool usePointMode, const float* innerLevels, const float* outerLevels)
991 {
992 	return referencePrimitiveCount(primitiveType, spacingMode, usePointMode, innerLevels, outerLevels)
993 		   * numVerticesPerPrimitive(outputPrimitiveTypeGL(primitiveType, usePointMode));
994 }
995 
996 //! Helper for calling referenceVertexCount multiple times with different tessellation levels.
997 //! \note Levels contains inner and outer levels, per patch, in order IIOOOO. The full 6 levels must always be present, irrespective of primitiveType.
multiplePatchReferenceVertexCount(TessPrimitiveType primitiveType,SpacingMode spacingMode,bool usePointMode,const float * levels,int numPatches)998 static int multiplePatchReferenceVertexCount (TessPrimitiveType primitiveType, SpacingMode spacingMode, bool usePointMode, const float* levels, int numPatches)
999 {
1000 	int result = 0;
1001 	for (int patchNdx = 0; patchNdx < numPatches; patchNdx++)
1002 		result += referenceVertexCount(primitiveType, spacingMode, usePointMode, &levels[6*patchNdx + 0], &levels[6*patchNdx + 2]);
1003 	return result;
1004 }
1005 
generateRandomPatchTessLevels(int numPatches,int constantOuterLevelIndex,float constantOuterLevel,de::Random & rnd)1006 vector<float> generateRandomPatchTessLevels (int numPatches, int constantOuterLevelIndex, float constantOuterLevel, de::Random& rnd)
1007 {
1008 	vector<float> tessLevels(numPatches*6);
1009 
1010 	for (int patchNdx = 0; patchNdx < numPatches; patchNdx++)
1011 	{
1012 		float* const inner = &tessLevels[patchNdx*6 + 0];
1013 		float* const outer = &tessLevels[patchNdx*6 + 2];
1014 
1015 		for (int j = 0; j < 2; j++)
1016 			inner[j] = rnd.getFloat(1.0f, 62.0f);
1017 		for (int j = 0; j < 4; j++)
1018 			outer[j] = j == constantOuterLevelIndex ? constantOuterLevel : rnd.getFloat(1.0f, 62.0f);
1019 	}
1020 
1021 	return tessLevels;
1022 }
1023 
drawPoint(tcu::Surface & dst,int centerX,int centerY,const tcu::RGBA & color,int size)1024 static inline void drawPoint (tcu::Surface& dst, int centerX, int centerY, const tcu::RGBA& color, int size)
1025 {
1026 	const int width		= dst.getWidth();
1027 	const int height	= dst.getHeight();
1028 	DE_ASSERT(de::inBounds(centerX, 0, width) && de::inBounds(centerY, 0, height));
1029 	DE_ASSERT(size > 0);
1030 
1031 	for (int yOff = -((size-1)/2); yOff <= size/2; yOff++)
1032 	for (int xOff = -((size-1)/2); xOff <= size/2; xOff++)
1033 	{
1034 		const int pixX = centerX + xOff;
1035 		const int pixY = centerY + yOff;
1036 		if (de::inBounds(pixX, 0, width) && de::inBounds(pixY, 0, height))
1037 			dst.setPixel(pixX, pixY, color);
1038 	}
1039 }
1040 
drawTessCoordPoint(tcu::Surface & dst,TessPrimitiveType primitiveType,const Vec3 & pt,const tcu::RGBA & color,int size)1041 static void drawTessCoordPoint (tcu::Surface& dst, TessPrimitiveType primitiveType, const Vec3& pt, const tcu::RGBA& color, int size)
1042 {
1043 	// \note These coordinates should match the description in the log message in TessCoordCase::iterate.
1044 
1045 	static const Vec2 triangleCorners[3] =
1046 	{
1047 		Vec2(0.95f, 0.95f),
1048 		Vec2(0.5f,  0.95f - 0.9f*deFloatSqrt(3.0f/4.0f)),
1049 		Vec2(0.05f, 0.95f)
1050 	};
1051 
1052 	static const float quadIsolineLDRU[4] =
1053 	{
1054 		0.1f, 0.9f, 0.9f, 0.1f
1055 	};
1056 
1057 	const Vec2 dstPos = primitiveType == TESSPRIMITIVETYPE_TRIANGLES ? pt.x()*triangleCorners[0]
1058 																	 + pt.y()*triangleCorners[1]
1059 																	 + pt.z()*triangleCorners[2]
1060 
1061 					  : primitiveType == TESSPRIMITIVETYPE_QUADS ||
1062 						primitiveType == TESSPRIMITIVETYPE_ISOLINES ? Vec2((1.0f - pt.x())*quadIsolineLDRU[0] + pt.x()*quadIsolineLDRU[2],
1063 																		   (1.0f - pt.y())*quadIsolineLDRU[1] + pt.y()*quadIsolineLDRU[3])
1064 
1065 					  : Vec2(-1.0f);
1066 
1067 	drawPoint(dst, (int)(dstPos.x() * (float)dst.getWidth()), (int)(dstPos.y() * (float)dst.getHeight()), color, size);
1068 }
1069 
drawTessCoordVisualization(tcu::Surface & dst,TessPrimitiveType primitiveType,const vector<Vec3> & coords)1070 static void drawTessCoordVisualization (tcu::Surface& dst, TessPrimitiveType primitiveType, const vector<Vec3>& coords)
1071 {
1072 	const int		imageWidth		= 256;
1073 	const int		imageHeight		= 256;
1074 	dst.setSize(imageWidth, imageHeight);
1075 
1076 	tcu::clear(dst.getAccess(), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
1077 
1078 	for (int i = 0; i < (int)coords.size(); i++)
1079 		drawTessCoordPoint(dst, primitiveType, coords[i], tcu::RGBA::white(), 2);
1080 }
1081 
binarySearchFirstVec3WithXAtLeast(const vector<Vec3> & sorted,float x)1082 static int binarySearchFirstVec3WithXAtLeast (const vector<Vec3>& sorted, float x)
1083 {
1084 	const Vec3 ref(x, 0.0f, 0.0f);
1085 	const vector<Vec3>::const_iterator first = std::lower_bound(sorted.begin(), sorted.end(), ref, vec3XLessThan);
1086 	if (first == sorted.end())
1087 		return -1;
1088 	return (int)std::distance(sorted.begin(), first);
1089 }
1090 
1091 template <typename T, typename P>
sorted(const vector<T> & unsorted,P pred)1092 static vector<T> sorted (const vector<T>& unsorted, P pred)
1093 {
1094 	vector<T> result = unsorted;
1095 	std::sort(result.begin(), result.end(), pred);
1096 	return result;
1097 }
1098 
1099 template <typename T>
sorted(const vector<T> & unsorted)1100 static vector<T> sorted (const vector<T>& unsorted)
1101 {
1102 	vector<T> result = unsorted;
1103 	std::sort(result.begin(), result.end());
1104 	return result;
1105 }
1106 
1107 // Check that all points in subset are (approximately) present also in superset.
oneWayComparePointSets(TestLog & log,tcu::Surface & errorDst,TessPrimitiveType primitiveType,const vector<Vec3> & subset,const vector<Vec3> & superset,const char * subsetName,const char * supersetName,const tcu::RGBA & errorColor)1108 static bool oneWayComparePointSets (TestLog&				log,
1109 									tcu::Surface&			errorDst,
1110 									TessPrimitiveType		primitiveType,
1111 									const vector<Vec3>&		subset,
1112 									const vector<Vec3>&		superset,
1113 									const char*				subsetName,
1114 									const char*				supersetName,
1115 									const tcu::RGBA&		errorColor)
1116 {
1117 	const vector<Vec3>	supersetSorted			= sorted(superset, vec3XLessThan);
1118 	const float			epsilon					= 0.01f;
1119 	const int			maxNumFailurePrints		= 5;
1120 	int					numFailuresDetected		= 0;
1121 
1122 	for (int subNdx = 0; subNdx < (int)subset.size(); subNdx++)
1123 	{
1124 		const Vec3& subPt = subset[subNdx];
1125 
1126 		bool matchFound = false;
1127 
1128 		{
1129 			// Binary search the index of the first point in supersetSorted with x in the [subPt.x() - epsilon, subPt.x() + epsilon] range.
1130 			const Vec3	matchMin			= subPt - epsilon;
1131 			const Vec3	matchMax			= subPt + epsilon;
1132 			int			firstCandidateNdx	= binarySearchFirstVec3WithXAtLeast(supersetSorted, matchMin.x());
1133 
1134 			if (firstCandidateNdx >= 0)
1135 			{
1136 				// Compare subPt to all points in supersetSorted with x in the [subPt.x() - epsilon, subPt.x() + epsilon] range.
1137 				for (int superNdx = firstCandidateNdx; superNdx < (int)supersetSorted.size() && supersetSorted[superNdx].x() <= matchMax.x(); superNdx++)
1138 				{
1139 					const Vec3& superPt = supersetSorted[superNdx];
1140 
1141 					if (tcu::boolAll(tcu::greaterThanEqual	(superPt, matchMin)) &&
1142 						tcu::boolAll(tcu::lessThanEqual		(superPt, matchMax)))
1143 					{
1144 						matchFound = true;
1145 						break;
1146 					}
1147 				}
1148 			}
1149 		}
1150 
1151 		if (!matchFound)
1152 		{
1153 			numFailuresDetected++;
1154 			if (numFailuresDetected < maxNumFailurePrints)
1155 				log << TestLog::Message << "Failure: no matching " << supersetName << " point found for " << subsetName << " point " << subPt << TestLog::EndMessage;
1156 			else if (numFailuresDetected == maxNumFailurePrints)
1157 				log << TestLog::Message << "Note: More errors follow" << TestLog::EndMessage;
1158 
1159 			drawTessCoordPoint(errorDst, primitiveType, subPt, errorColor, 4);
1160 		}
1161 	}
1162 
1163 	return numFailuresDetected == 0;
1164 }
1165 
compareTessCoords(TestLog & log,TessPrimitiveType primitiveType,const vector<Vec3> & refCoords,const vector<Vec3> & resCoords)1166 static bool compareTessCoords (TestLog& log, TessPrimitiveType primitiveType, const vector<Vec3>& refCoords, const vector<Vec3>& resCoords)
1167 {
1168 	tcu::Surface	refVisual;
1169 	tcu::Surface	resVisual;
1170 	bool			success = true;
1171 
1172 	drawTessCoordVisualization(refVisual, primitiveType, refCoords);
1173 	drawTessCoordVisualization(resVisual, primitiveType, resCoords);
1174 
1175 	// Check that all points in reference also exist in result.
1176 	success = oneWayComparePointSets(log, refVisual, primitiveType, refCoords, resCoords, "reference", "result", tcu::RGBA::blue()) && success;
1177 	// Check that all points in result also exist in reference.
1178 	success = oneWayComparePointSets(log, resVisual, primitiveType, resCoords, refCoords, "result", "reference", tcu::RGBA::red()) && success;
1179 
1180 	if (!success)
1181 	{
1182 		log << TestLog::Message << "Note: in the following reference visualization, points that are missing in result point set are blue (if any)" << TestLog::EndMessage
1183 			<< TestLog::Image("RefTessCoordVisualization", "Reference tessCoord visualization", refVisual)
1184 			<< TestLog::Message << "Note: in the following result visualization, points that are missing in reference point set are red (if any)" << TestLog::EndMessage;
1185 	}
1186 
1187 	log << TestLog::Image("ResTessCoordVisualization", "Result tessCoord visualization", resVisual);
1188 
1189 	return success;
1190 }
1191 
1192 namespace VerifyFractionalSpacingSingleInternal
1193 {
1194 
1195 struct Segment
1196 {
1197 	int		index; //!< Index of left coordinate in sortedXCoords.
1198 	float	length;
Segmentdeqp::gles31::Functional::__anon4a9088cf0211::VerifyFractionalSpacingSingleInternal::Segment1199 	Segment (void)						: index(-1),		length(-1.0f)	{}
Segmentdeqp::gles31::Functional::__anon4a9088cf0211::VerifyFractionalSpacingSingleInternal::Segment1200 	Segment (int index_, float length_)	: index(index_),	length(length_)	{}
1201 
lengthsdeqp::gles31::Functional::__anon4a9088cf0211::VerifyFractionalSpacingSingleInternal::Segment1202 	static vector<float> lengths (const vector<Segment>& segments) { return members(segments, &Segment::length); }
1203 };
1204 
1205 }
1206 
1207 /*--------------------------------------------------------------------*//*!
1208  * \brief Verify fractional spacing conditions for a single line
1209  *
1210  * Verify that the splitting of an edge (resulting from e.g. an isoline
1211  * with outer levels { 1.0, tessLevel }) with a given fractional spacing
1212  * mode fulfills certain conditions given in the spec.
1213  *
1214  * Note that some conditions can't be checked from just one line
1215  * (specifically, that the additional segment decreases monotonically
1216  * length and the requirement that the additional segments be placed
1217  * identically for identical values of clamped level).
1218  *
1219  * Therefore, the function stores some values to additionalSegmentLengthDst
1220  * and additionalSegmentLocationDst that can later be given to
1221  * verifyFractionalSpacingMultiple(). A negative value in length means that
1222  * no additional segments are present, i.e. there's just one segment.
1223  * A negative value in location means that the value wasn't determinable,
1224  * i.e. all segments had same length.
1225  * The values are not stored if false is returned.
1226  *//*--------------------------------------------------------------------*/
verifyFractionalSpacingSingle(TestLog & log,SpacingMode spacingMode,float tessLevel,const vector<float> & coords,float & additionalSegmentLengthDst,int & additionalSegmentLocationDst)1227 static bool verifyFractionalSpacingSingle (TestLog& log, SpacingMode spacingMode, float tessLevel, const vector<float>& coords, float& additionalSegmentLengthDst, int& additionalSegmentLocationDst)
1228 {
1229 	using namespace VerifyFractionalSpacingSingleInternal;
1230 
1231 	DE_ASSERT(spacingMode == SPACINGMODE_FRACTIONAL_ODD || spacingMode == SPACINGMODE_FRACTIONAL_EVEN);
1232 
1233 	const float				clampedLevel	= getClampedTessLevel(spacingMode, tessLevel);
1234 	const int				finalLevel		= getRoundedTessLevel(spacingMode, clampedLevel);
1235 	const vector<float>		sortedCoords	= sorted(coords);
1236 	string					failNote		= "Note: tessellation level is " + de::toString(tessLevel) + "\nNote: sorted coordinates are:\n    " + containerStr(sortedCoords);
1237 
1238 	if ((int)coords.size() != finalLevel + 1)
1239 	{
1240 		log << TestLog::Message << "Failure: number of vertices is " << coords.size() << "; expected " << finalLevel + 1
1241 			<< " (clamped tessellation level is " << clampedLevel << ")"
1242 			<< "; final level (clamped level rounded up to " << (spacingMode == SPACINGMODE_FRACTIONAL_EVEN ? "even" : "odd") << ") is " << finalLevel
1243 			<< " and should equal the number of segments, i.e. number of vertices minus 1" << TestLog::EndMessage
1244 			<< TestLog::Message << failNote << TestLog::EndMessage;
1245 		return false;
1246 	}
1247 
1248 	if (sortedCoords[0] != 0.0f || sortedCoords.back() != 1.0f)
1249 	{
1250 		log << TestLog::Message << "Failure: smallest coordinate should be 0.0 and biggest should be 1.0" << TestLog::EndMessage
1251 			<< TestLog::Message << failNote << TestLog::EndMessage;
1252 		return false;
1253 	}
1254 
1255 	{
1256 		vector<Segment> segments(finalLevel);
1257 		for (int i = 0; i < finalLevel; i++)
1258 			segments[i] = Segment(i, sortedCoords[i+1] - sortedCoords[i]);
1259 
1260 		failNote += "\nNote: segment lengths are, from left to right:\n    " + containerStr(Segment::lengths(segments));
1261 
1262 		{
1263 			// Divide segments to two different groups based on length.
1264 
1265 			vector<Segment> segmentsA;
1266 			vector<Segment> segmentsB;
1267 			segmentsA.push_back(segments[0]);
1268 
1269 			for (int segNdx = 1; segNdx < (int)segments.size(); segNdx++)
1270 			{
1271 				const float		epsilon		= 0.001f;
1272 				const Segment&	seg			= segments[segNdx];
1273 
1274 				if (de::abs(seg.length - segmentsA[0].length) < epsilon)
1275 					segmentsA.push_back(seg);
1276 				else if (segmentsB.empty() || de::abs(seg.length - segmentsB[0].length) < epsilon)
1277 					segmentsB.push_back(seg);
1278 				else
1279 				{
1280 					log << TestLog::Message << "Failure: couldn't divide segments to 2 groups by length; "
1281 											<< "e.g. segment of length " << seg.length << " isn't approximately equal to either "
1282 											<< segmentsA[0].length << " or " << segmentsB[0].length << TestLog::EndMessage
1283 											<< TestLog::Message << failNote << TestLog::EndMessage;
1284 					return false;
1285 				}
1286 			}
1287 
1288 			if (clampedLevel == (float)finalLevel)
1289 			{
1290 				// All segments should be of equal length.
1291 				if (!segmentsA.empty() && !segmentsB.empty())
1292 				{
1293 					log << TestLog::Message << "Failure: clamped and final tessellation level are equal, but not all segments are of equal length." << TestLog::EndMessage
1294 						<< TestLog::Message << failNote << TestLog::EndMessage;
1295 					return false;
1296 				}
1297 			}
1298 
1299 			if (segmentsA.empty() || segmentsB.empty()) // All segments have same length. This is ok.
1300 			{
1301 				additionalSegmentLengthDst		= segments.size() == 1 ? -1.0f : segments[0].length;
1302 				additionalSegmentLocationDst	= -1;
1303 				return true;
1304 			}
1305 
1306 			if (segmentsA.size() != 2 && segmentsB.size() != 2)
1307 			{
1308 				log << TestLog::Message << "Failure: when dividing the segments to 2 groups by length, neither of the two groups has exactly 2 or 0 segments in it" << TestLog::EndMessage
1309 					<< TestLog::Message << failNote << TestLog::EndMessage;
1310 				return false;
1311 			}
1312 
1313 			// For convenience, arrange so that the 2-segment group is segmentsB.
1314 			if (segmentsB.size() != 2)
1315 				std::swap(segmentsA, segmentsB);
1316 
1317 			// \note For 4-segment lines both segmentsA and segmentsB have 2 segments each.
1318 			//		 Thus, we can't be sure which ones were meant as the additional segments.
1319 			//		 We give the benefit of the doubt by assuming that they're the shorter
1320 			//		 ones (as they should).
1321 
1322 			if (segmentsA.size() != 2)
1323 			{
1324 				if (segmentsB[0].length > segmentsA[0].length + 0.001f)
1325 				{
1326 					log << TestLog::Message << "Failure: the two additional segments are longer than the other segments" << TestLog::EndMessage
1327 						<< TestLog::Message << failNote << TestLog::EndMessage;
1328 					return false;
1329 				}
1330 			}
1331 			else
1332 			{
1333 				// We have 2 segmentsA and 2 segmentsB, ensure segmentsB has the shorter lengths
1334 				if (segmentsB[0].length > segmentsA[0].length)
1335 					std::swap(segmentsA, segmentsB);
1336 			}
1337 
1338 			// Check that the additional segments are placed symmetrically.
1339 			if (segmentsB[0].index + segmentsB[1].index + 1 != (int)segments.size())
1340 			{
1341 				log << TestLog::Message << "Failure: the two additional segments aren't placed symmetrically; "
1342 										<< "one is at index " << segmentsB[0].index << " and other is at index " << segmentsB[1].index
1343 										<< " (note: the two indexes should sum to " << (int)segments.size()-1 << ", i.e. numberOfSegments-1)" << TestLog::EndMessage
1344 					<< TestLog::Message << failNote << TestLog::EndMessage;
1345 				return false;
1346 			}
1347 
1348 			additionalSegmentLengthDst = segmentsB[0].length;
1349 			if (segmentsA.size() != 2)
1350 				additionalSegmentLocationDst = de::min(segmentsB[0].index, segmentsB[1].index);
1351 			else
1352 				additionalSegmentLocationDst = segmentsB[0].length < segmentsA[0].length - 0.001f ? de::min(segmentsB[0].index, segmentsB[1].index)
1353 											 : -1; // \note -1 when can't reliably decide which ones are the additional segments, a or b.
1354 
1355 			return true;
1356 		}
1357 	}
1358 }
1359 
1360 namespace VerifyFractionalSpacingMultipleInternal
1361 {
1362 
1363 struct LineData
1364 {
1365 	float	tessLevel;
1366 	float	additionalSegmentLength;
1367 	int		additionalSegmentLocation;
LineDatadeqp::gles31::Functional::__anon4a9088cf0211::VerifyFractionalSpacingMultipleInternal::LineData1368 	LineData (float lev, float len, int loc) : tessLevel(lev), additionalSegmentLength(len), additionalSegmentLocation(loc) {}
1369 };
1370 
1371 }
1372 
1373 /*--------------------------------------------------------------------*//*!
1374  * \brief Verify fractional spacing conditions between multiple lines
1375  *
1376  * Verify the fractional spacing conditions that are not checked in
1377  * verifyFractionalSpacingSingle(). Uses values given by said function
1378  * as parameters, in addition to the spacing mode and tessellation level.
1379  *//*--------------------------------------------------------------------*/
verifyFractionalSpacingMultiple(TestLog & log,SpacingMode spacingMode,const vector<float> & tessLevels,const vector<float> & additionalSegmentLengths,const vector<int> & additionalSegmentLocations)1380 static bool verifyFractionalSpacingMultiple (TestLog& log, SpacingMode spacingMode, const vector<float>& tessLevels, const vector<float>& additionalSegmentLengths, const vector<int>& additionalSegmentLocations)
1381 {
1382 	using namespace VerifyFractionalSpacingMultipleInternal;
1383 
1384 	DE_ASSERT(spacingMode == SPACINGMODE_FRACTIONAL_ODD || spacingMode == SPACINGMODE_FRACTIONAL_EVEN);
1385 	DE_ASSERT(tessLevels.size() == additionalSegmentLengths.size() &&
1386 			  tessLevels.size() == additionalSegmentLocations.size());
1387 
1388 	vector<LineData> lineDatas;
1389 
1390 	for (int i = 0; i < (int)tessLevels.size(); i++)
1391 		lineDatas.push_back(LineData(tessLevels[i], additionalSegmentLengths[i], additionalSegmentLocations[i]));
1392 
1393 	{
1394 		const vector<LineData> lineDatasSortedByLevel = sorted(lineDatas, memberPred<std::less>(&LineData::tessLevel));
1395 
1396 		// Check that lines with identical clamped tessellation levels have identical additionalSegmentLocation.
1397 
1398 		for (int lineNdx = 1; lineNdx < (int)lineDatasSortedByLevel.size(); lineNdx++)
1399 		{
1400 			const LineData& curData		= lineDatasSortedByLevel[lineNdx];
1401 			const LineData& prevData	= lineDatasSortedByLevel[lineNdx-1];
1402 
1403 			if (curData.additionalSegmentLocation < 0 || prevData.additionalSegmentLocation < 0)
1404 				continue; // Unknown locations, skip.
1405 
1406 			if (getClampedTessLevel(spacingMode, curData.tessLevel) == getClampedTessLevel(spacingMode, prevData.tessLevel) &&
1407 				curData.additionalSegmentLocation != prevData.additionalSegmentLocation)
1408 			{
1409 				log << TestLog::Message << "Failure: additional segments not located identically for two edges with identical clamped tessellation levels" << TestLog::EndMessage
1410 					<< TestLog::Message << "Note: tessellation levels are " << curData.tessLevel << " and " << prevData.tessLevel
1411 										<< " (clamped level " << getClampedTessLevel(spacingMode, curData.tessLevel) << ")"
1412 										<< "; but first additional segments located at indices "
1413 										<< curData.additionalSegmentLocation << " and " << prevData.additionalSegmentLocation << ", respectively" << TestLog::EndMessage;
1414 				return false;
1415 			}
1416 		}
1417 
1418 		// Check that, among lines with same clamped rounded tessellation level, additionalSegmentLength is monotonically decreasing with "clampedRoundedTessLevel - clampedTessLevel" (the "fraction").
1419 
1420 		for (int lineNdx = 1; lineNdx < (int)lineDatasSortedByLevel.size(); lineNdx++)
1421 		{
1422 			const LineData&		curData				= lineDatasSortedByLevel[lineNdx];
1423 			const LineData&		prevData			= lineDatasSortedByLevel[lineNdx-1];
1424 
1425 			if (curData.additionalSegmentLength < 0.0f || prevData.additionalSegmentLength < 0.0f)
1426 				continue; // Unknown segment lengths, skip.
1427 
1428 			const float			curClampedLevel		= getClampedTessLevel(spacingMode, curData.tessLevel);
1429 			const float			prevClampedLevel	= getClampedTessLevel(spacingMode, prevData.tessLevel);
1430 			const int			curFinalLevel		= getRoundedTessLevel(spacingMode, curClampedLevel);
1431 			const int			prevFinalLevel		= getRoundedTessLevel(spacingMode, prevClampedLevel);
1432 
1433 			if (curFinalLevel != prevFinalLevel)
1434 				continue;
1435 
1436 			const float			curFraction		= (float)curFinalLevel - curClampedLevel;
1437 			const float			prevFraction	= (float)prevFinalLevel - prevClampedLevel;
1438 
1439 			if (curData.additionalSegmentLength < prevData.additionalSegmentLength ||
1440 				(curClampedLevel == prevClampedLevel && curData.additionalSegmentLength != prevData.additionalSegmentLength))
1441 			{
1442 				log << TestLog::Message << "Failure: additional segment length isn't monotonically decreasing with the fraction <n> - <f>, among edges with same final tessellation level" << TestLog::EndMessage
1443 					<< TestLog::Message << "Note: <f> stands for the clamped tessellation level and <n> for the final (rounded and clamped) tessellation level" << TestLog::EndMessage
1444 					<< TestLog::Message << "Note: two edges have tessellation levels " << prevData.tessLevel << " and " << curData.tessLevel << " respectively"
1445 										<< ", clamped " << prevClampedLevel << " and " << curClampedLevel << ", final " << prevFinalLevel << " and " << curFinalLevel
1446 										<< "; fractions are " << prevFraction << " and " << curFraction
1447 										<< ", but resulted in segment lengths " << prevData.additionalSegmentLength << " and " << curData.additionalSegmentLength << TestLog::EndMessage;
1448 				return false;
1449 			}
1450 		}
1451 	}
1452 
1453 	return true;
1454 }
1455 
1456 //! Compare triangle sets, ignoring triangle order and vertex order within triangle, and possibly exclude some triangles too.
1457 template <typename IsTriangleRelevantT>
compareTriangleSets(const vector<Vec3> & coordsA,const vector<Vec3> & coordsB,TestLog & log,const IsTriangleRelevantT & isTriangleRelevant,const char * ignoredTriangleDescription=DE_NULL)1458 static bool compareTriangleSets (const vector<Vec3>&			coordsA,
1459 								 const vector<Vec3>&			coordsB,
1460 								 TestLog&						log,
1461 								 const IsTriangleRelevantT&		isTriangleRelevant,
1462 								 const char*					ignoredTriangleDescription = DE_NULL)
1463 {
1464 	typedef tcu::Vector<Vec3, 3>							Triangle;
1465 	typedef LexCompare<Triangle, 3, VecLexLessThan<3> >		TriangleLexLessThan;
1466 	typedef std::set<Triangle, TriangleLexLessThan>			TriangleSet;
1467 
1468 	DE_ASSERT(coordsA.size() % 3 == 0 && coordsB.size() % 3 == 0);
1469 
1470 	const int		numTrianglesA = (int)coordsA.size()/3;
1471 	const int		numTrianglesB = (int)coordsB.size()/3;
1472 	TriangleSet		trianglesA;
1473 	TriangleSet		trianglesB;
1474 
1475 	for (int aOrB = 0; aOrB < 2; aOrB++)
1476 	{
1477 		const vector<Vec3>&		coords			= aOrB == 0 ? coordsA			: coordsB;
1478 		const int				numTriangles	= aOrB == 0 ? numTrianglesA		: numTrianglesB;
1479 		TriangleSet&			triangles		= aOrB == 0 ? trianglesA		: trianglesB;
1480 
1481 		for (int triNdx = 0; triNdx < numTriangles; triNdx++)
1482 		{
1483 			Triangle triangle(coords[3*triNdx + 0],
1484 							  coords[3*triNdx + 1],
1485 							  coords[3*triNdx + 2]);
1486 
1487 			if (isTriangleRelevant(triangle.getPtr()))
1488 			{
1489 				std::sort(triangle.getPtr(), triangle.getPtr()+3, VecLexLessThan<3>());
1490 				triangles.insert(triangle);
1491 			}
1492 		}
1493 	}
1494 
1495 	{
1496 		TriangleSet::const_iterator aIt = trianglesA.begin();
1497 		TriangleSet::const_iterator bIt = trianglesB.begin();
1498 
1499 		while (aIt != trianglesA.end() || bIt != trianglesB.end())
1500 		{
1501 			const bool aEnd = aIt == trianglesA.end();
1502 			const bool bEnd = bIt == trianglesB.end();
1503 
1504 			if (aEnd || bEnd || *aIt != *bIt)
1505 			{
1506 				log << TestLog::Message << "Failure: triangle sets in two cases are not equal (when ignoring triangle and vertex order"
1507 					<< (ignoredTriangleDescription == DE_NULL ? "" : string() + ", and " + ignoredTriangleDescription) << ")" << TestLog::EndMessage;
1508 
1509 				if (!aEnd && (bEnd || TriangleLexLessThan()(*aIt, *bIt)))
1510 					log << TestLog::Message << "Note: e.g. triangle " << *aIt << " exists for first case but not for second" << TestLog::EndMessage;
1511 				else
1512 					log << TestLog::Message << "Note: e.g. triangle " << *bIt << " exists for second case but not for first" << TestLog::EndMessage;
1513 
1514 				return false;
1515 			}
1516 
1517 			++aIt;
1518 			++bIt;
1519 		}
1520 
1521 		return true;
1522 	}
1523 }
1524 
compareTriangleSets(const vector<Vec3> & coordsA,const vector<Vec3> & coordsB,TestLog & log)1525 static bool compareTriangleSets (const vector<Vec3>& coordsA, const vector<Vec3>& coordsB, TestLog& log)
1526 {
1527 	return compareTriangleSets(coordsA, coordsB, log, ConstantUnaryPredicate<const Vec3*, true>());
1528 }
1529 
checkGPUShader5Support(Context & context)1530 static void checkGPUShader5Support (Context& context)
1531 {
1532 	const bool supportsES32 = glu::contextSupports(context.getRenderContext().getType(), glu::ApiType::es(3, 2));
1533 	TCU_CHECK_AND_THROW(NotSupportedError, supportsES32 || context.getContextInfo().isExtensionSupported("GL_EXT_gpu_shader5"), "GL_EXT_gpu_shader5 is not supported");
1534 }
1535 
checkTessellationSupport(Context & context)1536 static void checkTessellationSupport (Context& context)
1537 {
1538 	const bool supportsES32 = glu::contextSupports(context.getRenderContext().getType(), glu::ApiType::es(3, 2));
1539 	TCU_CHECK_AND_THROW(NotSupportedError, supportsES32 || context.getContextInfo().isExtensionSupported("GL_EXT_tessellation_shader"), "GL_EXT_tessellation_shader is not supported");
1540 }
1541 
specializeShader(Context & context,const char * code)1542 static std::string specializeShader(Context& context, const char* code)
1543 {
1544 	const glu::ContextType				contextType		= context.getRenderContext().getType();
1545 	const glu::GLSLVersion				glslVersion		= glu::getContextTypeGLSLVersion(contextType);
1546 	bool								supportsES32	= glu::contextSupports(contextType, glu::ApiType::es(3, 2));
1547 
1548 	std::map<std::string, std::string>	specializationMap;
1549 
1550 	specializationMap["GLSL_VERSION_DECL"]				= glu::getGLSLVersionDeclaration(glslVersion);
1551 	specializationMap["GPU_SHADER5_REQUIRE"]			= supportsES32 ? "" : "#extension GL_EXT_gpu_shader5 : require";
1552 	specializationMap["TESSELLATION_SHADER_REQUIRE"]	= supportsES32 ? "" : "#extension GL_EXT_tessellation_shader : require";
1553 
1554 	return tcu::StringTemplate(code).specialize(specializationMap);
1555 }
1556 
1557 // Draw primitives with shared edges and check that no cracks are visible at the shared edges.
1558 class CommonEdgeCase : public TestCase
1559 {
1560 public:
1561 	enum CaseType
1562 	{
1563 		CASETYPE_BASIC = 0,		//!< Order patch vertices such that when two patches share a vertex, it's at the same index for both.
1564 		CASETYPE_PRECISE,		//!< Vertex indices don't match like for CASETYPE_BASIC, but other measures are taken, using the 'precise' qualifier.
1565 
1566 		CASETYPE_LAST
1567 	};
1568 
CommonEdgeCase(Context & context,const char * name,const char * description,TessPrimitiveType primitiveType,SpacingMode spacing,CaseType caseType)1569 	CommonEdgeCase (Context& context, const char* name, const char* description, TessPrimitiveType primitiveType, SpacingMode spacing, CaseType caseType)
1570 		: TestCase			(context, name, description)
1571 		, m_primitiveType	(primitiveType)
1572 		, m_spacing			(spacing)
1573 		, m_caseType		(caseType)
1574 	{
1575 		DE_ASSERT(m_primitiveType == TESSPRIMITIVETYPE_TRIANGLES || m_primitiveType == TESSPRIMITIVETYPE_QUADS);
1576 	}
1577 
1578 	void							init		(void);
1579 	void							deinit		(void);
1580 	IterateResult					iterate		(void);
1581 
1582 private:
1583 	static const int				RENDER_SIZE = 256;
1584 
1585 	const TessPrimitiveType			m_primitiveType;
1586 	const SpacingMode				m_spacing;
1587 	const CaseType					m_caseType;
1588 
1589 	SharedPtr<const ShaderProgram>	m_program;
1590 };
1591 
init(void)1592 void CommonEdgeCase::init (void)
1593 {
1594 	checkTessellationSupport(m_context);
1595 
1596 	if (m_caseType == CASETYPE_PRECISE)
1597 		checkGPUShader5Support(m_context);
1598 
1599 	checkRenderTargetSize(m_context.getRenderTarget(), RENDER_SIZE);
1600 
1601 	std::string vertexShaderTemplate			("${GLSL_VERSION_DECL}\n"
1602 													 "\n"
1603 													 "in highp vec2 in_v_position;\n"
1604 													 "in highp float in_v_tessParam;\n"
1605 													 "\n"
1606 													 "out highp vec2 in_tc_position;\n"
1607 													 "out highp float in_tc_tessParam;\n"
1608 													 "\n"
1609 													 "void main (void)\n"
1610 													 "{\n"
1611 													 "	in_tc_position = in_v_position;\n"
1612 													 "	in_tc_tessParam = in_v_tessParam;\n"
1613 												 "}\n");
1614 
1615 	std::string tessellationControlTemplate		("${GLSL_VERSION_DECL}\n"
1616 												 "${TESSELLATION_SHADER_REQUIRE}\n"
1617 												 + string(m_caseType == CASETYPE_PRECISE ? "${GPU_SHADER5_REQUIRE}\n" : "") +
1618 													 "\n"
1619 													 "layout (vertices = " + string(m_primitiveType == TESSPRIMITIVETYPE_TRIANGLES ? "3" : m_primitiveType == TESSPRIMITIVETYPE_QUADS ? "4" : DE_NULL) + ") out;\n"
1620 													 "\n"
1621 													 "in highp vec2 in_tc_position[];\n"
1622 													 "in highp float in_tc_tessParam[];\n"
1623 													 "\n"
1624 													 "out highp vec2 in_te_position[];\n"
1625 													 "\n"
1626 													 + (m_caseType == CASETYPE_PRECISE ? "precise gl_TessLevelOuter;\n\n" : "") +
1627 													 "void main (void)\n"
1628 													 "{\n"
1629 													 "	in_te_position[gl_InvocationID] = in_tc_position[gl_InvocationID];\n"
1630 													 "\n"
1631 													 "	gl_TessLevelInner[0] = 5.0;\n"
1632 													 "	gl_TessLevelInner[1] = 5.0;\n"
1633 													 "\n"
1634 													 + (m_primitiveType == TESSPRIMITIVETYPE_TRIANGLES ?
1635 														"	gl_TessLevelOuter[0] = 1.0 + 59.0 * 0.5 * (in_tc_tessParam[1] + in_tc_tessParam[2]);\n"
1636 														"	gl_TessLevelOuter[1] = 1.0 + 59.0 * 0.5 * (in_tc_tessParam[2] + in_tc_tessParam[0]);\n"
1637 														"	gl_TessLevelOuter[2] = 1.0 + 59.0 * 0.5 * (in_tc_tessParam[0] + in_tc_tessParam[1]);\n"
1638 													  : m_primitiveType == TESSPRIMITIVETYPE_QUADS ?
1639 														"	gl_TessLevelOuter[0] = 1.0 + 59.0 * 0.5 * (in_tc_tessParam[0] + in_tc_tessParam[2]);\n"
1640 														"	gl_TessLevelOuter[1] = 1.0 + 59.0 * 0.5 * (in_tc_tessParam[1] + in_tc_tessParam[0]);\n"
1641 														"	gl_TessLevelOuter[2] = 1.0 + 59.0 * 0.5 * (in_tc_tessParam[3] + in_tc_tessParam[1]);\n"
1642 														"	gl_TessLevelOuter[3] = 1.0 + 59.0 * 0.5 * (in_tc_tessParam[2] + in_tc_tessParam[3]);\n"
1643 													  : DE_NULL) +
1644 												 "}\n");
1645 
1646 	std::string tessellationEvaluationTemplate	("${GLSL_VERSION_DECL}\n"
1647 												 "${TESSELLATION_SHADER_REQUIRE}\n"
1648 												 + string(m_caseType == CASETYPE_PRECISE ? "${GPU_SHADER5_REQUIRE}\n" : "") +
1649 													 "\n"
1650 													 + getTessellationEvaluationInLayoutString(m_primitiveType, m_spacing) +
1651 													 "\n"
1652 													 "in highp vec2 in_te_position[];\n"
1653 													 "\n"
1654 													 "out mediump vec4 in_f_color;\n"
1655 													 "\n"
1656 													 + (m_caseType == CASETYPE_PRECISE ? "precise gl_Position;\n\n" : "") +
1657 													 "void main (void)\n"
1658 													 "{\n"
1659 													 + (m_primitiveType == TESSPRIMITIVETYPE_TRIANGLES ?
1660 														"	highp vec2 pos = gl_TessCoord.x*in_te_position[0] + gl_TessCoord.y*in_te_position[1] + gl_TessCoord.z*in_te_position[2];\n"
1661 														"\n"
1662 														"	highp float f = sqrt(3.0 * min(gl_TessCoord.x, min(gl_TessCoord.y, gl_TessCoord.z))) * 0.5 + 0.5;\n"
1663 														"	in_f_color = vec4(gl_TessCoord*f, 1.0);\n"
1664 													  : m_primitiveType == TESSPRIMITIVETYPE_QUADS ?
1665 													    string()
1666 														+ (m_caseType == CASETYPE_BASIC ?
1667 															"	highp vec2 pos = (1.0-gl_TessCoord.x)*(1.0-gl_TessCoord.y)*in_te_position[0]\n"
1668 															"	               + (    gl_TessCoord.x)*(1.0-gl_TessCoord.y)*in_te_position[1]\n"
1669 															"	               + (1.0-gl_TessCoord.x)*(    gl_TessCoord.y)*in_te_position[2]\n"
1670 															"	               + (    gl_TessCoord.x)*(    gl_TessCoord.y)*in_te_position[3];\n"
1671 														 : m_caseType == CASETYPE_PRECISE ?
1672 															"	highp vec2 a = (1.0-gl_TessCoord.x)*(1.0-gl_TessCoord.y)*in_te_position[0];\n"
1673 															"	highp vec2 b = (    gl_TessCoord.x)*(1.0-gl_TessCoord.y)*in_te_position[1];\n"
1674 															"	highp vec2 c = (1.0-gl_TessCoord.x)*(    gl_TessCoord.y)*in_te_position[2];\n"
1675 															"	highp vec2 d = (    gl_TessCoord.x)*(    gl_TessCoord.y)*in_te_position[3];\n"
1676 															"	highp vec2 pos = a+b+c+d;\n"
1677 														 : DE_NULL) +
1678 														"\n"
1679 														"	highp float f = sqrt(1.0 - 2.0 * max(abs(gl_TessCoord.x - 0.5), abs(gl_TessCoord.y - 0.5)))*0.5 + 0.5;\n"
1680 														"	in_f_color = vec4(0.1, gl_TessCoord.xy*f, 1.0);\n"
1681 													  : DE_NULL) +
1682 													 "\n"
1683 													 "	// Offset the position slightly, based on the parity of the bits in the float representation.\n"
1684 													 "	// This is done to detect possible small differences in edge vertex positions between patches.\n"
1685 													 "	uvec2 bits = floatBitsToUint(pos);\n"
1686 													 "	uint numBits = 0u;\n"
1687 													 "	for (uint i = 0u; i < 32u; i++)\n"
1688 													 "		numBits += ((bits[0] >> i) & 1u) + ((bits[1] >> i) & 1u);\n"
1689 													 "	pos += float(numBits&1u)*0.04;\n"
1690 													 "\n"
1691 													 "	gl_Position = vec4(pos, 0.0, 1.0);\n"
1692 												 "}\n");
1693 
1694 	std::string fragmentShaderTemplate			("${GLSL_VERSION_DECL}\n"
1695 													 "\n"
1696 													 "layout (location = 0) out mediump vec4 o_color;\n"
1697 													 "\n"
1698 													 "in mediump vec4 in_f_color;\n"
1699 													 "\n"
1700 													 "void main (void)\n"
1701 													 "{\n"
1702 													 "	o_color = in_f_color;\n"
1703 												 "}\n");
1704 
1705 	m_program = SharedPtr<const ShaderProgram>(new ShaderProgram(m_context.getRenderContext(), glu::ProgramSources()
1706 			<< glu::VertexSource					(specializeShader(m_context, vertexShaderTemplate.c_str()))
1707 			<< glu::TessellationControlSource		(specializeShader(m_context, tessellationControlTemplate.c_str()))
1708 			<< glu::TessellationEvaluationSource	(specializeShader(m_context, tessellationEvaluationTemplate.c_str()))
1709 			<< glu::FragmentSource					(specializeShader(m_context, fragmentShaderTemplate.c_str()))));
1710 
1711 	m_testCtx.getLog() << *m_program;
1712 	if (!m_program->isOk())
1713 		TCU_FAIL("Program compilation failed");
1714 }
1715 
deinit(void)1716 void CommonEdgeCase::deinit (void)
1717 {
1718 	m_program.clear();
1719 }
1720 
iterate(void)1721 CommonEdgeCase::IterateResult CommonEdgeCase::iterate (void)
1722 {
1723 	TestLog&					log						= m_testCtx.getLog();
1724 	const RenderContext&		renderCtx				= m_context.getRenderContext();
1725 	const RandomViewport		viewport				(renderCtx.getRenderTarget(), RENDER_SIZE, RENDER_SIZE, deStringHash(getName()));
1726 	const deUint32				programGL				= m_program->getProgram();
1727 	const glw::Functions&		gl						= renderCtx.getFunctions();
1728 
1729 	const int					gridWidth				= 4;
1730 	const int					gridHeight				= 4;
1731 	const int					numVertices				= (gridWidth+1)*(gridHeight+1);
1732 	const int					numIndices				= gridWidth*gridHeight * (m_primitiveType == TESSPRIMITIVETYPE_TRIANGLES ? 3*2 : m_primitiveType == TESSPRIMITIVETYPE_QUADS ? 4 : -1);
1733 	const int					numPosCompsPerVertex	= 2;
1734 	const int					totalNumPosComps		= numPosCompsPerVertex*numVertices;
1735 	vector<float>				gridPosComps;
1736 	vector<float>				gridTessParams;
1737 	vector<deUint16>			gridIndices;
1738 
1739 	gridPosComps.reserve(totalNumPosComps);
1740 	gridTessParams.reserve(numVertices);
1741 	gridIndices.reserve(numIndices);
1742 
1743 	{
1744 		for (int i = 0; i < gridHeight+1; i++)
1745 		for (int j = 0; j < gridWidth+1; j++)
1746 		{
1747 			gridPosComps.push_back(-1.0f + 2.0f * ((float)j + 0.5f) / (float)(gridWidth+1));
1748 			gridPosComps.push_back(-1.0f + 2.0f * ((float)i + 0.5f) / (float)(gridHeight+1));
1749 			gridTessParams.push_back((float)(i*(gridWidth+1) + j) / (float)(numVertices-1));
1750 		}
1751 	}
1752 
1753 	// Generate patch vertex indices.
1754 	// \note If CASETYPE_BASIC, the vertices are ordered such that when multiple
1755 	//		 triangles/quads share a vertex, it's at the same index for everyone.
1756 
1757 	if (m_primitiveType == TESSPRIMITIVETYPE_TRIANGLES)
1758 	{
1759 		for (int i = 0; i < gridHeight; i++)
1760 		for (int j = 0; j < gridWidth; j++)
1761 		{
1762 			const deUint16 corners[4] =
1763 			{
1764 				(deUint16)((i+0)*(gridWidth+1) + j+0),
1765 				(deUint16)((i+0)*(gridWidth+1) + j+1),
1766 				(deUint16)((i+1)*(gridWidth+1) + j+0),
1767 				(deUint16)((i+1)*(gridWidth+1) + j+1)
1768 			};
1769 
1770 			const int secondTriangleVertexIndexOffset = m_caseType == CASETYPE_BASIC	? 0
1771 													  : m_caseType == CASETYPE_PRECISE	? 1
1772 													  : -1;
1773 			DE_ASSERT(secondTriangleVertexIndexOffset != -1);
1774 
1775 			for (int k = 0; k < 3; k++)
1776 				gridIndices.push_back(corners[(k+0 + i + (2-j%3)) % 3]);
1777 			for (int k = 0; k < 3; k++)
1778 				gridIndices.push_back(corners[(k+2 + i + (2-j%3) + secondTriangleVertexIndexOffset) % 3 + 1]);
1779 		}
1780 	}
1781 	else if (m_primitiveType == TESSPRIMITIVETYPE_QUADS)
1782 	{
1783 		for (int i = 0; i < gridHeight; i++)
1784 		for (int j = 0; j < gridWidth; j++)
1785 		{
1786 			// \note The vertices are ordered such that when multiple quads
1787 			//		 share a vertices, it's at the same index for everyone.
1788 			for (int m = 0; m < 2; m++)
1789 			for (int n = 0; n < 2; n++)
1790 				gridIndices.push_back((deUint16)((i+(i+m)%2)*(gridWidth+1) + j+(j+n)%2));
1791 
1792 			if(m_caseType == CASETYPE_PRECISE && (i+j) % 2 == 0)
1793 				std::reverse(gridIndices.begin() + (gridIndices.size() - 4),
1794 							 gridIndices.begin() + gridIndices.size());
1795 		}
1796 	}
1797 	else
1798 		DE_ASSERT(false);
1799 
1800 	DE_ASSERT((int)gridPosComps.size() == totalNumPosComps);
1801 	DE_ASSERT((int)gridTessParams.size() == numVertices);
1802 	DE_ASSERT((int)gridIndices.size() == numIndices);
1803 
1804 	setViewport(gl, viewport);
1805 	gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
1806 	gl.useProgram(programGL);
1807 
1808 	{
1809 		gl.patchParameteri(GL_PATCH_VERTICES, m_primitiveType == TESSPRIMITIVETYPE_TRIANGLES ? 3 : m_primitiveType == TESSPRIMITIVETYPE_QUADS ? 4 : -1);
1810 		gl.clear(GL_COLOR_BUFFER_BIT);
1811 
1812 		const glu::VertexArrayBinding attrBindings[] =
1813 		{
1814 			glu::va::Float("in_v_position", numPosCompsPerVertex, numVertices, 0, &gridPosComps[0]),
1815 			glu::va::Float("in_v_tessParam", 1, numVertices, 0, &gridTessParams[0])
1816 		};
1817 
1818 		glu::draw(renderCtx, programGL, DE_LENGTH_OF_ARRAY(attrBindings), &attrBindings[0],
1819 			glu::pr::Patches((int)gridIndices.size(), &gridIndices[0]));
1820 		GLU_EXPECT_NO_ERROR(gl.getError(), "Draw failed");
1821 	}
1822 
1823 	{
1824 		const tcu::Surface rendered = getPixels(renderCtx, viewport);
1825 
1826 		log << TestLog::Image("RenderedImage", "Rendered Image", rendered)
1827 			<< TestLog::Message << "Note: coloring is done to clarify the positioning and orientation of the "
1828 								<< (m_primitiveType == TESSPRIMITIVETYPE_TRIANGLES ? "triangles" : m_primitiveType == TESSPRIMITIVETYPE_QUADS ? "quads" : DE_NULL)
1829 								<< "; the color of a vertex corresponds to the index of that vertex in the patch"
1830 								<< TestLog::EndMessage;
1831 
1832 		if (m_caseType == CASETYPE_BASIC)
1833 			log << TestLog::Message << "Note: each shared vertex has the same index among the primitives it belongs to" << TestLog::EndMessage;
1834 		else if (m_caseType == CASETYPE_PRECISE)
1835 			log << TestLog::Message << "Note: the 'precise' qualifier is used to avoid cracks between primitives" << TestLog::EndMessage;
1836 		else
1837 			DE_ASSERT(false);
1838 
1839 		// Ad-hoc result verification - check that a certain rectangle in the image contains no black pixels.
1840 
1841 		const int startX	= (int)(0.15f * (float)rendered.getWidth());
1842 		const int endX		= (int)(0.85f * (float)rendered.getWidth());
1843 		const int startY	= (int)(0.15f * (float)rendered.getHeight());
1844 		const int endY		= (int)(0.85f * (float)rendered.getHeight());
1845 
1846 		for (int y = startY; y < endY; y++)
1847 		for (int x = startX; x < endX; x++)
1848 		{
1849 			const tcu::RGBA pixel = rendered.getPixel(x, y);
1850 
1851 			if (pixel.getRed() == 0 && pixel.getGreen() == 0 && pixel.getBlue() == 0)
1852 			{
1853 				log << TestLog::Message << "Failure: there seem to be cracks in the rendered result" << TestLog::EndMessage
1854 					<< TestLog::Message << "Note: pixel with zero r, g and b channels found at " << tcu::IVec2(x, y) << TestLog::EndMessage;
1855 
1856 				m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image verification failed");
1857 				return STOP;
1858 			}
1859 		}
1860 
1861 		log << TestLog::Message << "Success: there seem to be no cracks in the rendered result" << TestLog::EndMessage;
1862 	}
1863 
1864 	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1865 	return STOP;
1866 }
1867 
1868 // Check tessellation coordinates (read with transform feedback).
1869 class TessCoordCase : public TestCase
1870 {
1871 public:
TessCoordCase(Context & context,const char * name,const char * description,TessPrimitiveType primitiveType,SpacingMode spacing)1872 					TessCoordCase (Context& context, const char* name, const char* description, TessPrimitiveType primitiveType, SpacingMode spacing)
1873 						: TestCase			(context, name, description)
1874 						, m_primitiveType	(primitiveType)
1875 						, m_spacing			(spacing)
1876 					{
1877 					}
1878 
1879 	void			init		(void);
1880 	void			deinit		(void);
1881 	IterateResult	iterate		(void);
1882 
1883 private:
1884 	struct TessLevels
1885 	{
1886 		float inner[2];
1887 		float outer[4];
1888 	};
1889 
1890 	static const int				RENDER_SIZE = 16;
1891 
1892 	vector<TessLevels>				genTessLevelCases (void) const;
1893 
1894 	const TessPrimitiveType			m_primitiveType;
1895 	const SpacingMode				m_spacing;
1896 
1897 	SharedPtr<const ShaderProgram>	m_program;
1898 };
1899 
init(void)1900 void TessCoordCase::init (void)
1901 {
1902 	checkTessellationSupport(m_context);
1903 	checkRenderTargetSize(m_context.getRenderTarget(), RENDER_SIZE);
1904 
1905 	std::string vertexShaderTemplate			("${GLSL_VERSION_DECL}\n"
1906 													 "\n"
1907 													 "void main (void)\n"
1908 													 "{\n"
1909 												 "}\n");
1910 
1911 	std::string tessellationControlTemplate		("${GLSL_VERSION_DECL}\n"
1912 												 "${TESSELLATION_SHADER_REQUIRE}\n"
1913 													 "\n"
1914 													 "layout (vertices = 1) out;\n"
1915 													 "\n"
1916 													 "uniform mediump float u_tessLevelInner0;\n"
1917 													 "uniform mediump float u_tessLevelInner1;\n"
1918 													 "\n"
1919 													 "uniform mediump float u_tessLevelOuter0;\n"
1920 													 "uniform mediump float u_tessLevelOuter1;\n"
1921 													 "uniform mediump float u_tessLevelOuter2;\n"
1922 													 "uniform mediump float u_tessLevelOuter3;\n"
1923 													 "\n"
1924 													 "void main (void)\n"
1925 													 "{\n"
1926 													 "	gl_TessLevelInner[0] = u_tessLevelInner0;\n"
1927 													 "	gl_TessLevelInner[1] = u_tessLevelInner1;\n"
1928 													 "\n"
1929 													 "	gl_TessLevelOuter[0] = u_tessLevelOuter0;\n"
1930 													 "	gl_TessLevelOuter[1] = u_tessLevelOuter1;\n"
1931 													 "	gl_TessLevelOuter[2] = u_tessLevelOuter2;\n"
1932 													 "	gl_TessLevelOuter[3] = u_tessLevelOuter3;\n"
1933 												 "}\n");
1934 
1935 	std::string tessellationEvaluationTemplate	("${GLSL_VERSION_DECL}\n"
1936 												 "${TESSELLATION_SHADER_REQUIRE}\n"
1937 													 "\n"
1938 													 + getTessellationEvaluationInLayoutString(m_primitiveType, m_spacing, true) +
1939 													 "\n"
1940 													 "out highp vec3 out_te_tessCoord;\n"
1941 													 "\n"
1942 													 "void main (void)\n"
1943 													 "{\n"
1944 													 "	out_te_tessCoord = gl_TessCoord;\n"
1945 													 "	gl_Position = vec4(gl_TessCoord.xy*1.6 - 0.8, 0.0, 1.0);\n"
1946 												 "}\n");
1947 
1948 	std::string fragmentShaderTemplate			("${GLSL_VERSION_DECL}\n"
1949 													 "\n"
1950 													 "layout (location = 0) out mediump vec4 o_color;\n"
1951 													 "\n"
1952 													 "void main (void)\n"
1953 													 "{\n"
1954 													 "	o_color = vec4(1.0);\n"
1955 												 "}\n");
1956 
1957        m_program = SharedPtr<const ShaderProgram>(new ShaderProgram(m_context.getRenderContext(), glu::ProgramSources()
1958 			<< glu::VertexSource					(specializeShader(m_context, vertexShaderTemplate.c_str()))
1959 			<< glu::TessellationControlSource		(specializeShader(m_context, tessellationControlTemplate.c_str()))
1960 			<< glu::TessellationEvaluationSource	(specializeShader(m_context, tessellationEvaluationTemplate.c_str()))
1961 			<< glu::FragmentSource					(specializeShader(m_context, fragmentShaderTemplate.c_str()))
1962 			<< glu::TransformFeedbackVarying		("out_te_tessCoord")
1963 			<< glu::TransformFeedbackMode			(GL_INTERLEAVED_ATTRIBS)));
1964 
1965 	m_testCtx.getLog() << *m_program;
1966 	if (!m_program->isOk())
1967 		TCU_FAIL("Program compilation failed");
1968 }
1969 
deinit(void)1970 void TessCoordCase::deinit (void)
1971 {
1972 	m_program.clear();
1973 }
1974 
genTessLevelCases(void) const1975 vector<TessCoordCase::TessLevels> TessCoordCase::genTessLevelCases (void) const
1976 {
1977 	static const TessLevels rawTessLevelCases[] =
1978 	{
1979 		{ { 1.0f,	1.0f	},	{ 1.0f,		1.0f,	1.0f,	1.0f	} },
1980 		{ { 63.0f,	24.0f	},	{ 15.0f,	42.0f,	10.0f,	12.0f	} },
1981 		{ { 3.0f,	2.0f	},	{ 6.0f,		8.0f,	7.0f,	9.0f	} },
1982 		{ { 4.0f,	6.0f	},	{ 2.0f,		3.0f,	1.0f,	4.0f	} },
1983 		{ { 2.0f,	2.0f	},	{ 6.0f,		8.0f,	7.0f,	9.0f	} },
1984 		{ { 5.0f,	6.0f	},	{ 1.0f,		1.0f,	1.0f,	1.0f	} },
1985 		{ { 1.0f,	6.0f	},	{ 2.0f,		3.0f,	1.0f,	4.0f	} },
1986 		{ { 5.0f,	1.0f	},	{ 2.0f,		3.0f,	1.0f,	4.0f	} },
1987 		{ { 5.2f,	1.6f	},	{ 2.9f,		3.4f,	1.5f,	4.1f	} }
1988 	};
1989 
1990 	if (m_spacing == SPACINGMODE_EQUAL)
1991 		return vector<TessLevels>(DE_ARRAY_BEGIN(rawTessLevelCases), DE_ARRAY_END(rawTessLevelCases));
1992 	else
1993 	{
1994 		vector<TessLevels> result;
1995 		result.reserve(DE_LENGTH_OF_ARRAY(rawTessLevelCases));
1996 
1997 		for (int tessLevelCaseNdx = 0; tessLevelCaseNdx < DE_LENGTH_OF_ARRAY(rawTessLevelCases); tessLevelCaseNdx++)
1998 		{
1999 			TessLevels curTessLevelCase = rawTessLevelCases[tessLevelCaseNdx];
2000 
2001 			float* const inner = &curTessLevelCase.inner[0];
2002 			float* const outer = &curTessLevelCase.outer[0];
2003 
2004 			for (int j = 0; j < 2; j++) inner[j] = (float)getClampedRoundedTessLevel(m_spacing, inner[j]);
2005 			for (int j = 0; j < 4; j++) outer[j] = (float)getClampedRoundedTessLevel(m_spacing, outer[j]);
2006 
2007 			if (m_primitiveType == TESSPRIMITIVETYPE_TRIANGLES)
2008 			{
2009 				if (outer[0] > 1.0f || outer[1] > 1.0f || outer[2] > 1.0f)
2010 				{
2011 					if (inner[0] == 1.0f)
2012 						inner[0] = (float)getClampedRoundedTessLevel(m_spacing, inner[0] + 0.1f);
2013 				}
2014 			}
2015 			else if (m_primitiveType == TESSPRIMITIVETYPE_QUADS)
2016 			{
2017 				if (outer[0] > 1.0f || outer[1] > 1.0f || outer[2] > 1.0f || outer[3] > 1.0f)
2018 				{
2019 					if (inner[0] == 1.0f) inner[0] = (float)getClampedRoundedTessLevel(m_spacing, inner[0] + 0.1f);
2020 					if (inner[1] == 1.0f) inner[1] = (float)getClampedRoundedTessLevel(m_spacing, inner[1] + 0.1f);
2021 				}
2022 			}
2023 
2024 			result.push_back(curTessLevelCase);
2025 		}
2026 
2027 		DE_ASSERT((int)result.size() == DE_LENGTH_OF_ARRAY(rawTessLevelCases));
2028 		return result;
2029 	}
2030 }
2031 
iterate(void)2032 TessCoordCase::IterateResult TessCoordCase::iterate (void)
2033 {
2034 	typedef TransformFeedbackHandler<Vec3> TFHandler;
2035 
2036 	TestLog&						log							= m_testCtx.getLog();
2037 	const RenderContext&			renderCtx					= m_context.getRenderContext();
2038 	const RandomViewport			viewport					(renderCtx.getRenderTarget(), RENDER_SIZE, RENDER_SIZE, deStringHash(getName()));
2039 	const deUint32					programGL					= m_program->getProgram();
2040 	const glw::Functions&			gl							= renderCtx.getFunctions();
2041 
2042 	const int						tessLevelInner0Loc			= gl.getUniformLocation(programGL, "u_tessLevelInner0");
2043 	const int						tessLevelInner1Loc			= gl.getUniformLocation(programGL, "u_tessLevelInner1");
2044 	const int						tessLevelOuter0Loc			= gl.getUniformLocation(programGL, "u_tessLevelOuter0");
2045 	const int						tessLevelOuter1Loc			= gl.getUniformLocation(programGL, "u_tessLevelOuter1");
2046 	const int						tessLevelOuter2Loc			= gl.getUniformLocation(programGL, "u_tessLevelOuter2");
2047 	const int						tessLevelOuter3Loc			= gl.getUniformLocation(programGL, "u_tessLevelOuter3");
2048 
2049 	const vector<TessLevels>		tessLevelCases				= genTessLevelCases();
2050 	vector<vector<Vec3> >			caseReferences				(tessLevelCases.size());
2051 
2052 	for (int i = 0; i < (int)tessLevelCases.size(); i++)
2053 		caseReferences[i] = generateReferenceTessCoords(m_primitiveType, m_spacing, &tessLevelCases[i].inner[0], &tessLevelCases[i].outer[0]);
2054 
2055 	const int						maxNumVertices				= (int)std::max_element(caseReferences.begin(), caseReferences.end(), SizeLessThan<vector<Vec3> >())->size();
2056 	const TFHandler					tfHandler					(m_context.getRenderContext(), maxNumVertices);
2057 
2058 	bool							success						= true;
2059 
2060 	setViewport(gl, viewport);
2061 	gl.useProgram(programGL);
2062 
2063 	gl.patchParameteri(GL_PATCH_VERTICES, 1);
2064 
2065 	for (int tessLevelCaseNdx = 0; tessLevelCaseNdx < (int)tessLevelCases.size(); tessLevelCaseNdx++)
2066 	{
2067 		const float* const innerLevels = &tessLevelCases[tessLevelCaseNdx].inner[0];
2068 		const float* const outerLevels = &tessLevelCases[tessLevelCaseNdx].outer[0];
2069 
2070 		log << TestLog::Message << "Tessellation levels: " << tessellationLevelsString(innerLevels, outerLevels, m_primitiveType) << TestLog::EndMessage;
2071 
2072 		gl.uniform1f(tessLevelInner0Loc, innerLevels[0]);
2073 		gl.uniform1f(tessLevelInner1Loc, innerLevels[1]);
2074 		gl.uniform1f(tessLevelOuter0Loc, outerLevels[0]);
2075 		gl.uniform1f(tessLevelOuter1Loc, outerLevels[1]);
2076 		gl.uniform1f(tessLevelOuter2Loc, outerLevels[2]);
2077 		gl.uniform1f(tessLevelOuter3Loc, outerLevels[3]);
2078 		GLU_EXPECT_NO_ERROR(gl.getError(), "Setup failed");
2079 
2080 		{
2081 			const vector<Vec3>&			tessCoordsRef	= caseReferences[tessLevelCaseNdx];
2082 			const TFHandler::Result		tfResult		= tfHandler.renderAndGetPrimitives(programGL, GL_POINTS, 0, DE_NULL, 1);
2083 
2084 			if (tfResult.numPrimitives != (int)tessCoordsRef.size())
2085 			{
2086 				log << TestLog::Message << "Failure: GL reported GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN to be "
2087 										<< tfResult.numPrimitives << ", reference value is " << tessCoordsRef.size()
2088 										<< " (logging further info anyway)" << TestLog::EndMessage;
2089 				success = false;
2090 			}
2091 			else
2092 				log << TestLog::Message << "Note: GL reported GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN to be " << tfResult.numPrimitives << TestLog::EndMessage;
2093 
2094 			if (m_primitiveType == TESSPRIMITIVETYPE_TRIANGLES)
2095 				log << 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" << TestLog::EndMessage;
2096 			else if (m_primitiveType == TESSPRIMITIVETYPE_QUADS || m_primitiveType == TESSPRIMITIVETYPE_ISOLINES)
2097 				log << TestLog::Message << "Note: in the following visualization(s), u and v coordinate go left-to-right and bottom-to-top, respectively" << TestLog::EndMessage;
2098 			else
2099 				DE_ASSERT(false);
2100 
2101 			success = compareTessCoords(log, m_primitiveType, tessCoordsRef, tfResult.varying) && success;
2102 		}
2103 
2104 		if (!success)
2105 			break;
2106 		else
2107 			log << TestLog::Message << "All OK" << TestLog::EndMessage;
2108 	}
2109 
2110 	m_testCtx.setTestResult(success ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, success ? "Pass" : "Invalid tessellation coordinates");
2111 	return STOP;
2112 }
2113 
2114 // Check validity of fractional spacing modes. Draws a single isoline, reads tesscoords with transform feedback.
2115 class FractionalSpacingModeCase : public TestCase
2116 {
2117 public:
FractionalSpacingModeCase(Context & context,const char * name,const char * description,SpacingMode spacing)2118 					FractionalSpacingModeCase (Context& context, const char* name, const char* description, SpacingMode spacing)
2119 						: TestCase	(context, name, description)
2120 						, m_spacing	(spacing)
2121 					{
2122 						DE_ASSERT(m_spacing == SPACINGMODE_FRACTIONAL_EVEN || m_spacing == SPACINGMODE_FRACTIONAL_ODD);
2123 					}
2124 
2125 	void			init		(void);
2126 	void			deinit		(void);
2127 	IterateResult	iterate		(void);
2128 
2129 private:
2130 	static const int				RENDER_SIZE = 16;
2131 
2132 	static vector<float>			genTessLevelCases (void);
2133 
2134 	const SpacingMode				m_spacing;
2135 
2136 	SharedPtr<const ShaderProgram>	m_program;
2137 };
2138 
init(void)2139 void FractionalSpacingModeCase::init (void)
2140 {
2141 	checkTessellationSupport(m_context);
2142 	checkRenderTargetSize(m_context.getRenderTarget(), RENDER_SIZE);
2143 
2144 	std::string vertexShaderTemplate			("${GLSL_VERSION_DECL}\n"
2145 													 "\n"
2146 													 "void main (void)\n"
2147 													 "{\n"
2148 												 "}\n");
2149 	std::string tessellationControlTemplate		("${GLSL_VERSION_DECL}\n"
2150 												 "${TESSELLATION_SHADER_REQUIRE}\n"
2151 													 "\n"
2152 													 "layout (vertices = 1) out;\n"
2153 													 "\n"
2154 													 "uniform mediump float u_tessLevelOuter1;\n"
2155 													 "\n"
2156 													 "void main (void)\n"
2157 													 "{\n"
2158 													 "	gl_TessLevelOuter[0] = 1.0;\n"
2159 													 "	gl_TessLevelOuter[1] = u_tessLevelOuter1;\n"
2160 												 "}\n");
2161 	std::string tessellationEvaluationTemplate	("${GLSL_VERSION_DECL}\n"
2162 												 "${TESSELLATION_SHADER_REQUIRE}\n"
2163 													 "\n"
2164 													 + getTessellationEvaluationInLayoutString(TESSPRIMITIVETYPE_ISOLINES, m_spacing, true) +
2165 													 "\n"
2166 													 "out highp float out_te_tessCoord;\n"
2167 													 "\n"
2168 													 "void main (void)\n"
2169 													 "{\n"
2170 													 "	out_te_tessCoord = gl_TessCoord.x;\n"
2171 													 "	gl_Position = vec4(gl_TessCoord.xy*1.6 - 0.8, 0.0, 1.0);\n"
2172 												 "}\n");
2173 	std::string fragmentShaderTemplate			("${GLSL_VERSION_DECL}\n"
2174 													 "\n"
2175 													 "layout (location = 0) out mediump vec4 o_color;\n"
2176 													 "\n"
2177 													 "void main (void)\n"
2178 													 "{\n"
2179 													 "	o_color = vec4(1.0);\n"
2180 												 "}\n");
2181 
2182 	m_program = SharedPtr<const ShaderProgram>(new ShaderProgram(m_context.getRenderContext(), glu::ProgramSources()
2183 			<< glu::VertexSource					(specializeShader(m_context, vertexShaderTemplate.c_str()))
2184 			<< glu::TessellationControlSource		(specializeShader(m_context, tessellationControlTemplate.c_str()))
2185 			<< glu::TessellationEvaluationSource	(specializeShader(m_context, tessellationEvaluationTemplate.c_str()))
2186 			<< glu::FragmentSource					(specializeShader(m_context, fragmentShaderTemplate.c_str()))
2187 			<< glu::TransformFeedbackVarying		("out_te_tessCoord")
2188 			<< glu::TransformFeedbackMode			(GL_INTERLEAVED_ATTRIBS)));
2189 
2190 	m_testCtx.getLog() << *m_program;
2191 	if (!m_program->isOk())
2192 		TCU_FAIL("Program compilation failed");
2193 }
2194 
deinit(void)2195 void FractionalSpacingModeCase::deinit (void)
2196 {
2197 	m_program.clear();
2198 }
2199 
genTessLevelCases(void)2200 vector<float> FractionalSpacingModeCase::genTessLevelCases (void)
2201 {
2202 	vector<float> result;
2203 
2204 	// Ranges [7.0 .. 8.0), [8.0 .. 9.0) and [9.0 .. 10.0)
2205 	{
2206 		static const float	rangeStarts[]		= { 7.0f, 8.0f, 9.0f };
2207 		const int			numSamplesPerRange	= 10;
2208 
2209 		for (int rangeNdx = 0; rangeNdx < DE_LENGTH_OF_ARRAY(rangeStarts); rangeNdx++)
2210 			for (int i = 0; i < numSamplesPerRange; i++)
2211 				result.push_back(rangeStarts[rangeNdx] + (float)i/(float)numSamplesPerRange);
2212 	}
2213 
2214 	// 0.3, 1.3, 2.3,  ... , 62.3
2215 	for (int i = 0; i <= 62; i++)
2216 		result.push_back((float)i + 0.3f);
2217 
2218 	return result;
2219 }
2220 
iterate(void)2221 FractionalSpacingModeCase::IterateResult FractionalSpacingModeCase::iterate (void)
2222 {
2223 	typedef TransformFeedbackHandler<float> TFHandler;
2224 
2225 	TestLog&						log							= m_testCtx.getLog();
2226 	const RenderContext&			renderCtx					= m_context.getRenderContext();
2227 	const RandomViewport			viewport					(renderCtx.getRenderTarget(), RENDER_SIZE, RENDER_SIZE, deStringHash(getName()));
2228 	const deUint32					programGL					= m_program->getProgram();
2229 	const glw::Functions&			gl							= renderCtx.getFunctions();
2230 
2231 	const int						tessLevelOuter1Loc			= gl.getUniformLocation(programGL, "u_tessLevelOuter1");
2232 
2233 	// Second outer tessellation levels.
2234 	const vector<float>				tessLevelCases				= genTessLevelCases();
2235 	const int						maxNumVertices				= 1 + getClampedRoundedTessLevel(m_spacing, *std::max_element(tessLevelCases.begin(), tessLevelCases.end()));
2236 	vector<float>					additionalSegmentLengths;
2237 	vector<int>						additionalSegmentLocations;
2238 
2239 	const TFHandler					tfHandler					(m_context.getRenderContext(), maxNumVertices);
2240 
2241 	bool							success						= true;
2242 
2243 	setViewport(gl, viewport);
2244 	gl.useProgram(programGL);
2245 
2246 	gl.patchParameteri(GL_PATCH_VERTICES, 1);
2247 
2248 	for (int tessLevelCaseNdx = 0; tessLevelCaseNdx < (int)tessLevelCases.size(); tessLevelCaseNdx++)
2249 	{
2250 		const float outerLevel1 = tessLevelCases[tessLevelCaseNdx];
2251 
2252 		gl.uniform1f(tessLevelOuter1Loc, outerLevel1);
2253 		GLU_EXPECT_NO_ERROR(gl.getError(), "Setup failed");
2254 
2255 		{
2256 			const TFHandler::Result		tfResult = tfHandler.renderAndGetPrimitives(programGL, GL_POINTS, 0, DE_NULL, 1);
2257 			float						additionalSegmentLength;
2258 			int							additionalSegmentLocation;
2259 
2260 			success = verifyFractionalSpacingSingle(log, m_spacing, outerLevel1, tfResult.varying,
2261 													additionalSegmentLength, additionalSegmentLocation);
2262 
2263 			if (!success)
2264 				break;
2265 
2266 			additionalSegmentLengths.push_back(additionalSegmentLength);
2267 			additionalSegmentLocations.push_back(additionalSegmentLocation);
2268 		}
2269 	}
2270 
2271 	if (success)
2272 		success = verifyFractionalSpacingMultiple(log, m_spacing, tessLevelCases, additionalSegmentLengths, additionalSegmentLocations);
2273 
2274 	m_testCtx.setTestResult(success ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, success ? "Pass" : "Invalid tessellation coordinates");
2275 	return STOP;
2276 }
2277 
2278 // Base class for a case with one input attribute (in_v_position) and optionally a TCS; tests with a couple of different sets of tessellation levels.
2279 class BasicVariousTessLevelsPosAttrCase : public TestCase
2280 {
2281 public:
BasicVariousTessLevelsPosAttrCase(Context & context,const char * name,const char * description,TessPrimitiveType primitiveType,SpacingMode spacing,const char * referenceImagePathPrefix)2282 					BasicVariousTessLevelsPosAttrCase (Context&				context,
2283 													   const char*			name,
2284 													   const char*			description,
2285 													   TessPrimitiveType	primitiveType,
2286 													   SpacingMode			spacing,
2287 													   const char*			referenceImagePathPrefix)
2288 						: TestCase						(context, name, description)
2289 						, m_primitiveType				(primitiveType)
2290 						, m_spacing						(spacing)
2291 						, m_referenceImagePathPrefix	(referenceImagePathPrefix)
2292 					{
2293 					}
2294 
2295 	void			init			(void);
2296 	void			deinit			(void);
2297 	IterateResult	iterate			(void);
2298 
2299 protected:
2300 	virtual const glu::ProgramSources	makeSources (TessPrimitiveType, SpacingMode, const char* vtxOutPosAttrName) const = DE_NULL;
2301 
2302 private:
2303 	static const int					RENDER_SIZE = 256;
2304 
2305 	const TessPrimitiveType				m_primitiveType;
2306 	const SpacingMode					m_spacing;
2307 	const string						m_referenceImagePathPrefix;
2308 
2309 	SharedPtr<const ShaderProgram>		m_program;
2310 };
2311 
init(void)2312 void BasicVariousTessLevelsPosAttrCase::init (void)
2313 {
2314 	checkTessellationSupport(m_context);
2315 	checkRenderTargetSize(m_context.getRenderTarget(), RENDER_SIZE);
2316 
2317 	{
2318 		glu::ProgramSources sources = makeSources(m_primitiveType, m_spacing, "in_tc_position");
2319 		DE_ASSERT(sources.sources[glu::SHADERTYPE_TESSELLATION_CONTROL].empty());
2320 
2321 		std::string tessellationControlTemplate		("${GLSL_VERSION_DECL}\n"
2322 													 "${TESSELLATION_SHADER_REQUIRE}\n"
2323 													"\n"
2324 													"layout (vertices = " + string(m_primitiveType == TESSPRIMITIVETYPE_TRIANGLES ? "3" : "4") + ") out;\n"
2325 													"\n"
2326 													"in highp vec2 in_tc_position[];\n"
2327 													"\n"
2328 													"out highp vec2 in_te_position[];\n"
2329 													"\n"
2330 													"uniform mediump float u_tessLevelInner0;\n"
2331 													"uniform mediump float u_tessLevelInner1;\n"
2332 													"uniform mediump float u_tessLevelOuter0;\n"
2333 													"uniform mediump float u_tessLevelOuter1;\n"
2334 													"uniform mediump float u_tessLevelOuter2;\n"
2335 													"uniform mediump float u_tessLevelOuter3;\n"
2336 													"\n"
2337 													"void main (void)\n"
2338 													"{\n"
2339 													"	in_te_position[gl_InvocationID] = in_tc_position[gl_InvocationID];\n"
2340 													"\n"
2341 													"	gl_TessLevelInner[0] = u_tessLevelInner0;\n"
2342 													"	gl_TessLevelInner[1] = u_tessLevelInner1;\n"
2343 													"\n"
2344 													"	gl_TessLevelOuter[0] = u_tessLevelOuter0;\n"
2345 													"	gl_TessLevelOuter[1] = u_tessLevelOuter1;\n"
2346 													"	gl_TessLevelOuter[2] = u_tessLevelOuter2;\n"
2347 													"	gl_TessLevelOuter[3] = u_tessLevelOuter3;\n"
2348 													"}\n");
2349 
2350 		sources << glu::TessellationControlSource(specializeShader(m_context, tessellationControlTemplate.c_str()));
2351 
2352 		m_program = SharedPtr<const ShaderProgram>(new glu::ShaderProgram(m_context.getRenderContext(), sources));
2353 	}
2354 
2355 	m_testCtx.getLog() << *m_program;
2356 	if (!m_program->isOk())
2357 		TCU_FAIL("Program compilation failed");
2358 }
2359 
deinit(void)2360 void BasicVariousTessLevelsPosAttrCase::deinit (void)
2361 {
2362 	m_program.clear();
2363 }
2364 
iterate(void)2365 BasicVariousTessLevelsPosAttrCase::IterateResult BasicVariousTessLevelsPosAttrCase::iterate (void)
2366 {
2367 	static const struct
2368 	{
2369 		float inner[2];
2370 		float outer[4];
2371 	} tessLevelCases[] =
2372 	{
2373 		{ { 9.0f,	9.0f	},	{ 9.0f,		9.0f,	9.0f,	9.0f	} },
2374 		{ { 8.0f,	11.0f	},	{ 13.0f,	15.0f,	18.0f,	21.0f	} },
2375 		{ { 17.0f,	14.0f	},	{ 3.0f,		6.0f,	9.0f,	12.0f	} }
2376 	};
2377 
2378 	TestLog&				log					= m_testCtx.getLog();
2379 	const RenderContext&	renderCtx			= m_context.getRenderContext();
2380 	const RandomViewport	viewport			(renderCtx.getRenderTarget(), RENDER_SIZE, RENDER_SIZE, deStringHash(getName()));
2381 	const deUint32			programGL			= m_program->getProgram();
2382 	const glw::Functions&	gl					= renderCtx.getFunctions();
2383 	const int				patchSize			= m_primitiveType == TESSPRIMITIVETYPE_TRIANGLES	? 3
2384 												: m_primitiveType == TESSPRIMITIVETYPE_QUADS		? 4
2385 												: m_primitiveType == TESSPRIMITIVETYPE_ISOLINES		? 4
2386 												: -1;
2387 
2388 	setViewport(gl, viewport);
2389 	gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
2390 	gl.useProgram(programGL);
2391 
2392 	gl.patchParameteri(GL_PATCH_VERTICES, patchSize);
2393 
2394 	for (int tessLevelCaseNdx = 0; tessLevelCaseNdx < DE_LENGTH_OF_ARRAY(tessLevelCases); tessLevelCaseNdx++)
2395 	{
2396 		float innerLevels[2];
2397 		float outerLevels[4];
2398 
2399 		for (int i = 0; i < DE_LENGTH_OF_ARRAY(innerLevels); i++)
2400 			innerLevels[i] = (float)getClampedRoundedTessLevel(m_spacing, tessLevelCases[tessLevelCaseNdx].inner[i]);
2401 
2402 		for (int i = 0; i < DE_LENGTH_OF_ARRAY(outerLevels); i++)
2403 			outerLevels[i] = (float)getClampedRoundedTessLevel(m_spacing, tessLevelCases[tessLevelCaseNdx].outer[i]);
2404 
2405 		log << TestLog::Message << "Tessellation levels: " << tessellationLevelsString(&innerLevels[0], &outerLevels[0], m_primitiveType) << TestLog::EndMessage;
2406 
2407 		gl.uniform1f(gl.getUniformLocation(programGL, "u_tessLevelInner0"), innerLevels[0]);
2408 		gl.uniform1f(gl.getUniformLocation(programGL, "u_tessLevelInner1"), innerLevels[1]);
2409 		gl.uniform1f(gl.getUniformLocation(programGL, "u_tessLevelOuter0"), outerLevels[0]);
2410 		gl.uniform1f(gl.getUniformLocation(programGL, "u_tessLevelOuter1"), outerLevels[1]);
2411 		gl.uniform1f(gl.getUniformLocation(programGL, "u_tessLevelOuter2"), outerLevels[2]);
2412 		gl.uniform1f(gl.getUniformLocation(programGL, "u_tessLevelOuter3"), outerLevels[3]);
2413 
2414 		gl.clear(GL_COLOR_BUFFER_BIT);
2415 
2416 		{
2417 			vector<Vec2> positions;
2418 			positions.reserve(4);
2419 
2420 			if (m_primitiveType == TESSPRIMITIVETYPE_TRIANGLES)
2421 			{
2422 				positions.push_back(Vec2( 0.8f,    0.6f));
2423 				positions.push_back(Vec2( 0.0f, -0.786f));
2424 				positions.push_back(Vec2(-0.8f,    0.6f));
2425 			}
2426 			else if (m_primitiveType == TESSPRIMITIVETYPE_QUADS || m_primitiveType == TESSPRIMITIVETYPE_ISOLINES)
2427 			{
2428 				positions.push_back(Vec2(-0.8f, -0.8f));
2429 				positions.push_back(Vec2( 0.8f, -0.8f));
2430 				positions.push_back(Vec2(-0.8f,  0.8f));
2431 				positions.push_back(Vec2( 0.8f,  0.8f));
2432 			}
2433 			else
2434 				DE_ASSERT(false);
2435 
2436 			DE_ASSERT((int)positions.size() == patchSize);
2437 
2438 			const glu::VertexArrayBinding attrBindings[] =
2439 			{
2440 				glu::va::Float("in_v_position", 2, (int)positions.size(), 0, &positions[0].x())
2441 			};
2442 
2443 			glu::draw(m_context.getRenderContext(), programGL, DE_LENGTH_OF_ARRAY(attrBindings), &attrBindings[0],
2444 				glu::pr::Patches(patchSize));
2445 			GLU_EXPECT_NO_ERROR(gl.getError(), "Draw failed");
2446 		}
2447 
2448 		{
2449 			const tcu::Surface			rendered	= getPixels(renderCtx, viewport);
2450 			const tcu::TextureLevel		reference	= getPNG(m_testCtx.getArchive(), m_referenceImagePathPrefix + "_" + de::toString(tessLevelCaseNdx) + ".png");
2451 			const bool					success		= tcu::fuzzyCompare(log, "ImageComparison", "Image Comparison", reference.getAccess(), rendered.getAccess(), 0.002f, tcu::COMPARE_LOG_RESULT);
2452 
2453 			if (!success)
2454 			{
2455 				m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed");
2456 				return STOP;
2457 			}
2458 		}
2459 	}
2460 
2461 	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
2462 	return STOP;
2463 }
2464 
2465 // Test that there are no obvious gaps in the triangulation of a tessellated triangle or quad.
2466 class BasicTriangleFillCoverCase : public BasicVariousTessLevelsPosAttrCase
2467 {
2468 public:
BasicTriangleFillCoverCase(Context & context,const char * name,const char * description,TessPrimitiveType primitiveType,SpacingMode spacing,const char * referenceImagePathPrefix)2469 	BasicTriangleFillCoverCase (Context& context, const char* name, const char* description, TessPrimitiveType primitiveType, SpacingMode spacing, const char* referenceImagePathPrefix)
2470 		: BasicVariousTessLevelsPosAttrCase (context, name, description, primitiveType, spacing, referenceImagePathPrefix)
2471 	{
2472 		DE_ASSERT(primitiveType == TESSPRIMITIVETYPE_TRIANGLES || primitiveType == TESSPRIMITIVETYPE_QUADS);
2473 	}
2474 
2475 protected:
init(void)2476 	void init (void)
2477 	{
2478 		checkGPUShader5Support(m_context);
2479 		BasicVariousTessLevelsPosAttrCase::init();
2480 	}
2481 
makeSources(TessPrimitiveType primitiveType,SpacingMode spacing,const char * vtxOutPosAttrName) const2482 	const glu::ProgramSources makeSources (TessPrimitiveType primitiveType, SpacingMode spacing, const char* vtxOutPosAttrName) const
2483 	{
2484 		std::string vertexShaderTemplate			("${GLSL_VERSION_DECL}\n"
2485 													 "\n"
2486 													 "in highp vec2 in_v_position;\n"
2487 													 "\n"
2488 													 "out highp vec2 " + string(vtxOutPosAttrName) + ";\n"
2489 													 "\n"
2490 													 "void main (void)\n"
2491 													 "{\n"
2492 													 "	" + vtxOutPosAttrName + " = in_v_position;\n"
2493 													 "}\n");
2494 		std::string tessellationEvaluationTemplate	("${GLSL_VERSION_DECL}\n"
2495 													 "${TESSELLATION_SHADER_REQUIRE}\n"
2496 													 "${GPU_SHADER5_REQUIRE}\n"
2497 													 "\n"
2498 													 + getTessellationEvaluationInLayoutString(primitiveType, spacing) +
2499 													 "\n"
2500 													 "in highp vec2 in_te_position[];\n"
2501 													 "\n"
2502 													 "precise gl_Position;\n"
2503 													 "void main (void)\n"
2504 													 "{\n"
2505 													 + (primitiveType == TESSPRIMITIVETYPE_TRIANGLES ?
2506 														"\n"
2507 														"	highp float d = 3.0 * min(gl_TessCoord.x, min(gl_TessCoord.y, gl_TessCoord.z));\n"
2508 														"	highp vec2 corner0 = in_te_position[0];\n"
2509 														"	highp vec2 corner1 = in_te_position[1];\n"
2510 														"	highp vec2 corner2 = in_te_position[2];\n"
2511 														"	highp vec2 pos =  corner0*gl_TessCoord.x + corner1*gl_TessCoord.y + corner2*gl_TessCoord.z;\n"
2512 														"	highp vec2 fromCenter = pos - (corner0 + corner1 + corner2) / 3.0;\n"
2513 														"	highp float f = (1.0 - length(fromCenter)) * (1.5 - d);\n"
2514 														"	pos += 0.75 * f * fromCenter / (length(fromCenter) + 0.3);\n"
2515 														"	gl_Position = vec4(pos, 0.0, 1.0);\n"
2516 													  : primitiveType == TESSPRIMITIVETYPE_QUADS ?
2517 														"	highp vec2 corner0 = in_te_position[0];\n"
2518 														"	highp vec2 corner1 = in_te_position[1];\n"
2519 														"	highp vec2 corner2 = in_te_position[2];\n"
2520 														"	highp vec2 corner3 = in_te_position[3];\n"
2521 														"	highp vec2 pos = (1.0-gl_TessCoord.x)*(1.0-gl_TessCoord.y)*corner0\n"
2522 														"	               + (    gl_TessCoord.x)*(1.0-gl_TessCoord.y)*corner1\n"
2523 														"	               + (1.0-gl_TessCoord.x)*(    gl_TessCoord.y)*corner2\n"
2524 														"	               + (    gl_TessCoord.x)*(    gl_TessCoord.y)*corner3;\n"
2525 														"	highp float d = 2.0 * min(abs(gl_TessCoord.x-0.5), abs(gl_TessCoord.y-0.5));\n"
2526 														"	highp vec2 fromCenter = pos - (corner0 + corner1 + corner2 + corner3) / 4.0;\n"
2527 														"	highp float f = (1.0 - length(fromCenter)) * sqrt(1.7 - d);\n"
2528 														"	pos += 0.75 * f * fromCenter / (length(fromCenter) + 0.3);\n"
2529 														"	gl_Position = vec4(pos, 0.0, 1.0);\n"
2530 													  : DE_NULL) +
2531 													 "}\n");
2532 		std::string fragmentShaderTemplate			("${GLSL_VERSION_DECL}\n"
2533 													 "\n"
2534 													 "layout (location = 0) out mediump vec4 o_color;\n"
2535 													 "\n"
2536 													 "void main (void)\n"
2537 													 "{\n"
2538 													 "	o_color = vec4(1.0);\n"
2539 													 "}\n");
2540 
2541 		return glu::ProgramSources()
2542 			<< glu::VertexSource					(specializeShader(m_context, vertexShaderTemplate.c_str()))
2543 			<< glu::TessellationEvaluationSource	(specializeShader(m_context, tessellationEvaluationTemplate.c_str()))
2544 			<< glu::FragmentSource					(specializeShader(m_context, fragmentShaderTemplate.c_str()));
2545 	}
2546 };
2547 
2548 // Check that there are no obvious overlaps in the triangulation of a tessellated triangle or quad.
2549 class BasicTriangleFillNonOverlapCase : public BasicVariousTessLevelsPosAttrCase
2550 {
2551 public:
BasicTriangleFillNonOverlapCase(Context & context,const char * name,const char * description,TessPrimitiveType primitiveType,SpacingMode spacing,const char * referenceImagePathPrefix)2552 	BasicTriangleFillNonOverlapCase (Context& context, const char* name, const char* description, TessPrimitiveType primitiveType, SpacingMode spacing, const char* referenceImagePathPrefix)
2553 		: BasicVariousTessLevelsPosAttrCase (context, name, description, primitiveType, spacing, referenceImagePathPrefix)
2554 	{
2555 		DE_ASSERT(primitiveType == TESSPRIMITIVETYPE_TRIANGLES || primitiveType == TESSPRIMITIVETYPE_QUADS);
2556 	}
2557 
2558 protected:
makeSources(TessPrimitiveType primitiveType,SpacingMode spacing,const char * vtxOutPosAttrName) const2559 	const glu::ProgramSources makeSources (TessPrimitiveType primitiveType, SpacingMode spacing, const char* vtxOutPosAttrName) const
2560 	{
2561 		std::string vertexShaderTemplate			("${GLSL_VERSION_DECL}\n"
2562 													 "\n"
2563 													 "in highp vec2 in_v_position;\n"
2564 													 "\n"
2565 													 "out highp vec2 " + string(vtxOutPosAttrName) + ";\n"
2566 													 "\n"
2567 													 "void main (void)\n"
2568 													 "{\n"
2569 													 "	" + vtxOutPosAttrName + " = in_v_position;\n"
2570 													 "}\n");
2571 		std::string tessellationEvaluationTemplate	("${GLSL_VERSION_DECL}\n"
2572 													 "${TESSELLATION_SHADER_REQUIRE}\n"
2573 													 "\n"
2574 													 + getTessellationEvaluationInLayoutString(primitiveType, spacing) +
2575 													 "\n"
2576 													 "in highp vec2 in_te_position[];\n"
2577 													 "\n"
2578 													 "out mediump vec4 in_f_color;\n"
2579 													 "\n"
2580 													 "uniform mediump float u_tessLevelInner0;\n"
2581 													 "uniform mediump float u_tessLevelInner1;\n"
2582 													 "\n"
2583 													 "void main (void)\n"
2584 													 "{\n"
2585 													 + (primitiveType == TESSPRIMITIVETYPE_TRIANGLES ?
2586 														"\n"
2587 														"	highp vec2 corner0 = in_te_position[0];\n"
2588 														"	highp vec2 corner1 = in_te_position[1];\n"
2589 														"	highp vec2 corner2 = in_te_position[2];\n"
2590 														"	highp vec2 pos =  corner0*gl_TessCoord.x + corner1*gl_TessCoord.y + corner2*gl_TessCoord.z;\n"
2591 														"	gl_Position = vec4(pos, 0.0, 1.0);\n"
2592 														"	highp int numConcentricTriangles = int(round(u_tessLevelInner0)) / 2 + 1;\n"
2593 														"	highp float d = 3.0 * min(gl_TessCoord.x, min(gl_TessCoord.y, gl_TessCoord.z));\n"
2594 														"	highp int phase = int(d*float(numConcentricTriangles)) % 3;\n"
2595 														"	in_f_color = phase == 0 ? vec4(1.0, 0.0, 0.0, 1.0)\n"
2596 														"	           : phase == 1 ? vec4(0.0, 1.0, 0.0, 1.0)\n"
2597 														"	           :              vec4(0.0, 0.0, 1.0, 1.0);\n"
2598 													  : primitiveType == TESSPRIMITIVETYPE_QUADS ?
2599 														"	highp vec2 corner0 = in_te_position[0];\n"
2600 														"	highp vec2 corner1 = in_te_position[1];\n"
2601 														"	highp vec2 corner2 = in_te_position[2];\n"
2602 														"	highp vec2 corner3 = in_te_position[3];\n"
2603 														"	highp vec2 pos = (1.0-gl_TessCoord.x)*(1.0-gl_TessCoord.y)*corner0\n"
2604 														"	               + (    gl_TessCoord.x)*(1.0-gl_TessCoord.y)*corner1\n"
2605 														"	               + (1.0-gl_TessCoord.x)*(    gl_TessCoord.y)*corner2\n"
2606 														"	               + (    gl_TessCoord.x)*(    gl_TessCoord.y)*corner3;\n"
2607 														"	gl_Position = vec4(pos, 0.0, 1.0);\n"
2608 														"	highp int phaseX = int(round((0.5 - abs(gl_TessCoord.x-0.5)) * u_tessLevelInner0));\n"
2609 														"	highp int phaseY = int(round((0.5 - abs(gl_TessCoord.y-0.5)) * u_tessLevelInner1));\n"
2610 														"	highp int phase = min(phaseX, phaseY) % 3;\n"
2611 														"	in_f_color = phase == 0 ? vec4(1.0, 0.0, 0.0, 1.0)\n"
2612 														"	           : phase == 1 ? vec4(0.0, 1.0, 0.0, 1.0)\n"
2613 														"	           :              vec4(0.0, 0.0, 1.0, 1.0);\n"
2614 													  : DE_NULL) +
2615 													 "}\n");
2616 		std::string fragmentShaderTemplate			("${GLSL_VERSION_DECL}\n"
2617 													 "\n"
2618 													 "layout (location = 0) out mediump vec4 o_color;\n"
2619 													 "\n"
2620 													 "in mediump vec4 in_f_color;\n"
2621 													 "\n"
2622 													 "void main (void)\n"
2623 													 "{\n"
2624 													 "	o_color = in_f_color;\n"
2625 													 "}\n");
2626 
2627 		return glu::ProgramSources()
2628 			<< glu::VertexSource					(specializeShader(m_context, vertexShaderTemplate.c_str()))
2629 			<< glu::TessellationEvaluationSource	(specializeShader(m_context, tessellationEvaluationTemplate.c_str()))
2630 			<< glu::FragmentSource					(specializeShader(m_context, fragmentShaderTemplate.c_str()));
2631 	}
2632 };
2633 
2634 // Basic isolines rendering case.
2635 class IsolinesRenderCase : public BasicVariousTessLevelsPosAttrCase
2636 {
2637 public:
IsolinesRenderCase(Context & context,const char * name,const char * description,SpacingMode spacing,const char * referenceImagePathPrefix)2638 	IsolinesRenderCase (Context& context, const char* name, const char* description, SpacingMode spacing, const char* referenceImagePathPrefix)
2639 		: BasicVariousTessLevelsPosAttrCase (context, name, description, TESSPRIMITIVETYPE_ISOLINES, spacing, referenceImagePathPrefix)
2640 	{
2641 	}
2642 
2643 protected:
makeSources(TessPrimitiveType primitiveType,SpacingMode spacing,const char * vtxOutPosAttrName) const2644 	const glu::ProgramSources makeSources (TessPrimitiveType primitiveType, SpacingMode spacing, const char* vtxOutPosAttrName) const
2645 	{
2646 		DE_ASSERT(primitiveType == TESSPRIMITIVETYPE_ISOLINES);
2647 		DE_UNREF(primitiveType);
2648 
2649 		std::string vertexShaderTemplate			("${GLSL_VERSION_DECL}\n"
2650 													 "\n"
2651 													 "in highp vec2 in_v_position;\n"
2652 													 "\n"
2653 													 "out highp vec2 " + string(vtxOutPosAttrName) + ";\n"
2654 													 "\n"
2655 													 "void main (void)\n"
2656 													 "{\n"
2657 													 "	" + vtxOutPosAttrName + " = in_v_position;\n"
2658 													 "}\n");
2659 		std::string tessellationEvaluationTemplate	("${GLSL_VERSION_DECL}\n"
2660 													 "${TESSELLATION_SHADER_REQUIRE}\n"
2661 													 "\n"
2662 													 + getTessellationEvaluationInLayoutString(TESSPRIMITIVETYPE_ISOLINES, spacing) +
2663 													 "\n"
2664 													 "in highp vec2 in_te_position[];\n"
2665 													 "\n"
2666 													 "out mediump vec4 in_f_color;\n"
2667 													 "\n"
2668 													 "uniform mediump float u_tessLevelOuter0;\n"
2669 													 "uniform mediump float u_tessLevelOuter1;\n"
2670 													 "\n"
2671 													 "void main (void)\n"
2672 													 "{\n"
2673 													 "	highp vec2 corner0 = in_te_position[0];\n"
2674 													 "	highp vec2 corner1 = in_te_position[1];\n"
2675 													 "	highp vec2 corner2 = in_te_position[2];\n"
2676 													 "	highp vec2 corner3 = in_te_position[3];\n"
2677 													 "	highp vec2 pos = (1.0-gl_TessCoord.x)*(1.0-gl_TessCoord.y)*corner0\n"
2678 													 "	               + (    gl_TessCoord.x)*(1.0-gl_TessCoord.y)*corner1\n"
2679 													 "	               + (1.0-gl_TessCoord.x)*(    gl_TessCoord.y)*corner2\n"
2680 													 "	               + (    gl_TessCoord.x)*(    gl_TessCoord.y)*corner3;\n"
2681 													 "	pos.y += 0.15*sin(gl_TessCoord.x*10.0);\n"
2682 													 "	gl_Position = vec4(pos, 0.0, 1.0);\n"
2683 													 "	highp int phaseX = int(round(gl_TessCoord.x*u_tessLevelOuter1));\n"
2684 													 "	highp int phaseY = int(round(gl_TessCoord.y*u_tessLevelOuter0));\n"
2685 													 "	highp int phase = (phaseX + phaseY) % 3;\n"
2686 													 "	in_f_color = phase == 0 ? vec4(1.0, 0.0, 0.0, 1.0)\n"
2687 													 "	           : phase == 1 ? vec4(0.0, 1.0, 0.0, 1.0)\n"
2688 													 "	           :              vec4(0.0, 0.0, 1.0, 1.0);\n"
2689 													 "}\n");
2690 		std::string fragmentShaderTemplate			("${GLSL_VERSION_DECL}\n"
2691 													 "\n"
2692 													 "layout (location = 0) out mediump vec4 o_color;\n"
2693 													 "\n"
2694 													 "in mediump vec4 in_f_color;\n"
2695 													 "\n"
2696 													 "void main (void)\n"
2697 													 "{\n"
2698 													 "	o_color = in_f_color;\n"
2699 													 "}\n");
2700 
2701 		return glu::ProgramSources()
2702 				<< glu::VertexSource					(specializeShader(m_context, vertexShaderTemplate.c_str()))
2703 				<< glu::TessellationEvaluationSource	(specializeShader(m_context, tessellationEvaluationTemplate.c_str()))
2704 				<< glu::FragmentSource					(specializeShader(m_context, fragmentShaderTemplate.c_str()));
2705 	}
2706 };
2707 
2708 // Test the "cw" and "ccw" TES input layout qualifiers.
2709 class WindingCase : public TestCase
2710 {
2711 public:
WindingCase(Context & context,const char * name,const char * description,TessPrimitiveType primitiveType,Winding winding)2712 					WindingCase (Context& context, const char* name, const char* description, TessPrimitiveType primitiveType, Winding winding)
2713 						: TestCase			(context, name, description)
2714 						, m_primitiveType	(primitiveType)
2715 						, m_winding			(winding)
2716 					{
2717 						DE_ASSERT(primitiveType == TESSPRIMITIVETYPE_TRIANGLES || primitiveType == TESSPRIMITIVETYPE_QUADS);
2718 					}
2719 
2720 	void			init		(void);
2721 	void			deinit		(void);
2722 	IterateResult	iterate		(void);
2723 
2724 private:
2725 	static const int				RENDER_SIZE = 64;
2726 
2727 	const TessPrimitiveType			m_primitiveType;
2728 	const Winding					m_winding;
2729 
2730 	SharedPtr<const ShaderProgram>	m_program;
2731 };
2732 
init(void)2733 void WindingCase::init (void)
2734 {
2735 	checkTessellationSupport(m_context);
2736 	checkRenderTargetSize(m_context.getRenderTarget(), RENDER_SIZE);
2737 
2738 	std::string vertexShaderTemplate			("${GLSL_VERSION_DECL}\n"
2739 													 "\n"
2740 													 "void main (void)\n"
2741 													 "{\n"
2742 												 "}\n");
2743 	std::string tessellationControlTemplate		("${GLSL_VERSION_DECL}\n"
2744 												 "${TESSELLATION_SHADER_REQUIRE}\n"
2745 													 "\n"
2746 													 "layout (vertices = 1) out;\n"
2747 													 "\n"
2748 													 "void main (void)\n"
2749 													 "{\n"
2750 													 "	gl_TessLevelInner[0] = 5.0;\n"
2751 													 "	gl_TessLevelInner[1] = 5.0;\n"
2752 													 "\n"
2753 													 "	gl_TessLevelOuter[0] = 5.0;\n"
2754 													 "	gl_TessLevelOuter[1] = 5.0;\n"
2755 													 "	gl_TessLevelOuter[2] = 5.0;\n"
2756 													 "	gl_TessLevelOuter[3] = 5.0;\n"
2757 												 "}\n");
2758 	std::string tessellationEvaluationTemplate	("${GLSL_VERSION_DECL}\n"
2759 												 "${TESSELLATION_SHADER_REQUIRE}\n"
2760 													 "\n"
2761 													 + getTessellationEvaluationInLayoutString(m_primitiveType, m_winding) +
2762 													 "\n"
2763 													 "void main (void)\n"
2764 													 "{\n"
2765 													 "	gl_Position = vec4(gl_TessCoord.xy*2.0 - 1.0, 0.0, 1.0);\n"
2766 												 "}\n");
2767 	std::string fragmentShaderTemplate			("${GLSL_VERSION_DECL}\n"
2768 													 "\n"
2769 													 "layout (location = 0) out mediump vec4 o_color;\n"
2770 													 "\n"
2771 													 "void main (void)\n"
2772 													 "{\n"
2773 													 "	o_color = vec4(1.0);\n"
2774 												 "}\n");
2775 
2776 	m_program = SharedPtr<const ShaderProgram>(new ShaderProgram(m_context.getRenderContext(), glu::ProgramSources()
2777 			<< glu::VertexSource					(specializeShader(m_context, vertexShaderTemplate.c_str()))
2778 			<< glu::TessellationControlSource		(specializeShader(m_context, tessellationControlTemplate.c_str()))
2779 			<< glu::TessellationEvaluationSource	(specializeShader(m_context, tessellationEvaluationTemplate.c_str()))
2780 			<< glu::FragmentSource					(specializeShader(m_context, fragmentShaderTemplate.c_str()))));
2781 
2782 	m_testCtx.getLog() << *m_program;
2783 	if (!m_program->isOk())
2784 		TCU_FAIL("Program compilation failed");
2785 }
2786 
deinit(void)2787 void WindingCase::deinit (void)
2788 {
2789 	m_program.clear();
2790 }
2791 
iterate(void)2792 WindingCase::IterateResult WindingCase::iterate (void)
2793 {
2794 	TestLog&						log							= m_testCtx.getLog();
2795 	const RenderContext&			renderCtx					= m_context.getRenderContext();
2796 	const RandomViewport			viewport					(renderCtx.getRenderTarget(), RENDER_SIZE, RENDER_SIZE, deStringHash(getName()));
2797 	const deUint32					programGL					= m_program->getProgram();
2798 	const glw::Functions&			gl							= renderCtx.getFunctions();
2799 	const glu::VertexArray			vao							(renderCtx);
2800 
2801 	bool							success						= true;
2802 
2803 	setViewport(gl, viewport);
2804 	gl.clearColor(1.0f, 0.0f, 0.0f, 1.0f);
2805 	gl.useProgram(programGL);
2806 
2807 	gl.patchParameteri(GL_PATCH_VERTICES, 1);
2808 
2809 	gl.enable(GL_CULL_FACE);
2810 
2811 	gl.bindVertexArray(*vao);
2812 
2813 	log << TestLog::Message << "Face culling enabled" << TestLog::EndMessage;
2814 
2815 	for (int frontFaceWinding = 0; frontFaceWinding < WINDING_LAST; frontFaceWinding++)
2816 	{
2817 		log << TestLog::Message << "Setting glFrontFace(" << (frontFaceWinding == WINDING_CW ? "GL_CW" : "GL_CCW") << ")" << TestLog::EndMessage;
2818 
2819 		gl.frontFace(frontFaceWinding == WINDING_CW ? GL_CW : GL_CCW);
2820 
2821 		gl.clear(GL_COLOR_BUFFER_BIT);
2822 		gl.drawArrays(GL_PATCHES, 0, 1);
2823 		GLU_EXPECT_NO_ERROR(gl.getError(), "Draw failed");
2824 
2825 		{
2826 			const tcu::Surface rendered = getPixels(renderCtx, viewport);
2827 			log << TestLog::Image("RenderedImage", "Rendered Image", rendered);
2828 
2829 			{
2830 				const int totalNumPixels		= rendered.getWidth()*rendered.getHeight();
2831 				const int badPixelTolerance		= m_primitiveType == TESSPRIMITIVETYPE_TRIANGLES ? 5*de::max(rendered.getWidth(), rendered.getHeight()) : 0;
2832 
2833 				int numWhitePixels	= 0;
2834 				int numRedPixels	= 0;
2835 				for (int y = 0; y < rendered.getHeight();	y++)
2836 				for (int x = 0; x < rendered.getWidth();	x++)
2837 				{
2838 					numWhitePixels	+= rendered.getPixel(x, y) == tcu::RGBA::white()	? 1 : 0;
2839 					numRedPixels	+= rendered.getPixel(x, y) == tcu::RGBA::red()	? 1 : 0;
2840 				}
2841 
2842 				DE_ASSERT(numWhitePixels + numRedPixels <= totalNumPixels);
2843 
2844 				log << TestLog::Message << "Note: got " << numWhitePixels << " white and " << numRedPixels << " red pixels" << TestLog::EndMessage;
2845 
2846 				if (totalNumPixels - numWhitePixels - numRedPixels > badPixelTolerance)
2847 				{
2848 					log << TestLog::Message << "Failure: Got " << totalNumPixels - numWhitePixels - numRedPixels << " other than white or red pixels (maximum tolerance " << badPixelTolerance << ")" << TestLog::EndMessage;
2849 					success = false;
2850 					break;
2851 				}
2852 
2853 				if ((Winding)frontFaceWinding == m_winding)
2854 				{
2855 					if (m_primitiveType == TESSPRIMITIVETYPE_TRIANGLES)
2856 					{
2857 						if (de::abs(numWhitePixels - totalNumPixels/2) > badPixelTolerance)
2858 						{
2859 							log << TestLog::Message << "Failure: wrong number of white pixels; expected approximately " << totalNumPixels/2 << TestLog::EndMessage;
2860 							success = false;
2861 							break;
2862 						}
2863 					}
2864 					else if (m_primitiveType == TESSPRIMITIVETYPE_QUADS)
2865 					{
2866 						if (numWhitePixels != totalNumPixels)
2867 						{
2868 							log << TestLog::Message << "Failure: expected only white pixels (full-viewport quad)" << TestLog::EndMessage;
2869 							success = false;
2870 							break;
2871 						}
2872 					}
2873 					else
2874 						DE_ASSERT(false);
2875 				}
2876 				else
2877 				{
2878 					if (numWhitePixels != 0)
2879 					{
2880 						log << TestLog::Message << "Failure: expected only red pixels (everything culled)" << TestLog::EndMessage;
2881 						success = false;
2882 						break;
2883 					}
2884 				}
2885 			}
2886 		}
2887 	}
2888 
2889 	m_testCtx.setTestResult(success ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, success ? "Pass" : "Image verification failed");
2890 	return STOP;
2891 }
2892 
2893 // Test potentially differing input and output patch sizes.
2894 class PatchVertexCountCase : public TestCase
2895 {
2896 public:
PatchVertexCountCase(Context & context,const char * name,const char * description,int inputPatchSize,int outputPatchSize,const char * referenceImagePath)2897 	PatchVertexCountCase (Context& context, const char* name, const char* description, int inputPatchSize, int outputPatchSize, const char* referenceImagePath)
2898 		: TestCase				(context, name, description)
2899 		, m_inputPatchSize		(inputPatchSize)
2900 		, m_outputPatchSize		(outputPatchSize)
2901 		, m_referenceImagePath	(referenceImagePath)
2902 	{
2903 	}
2904 
2905 	void							init				(void);
2906 	void							deinit				(void);
2907 	IterateResult					iterate				(void);
2908 
2909 private:
2910 	static const int				RENDER_SIZE = 256;
2911 
2912 	const int						m_inputPatchSize;
2913 	const int						m_outputPatchSize;
2914 
2915 	const string					m_referenceImagePath;
2916 
2917 	SharedPtr<const ShaderProgram>	m_program;
2918 };
2919 
init(void)2920 void PatchVertexCountCase::init (void)
2921 {
2922 	checkTessellationSupport(m_context);
2923 	checkRenderTargetSize(m_context.getRenderTarget(), RENDER_SIZE);
2924 
2925 	const string inSizeStr		= de::toString(m_inputPatchSize);
2926 	const string outSizeStr		= de::toString(m_outputPatchSize);
2927 
2928 	std::string vertexShaderTemplate			("${GLSL_VERSION_DECL}\n"
2929 													 "\n"
2930 													 "in highp float in_v_attr;\n"
2931 													 "\n"
2932 													 "out highp float in_tc_attr;\n"
2933 													 "\n"
2934 													 "void main (void)\n"
2935 													 "{\n"
2936 													 "	in_tc_attr = in_v_attr;\n"
2937 												 "}\n");
2938 	std::string tessellationControlTemplate		("${GLSL_VERSION_DECL}\n"
2939 												 "${TESSELLATION_SHADER_REQUIRE}\n"
2940 													 "\n"
2941 													 "layout (vertices = " + outSizeStr + ") out;\n"
2942 													 "\n"
2943 													 "in highp float in_tc_attr[];\n"
2944 													 "\n"
2945 													 "out highp float in_te_attr[];\n"
2946 													 "\n"
2947 													 "void main (void)\n"
2948 													 "{\n"
2949 													 "	in_te_attr[gl_InvocationID] = in_tc_attr[gl_InvocationID*" + inSizeStr + "/" + outSizeStr + "];\n"
2950 													 "\n"
2951 													 "	gl_TessLevelInner[0] = 5.0;\n"
2952 													 "	gl_TessLevelInner[1] = 5.0;\n"
2953 													 "\n"
2954 													"	gl_TessLevelOuter[0] = 5.0;\n"
2955 													"	gl_TessLevelOuter[1] = 5.0;\n"
2956 													"	gl_TessLevelOuter[2] = 5.0;\n"
2957 													"	gl_TessLevelOuter[3] = 5.0;\n"
2958 												 "}\n");
2959 	std::string tessellationEvaluationTemplate	("${GLSL_VERSION_DECL}\n"
2960 												 "${TESSELLATION_SHADER_REQUIRE}\n"
2961 													 "\n"
2962 													 + getTessellationEvaluationInLayoutString(TESSPRIMITIVETYPE_QUADS) +
2963 													 "\n"
2964 													 "in highp float in_te_attr[];\n"
2965 													 "\n"
2966 													 "out mediump vec4 in_f_color;\n"
2967 													 "\n"
2968 													 "void main (void)\n"
2969 													 "{\n"
2970 													 "	highp float x = gl_TessCoord.x*2.0 - 1.0;\n"
2971 													 "	highp float y = gl_TessCoord.y - in_te_attr[int(round(gl_TessCoord.x*float(" + outSizeStr + "-1)))];\n"
2972 													 "	gl_Position = vec4(x, y, 0.0, 1.0);\n"
2973 													 "	in_f_color = vec4(1.0);\n"
2974 												 "}\n");
2975 	std::string fragmentShaderTemplate			("${GLSL_VERSION_DECL}\n"
2976 													 "\n"
2977 													 "layout (location = 0) out mediump vec4 o_color;\n"
2978 													 "\n"
2979 													 "in mediump vec4 in_f_color;\n"
2980 													 "\n"
2981 													 "void main (void)\n"
2982 													 "{\n"
2983 													 "	o_color = in_f_color;\n"
2984 												 "}\n");
2985 
2986 	m_program = SharedPtr<const ShaderProgram>(new ShaderProgram(m_context.getRenderContext(), glu::ProgramSources()
2987 			<< glu::VertexSource					(specializeShader(m_context, vertexShaderTemplate.c_str()))
2988 			<< glu::TessellationControlSource		(specializeShader(m_context, tessellationControlTemplate.c_str()))
2989 			<< glu::TessellationEvaluationSource	(specializeShader(m_context, tessellationEvaluationTemplate.c_str()))
2990 			<< glu::FragmentSource					(specializeShader(m_context, fragmentShaderTemplate.c_str()))));
2991 
2992 	m_testCtx.getLog() << *m_program;
2993 	if (!m_program->isOk())
2994 		TCU_FAIL("Program compilation failed");
2995 }
2996 
deinit(void)2997 void PatchVertexCountCase::deinit (void)
2998 {
2999 	m_program.clear();
3000 }
3001 
iterate(void)3002 PatchVertexCountCase::IterateResult PatchVertexCountCase::iterate (void)
3003 {
3004 	TestLog&					log						= m_testCtx.getLog();
3005 	const RenderContext&		renderCtx				= m_context.getRenderContext();
3006 	const RandomViewport		viewport				(renderCtx.getRenderTarget(), RENDER_SIZE, RENDER_SIZE, deStringHash(getName()));
3007 	const deUint32				programGL				= m_program->getProgram();
3008 	const glw::Functions&		gl						= renderCtx.getFunctions();
3009 
3010 	setViewport(gl, viewport);
3011 	gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
3012 	gl.useProgram(programGL);
3013 
3014 	log << TestLog::Message << "Note: input patch size is " << m_inputPatchSize << ", output patch size is " << m_outputPatchSize << TestLog::EndMessage;
3015 
3016 	{
3017 		vector<float> attributeData;
3018 		attributeData.reserve(m_inputPatchSize);
3019 
3020 		for (int i = 0; i < m_inputPatchSize; i++)
3021 		{
3022 			const float f = (float)i / (float)(m_inputPatchSize-1);
3023 			attributeData.push_back(f*f);
3024 		}
3025 
3026 		gl.patchParameteri(GL_PATCH_VERTICES, m_inputPatchSize);
3027 		gl.clear(GL_COLOR_BUFFER_BIT);
3028 
3029 		const glu::VertexArrayBinding attrBindings[] =
3030 		{
3031 			glu::va::Float("in_v_attr", 1, (int)attributeData.size(), 0, &attributeData[0])
3032 		};
3033 
3034 		glu::draw(m_context.getRenderContext(), programGL, DE_LENGTH_OF_ARRAY(attrBindings), &attrBindings[0],
3035 			glu::pr::Patches(m_inputPatchSize));
3036 		GLU_EXPECT_NO_ERROR(gl.getError(), "Draw failed");
3037 	}
3038 
3039 	{
3040 		const tcu::Surface			rendered	= getPixels(renderCtx, viewport);
3041 		const tcu::TextureLevel		reference	= getPNG(m_testCtx.getArchive(), m_referenceImagePath);
3042 		const bool					success		= tcu::fuzzyCompare(log, "ImageComparison", "Image Comparison", reference.getAccess(), rendered.getAccess(), 0.02f, tcu::COMPARE_LOG_RESULT);
3043 
3044 		m_testCtx.setTestResult(success ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, success ? "Pass" : "Image comparison failed");
3045 		return STOP;
3046 	}
3047 }
3048 
3049 // Test per-patch inputs/outputs.
3050 class PerPatchDataCase : public TestCase
3051 {
3052 public:
3053 	enum CaseType
3054 	{
3055 		CASETYPE_PRIMITIVE_ID_TCS = 0,
3056 		CASETYPE_PRIMITIVE_ID_TES,
3057 		CASETYPE_PATCH_VERTICES_IN_TCS,
3058 		CASETYPE_PATCH_VERTICES_IN_TES,
3059 		CASETYPE_TESS_LEVEL_INNER0_TES,
3060 		CASETYPE_TESS_LEVEL_INNER1_TES,
3061 		CASETYPE_TESS_LEVEL_OUTER0_TES,
3062 		CASETYPE_TESS_LEVEL_OUTER1_TES,
3063 		CASETYPE_TESS_LEVEL_OUTER2_TES,
3064 		CASETYPE_TESS_LEVEL_OUTER3_TES,
3065 
3066 		CASETYPE_LAST
3067 	};
3068 
PerPatchDataCase(Context & context,const char * name,const char * description,CaseType caseType,const char * referenceImagePath)3069 	PerPatchDataCase (Context& context, const char* name, const char* description, CaseType caseType, const char* referenceImagePath)
3070 		: TestCase				(context, name, description)
3071 		, m_caseType			(caseType)
3072 		, m_referenceImagePath	(caseTypeUsesRefImageFromFile(caseType) ? referenceImagePath : "")
3073 	{
3074 		DE_ASSERT(caseTypeUsesRefImageFromFile(caseType) == (referenceImagePath != DE_NULL));
3075 	}
3076 
3077 	void							init							(void);
3078 	void							deinit							(void);
3079 	IterateResult					iterate							(void);
3080 
3081 	static const char*				getCaseTypeName					(CaseType);
3082 	static const char*				getCaseTypeDescription			(CaseType);
3083 	static bool						caseTypeUsesRefImageFromFile	(CaseType);
3084 
3085 private:
3086 	static const int				RENDER_SIZE = 256;
3087 	static const int				INPUT_PATCH_SIZE;
3088 	static const int				OUTPUT_PATCH_SIZE;
3089 
3090 	const CaseType					m_caseType;
3091 	const string					m_referenceImagePath;
3092 
3093 	SharedPtr<const ShaderProgram>	m_program;
3094 };
3095 
3096 const int PerPatchDataCase::INPUT_PATCH_SIZE	= 10;
3097 const int PerPatchDataCase::OUTPUT_PATCH_SIZE	= 5;
3098 
getCaseTypeName(CaseType type)3099 const char* PerPatchDataCase::getCaseTypeName (CaseType type)
3100 {
3101 	switch (type)
3102 	{
3103 		case CASETYPE_PRIMITIVE_ID_TCS:			return "primitive_id_tcs";
3104 		case CASETYPE_PRIMITIVE_ID_TES:			return "primitive_id_tes";
3105 		case CASETYPE_PATCH_VERTICES_IN_TCS:	return "patch_vertices_in_tcs";
3106 		case CASETYPE_PATCH_VERTICES_IN_TES:	return "patch_vertices_in_tes";
3107 		case CASETYPE_TESS_LEVEL_INNER0_TES:	return "tess_level_inner_0_tes";
3108 		case CASETYPE_TESS_LEVEL_INNER1_TES:	return "tess_level_inner_1_tes";
3109 		case CASETYPE_TESS_LEVEL_OUTER0_TES:	return "tess_level_outer_0_tes";
3110 		case CASETYPE_TESS_LEVEL_OUTER1_TES:	return "tess_level_outer_1_tes";
3111 		case CASETYPE_TESS_LEVEL_OUTER2_TES:	return "tess_level_outer_2_tes";
3112 		case CASETYPE_TESS_LEVEL_OUTER3_TES:	return "tess_level_outer_3_tes";
3113 		default:
3114 			DE_ASSERT(false);
3115 			return DE_NULL;
3116 	}
3117 }
3118 
getCaseTypeDescription(CaseType type)3119 const char* PerPatchDataCase::getCaseTypeDescription (CaseType type)
3120 {
3121 	switch (type)
3122 	{
3123 		case CASETYPE_PRIMITIVE_ID_TCS:			return "Read gl_PrimitiveID in TCS and pass it as patch output to TES";
3124 		case CASETYPE_PRIMITIVE_ID_TES:			return "Read gl_PrimitiveID in TES";
3125 		case CASETYPE_PATCH_VERTICES_IN_TCS:	return "Read gl_PatchVerticesIn in TCS and pass it as patch output to TES";
3126 		case CASETYPE_PATCH_VERTICES_IN_TES:	return "Read gl_PatchVerticesIn in TES";
3127 		case CASETYPE_TESS_LEVEL_INNER0_TES:	return "Read gl_TessLevelInner[0] in TES";
3128 		case CASETYPE_TESS_LEVEL_INNER1_TES:	return "Read gl_TessLevelInner[1] in TES";
3129 		case CASETYPE_TESS_LEVEL_OUTER0_TES:	return "Read gl_TessLevelOuter[0] in TES";
3130 		case CASETYPE_TESS_LEVEL_OUTER1_TES:	return "Read gl_TessLevelOuter[1] in TES";
3131 		case CASETYPE_TESS_LEVEL_OUTER2_TES:	return "Read gl_TessLevelOuter[2] in TES";
3132 		case CASETYPE_TESS_LEVEL_OUTER3_TES:	return "Read gl_TessLevelOuter[3] in TES";
3133 		default:
3134 			DE_ASSERT(false);
3135 			return DE_NULL;
3136 	}
3137 }
3138 
caseTypeUsesRefImageFromFile(CaseType type)3139 bool PerPatchDataCase::caseTypeUsesRefImageFromFile (CaseType type)
3140 {
3141 	switch (type)
3142 	{
3143 		case CASETYPE_PRIMITIVE_ID_TCS:
3144 		case CASETYPE_PRIMITIVE_ID_TES:
3145 			return true;
3146 
3147 		default:
3148 			return false;
3149 	}
3150 }
3151 
init(void)3152 void PerPatchDataCase::init (void)
3153 {
3154 	checkTessellationSupport(m_context);
3155 	checkRenderTargetSize(m_context.getRenderTarget(), RENDER_SIZE);
3156 
3157 	DE_ASSERT(OUTPUT_PATCH_SIZE < INPUT_PATCH_SIZE);
3158 
3159 	const string inSizeStr		= de::toString(INPUT_PATCH_SIZE);
3160 	const string outSizeStr		= de::toString(OUTPUT_PATCH_SIZE);
3161 
3162 	std::string vertexShaderTemplate			("${GLSL_VERSION_DECL}\n"
3163 													 "\n"
3164 													 "in highp float in_v_attr;\n"
3165 													 "\n"
3166 													 "out highp float in_tc_attr;\n"
3167 													 "\n"
3168 													 "void main (void)\n"
3169 													 "{\n"
3170 													 "	in_tc_attr = in_v_attr;\n"
3171 												 "}\n");
3172 	std::string tessellationControlTemplate		("${GLSL_VERSION_DECL}\n"
3173 												 "${TESSELLATION_SHADER_REQUIRE}\n"
3174 													 "\n"
3175 													 "layout (vertices = " + outSizeStr + ") out;\n"
3176 													 "\n"
3177 													 "in highp float in_tc_attr[];\n"
3178 													 "\n"
3179 													 "out highp float in_te_attr[];\n"
3180 													 + (m_caseType == CASETYPE_PRIMITIVE_ID_TCS			? "patch out mediump int in_te_primitiveIDFromTCS;\n"
3181 													  : m_caseType == CASETYPE_PATCH_VERTICES_IN_TCS	? "patch out mediump int in_te_patchVerticesInFromTCS;\n"
3182 													  : "") +
3183 													 "\n"
3184 													 "void main (void)\n"
3185 													 "{\n"
3186 													 "	in_te_attr[gl_InvocationID] = in_tc_attr[gl_InvocationID];\n"
3187 													 + (m_caseType == CASETYPE_PRIMITIVE_ID_TCS			? "\tin_te_primitiveIDFromTCS = gl_PrimitiveID;\n"
3188 													  : m_caseType == CASETYPE_PATCH_VERTICES_IN_TCS	? "\tin_te_patchVerticesInFromTCS = gl_PatchVerticesIn;\n"
3189 													  : "") +
3190 													 "\n"
3191 													 "	gl_TessLevelInner[0] = 9.0;\n"
3192 													 "	gl_TessLevelInner[1] = 8.0;\n"
3193 													 "\n"
3194 													"	gl_TessLevelOuter[0] = 7.0;\n"
3195 													"	gl_TessLevelOuter[1] = 6.0;\n"
3196 													"	gl_TessLevelOuter[2] = 5.0;\n"
3197 													"	gl_TessLevelOuter[3] = 4.0;\n"
3198 												 "}\n");
3199 	std::string tessellationEvaluationTemplate	("${GLSL_VERSION_DECL}\n"
3200 												 "${TESSELLATION_SHADER_REQUIRE}\n"
3201 													 "\n"
3202 													 + getTessellationEvaluationInLayoutString(TESSPRIMITIVETYPE_QUADS) +
3203 													 "\n"
3204 													 "in highp float in_te_attr[];\n"
3205 													 + (m_caseType == CASETYPE_PRIMITIVE_ID_TCS			? "patch in mediump int in_te_primitiveIDFromTCS;\n"
3206 													  : m_caseType == CASETYPE_PATCH_VERTICES_IN_TCS	? "patch in mediump int in_te_patchVerticesInFromTCS;\n"
3207 													  : string()) +
3208 													 "\n"
3209 													 "out mediump vec4 in_f_color;\n"
3210 													 "\n"
3211 													 "uniform highp float u_xScale;\n"
3212 													 "\n"
3213 													 "void main (void)\n"
3214 													 "{\n"
3215 													 "	highp float x = (gl_TessCoord.x*u_xScale + in_te_attr[0]) * 2.0 - 1.0;\n"
3216 													 "	highp float y = gl_TessCoord.y*2.0 - 1.0;\n"
3217 													 "	gl_Position = vec4(x, y, 0.0, 1.0);\n"
3218 													 + (m_caseType == CASETYPE_PRIMITIVE_ID_TCS			? "\tbool ok = in_te_primitiveIDFromTCS == 3;\n"
3219 													  : m_caseType == CASETYPE_PRIMITIVE_ID_TES			? "\tbool ok = gl_PrimitiveID == 3;\n"
3220 													  : m_caseType == CASETYPE_PATCH_VERTICES_IN_TCS	? "\tbool ok = in_te_patchVerticesInFromTCS == " + inSizeStr + ";\n"
3221 													  : m_caseType == CASETYPE_PATCH_VERTICES_IN_TES	? "\tbool ok = gl_PatchVerticesIn == " + outSizeStr + ";\n"
3222 													  : m_caseType == CASETYPE_TESS_LEVEL_INNER0_TES	? "\tbool ok = abs(gl_TessLevelInner[0] - 9.0) < 0.1f;\n"
3223 													  : m_caseType == CASETYPE_TESS_LEVEL_INNER1_TES	? "\tbool ok = abs(gl_TessLevelInner[1] - 8.0) < 0.1f;\n"
3224 													  : m_caseType == CASETYPE_TESS_LEVEL_OUTER0_TES	? "\tbool ok = abs(gl_TessLevelOuter[0] - 7.0) < 0.1f;\n"
3225 													  : m_caseType == CASETYPE_TESS_LEVEL_OUTER1_TES	? "\tbool ok = abs(gl_TessLevelOuter[1] - 6.0) < 0.1f;\n"
3226 													  : m_caseType == CASETYPE_TESS_LEVEL_OUTER2_TES	? "\tbool ok = abs(gl_TessLevelOuter[2] - 5.0) < 0.1f;\n"
3227 													  : m_caseType == CASETYPE_TESS_LEVEL_OUTER3_TES	? "\tbool ok = abs(gl_TessLevelOuter[3] - 4.0) < 0.1f;\n"
3228 													  : DE_NULL) +
3229 													  "	in_f_color = ok ? vec4(1.0) : vec4(vec3(0.0), 1.0);\n"
3230 												 "}\n");
3231 	std::string fragmentShaderTemplate			("${GLSL_VERSION_DECL}\n"
3232 													 "\n"
3233 													 "layout (location = 0) out mediump vec4 o_color;\n"
3234 													 "\n"
3235 													 "in mediump vec4 in_f_color;\n"
3236 													 "\n"
3237 													 "void main (void)\n"
3238 													 "{\n"
3239 													 "	o_color = in_f_color;\n"
3240 												 "}\n");
3241 
3242 	m_program = SharedPtr<const ShaderProgram>(new ShaderProgram(m_context.getRenderContext(), glu::ProgramSources()
3243 			<< glu::VertexSource					(specializeShader(m_context, vertexShaderTemplate.c_str()))
3244 			<< glu::TessellationControlSource		(specializeShader(m_context, tessellationControlTemplate.c_str()))
3245 			<< glu::TessellationEvaluationSource	(specializeShader(m_context, tessellationEvaluationTemplate.c_str()))
3246 			<< glu::FragmentSource					(specializeShader(m_context, fragmentShaderTemplate.c_str()))));
3247 
3248 	m_testCtx.getLog() << *m_program;
3249 	if (!m_program->isOk())
3250 		TCU_FAIL("Program compilation failed");
3251 }
3252 
deinit(void)3253 void PerPatchDataCase::deinit (void)
3254 {
3255 	m_program.clear();
3256 }
3257 
iterate(void)3258 PerPatchDataCase::IterateResult PerPatchDataCase::iterate (void)
3259 {
3260 	TestLog&					log						= m_testCtx.getLog();
3261 	const RenderContext&		renderCtx				= m_context.getRenderContext();
3262 	const RandomViewport		viewport				(renderCtx.getRenderTarget(), RENDER_SIZE, RENDER_SIZE, deStringHash(getName()));
3263 	const deUint32				programGL				= m_program->getProgram();
3264 	const glw::Functions&		gl						= renderCtx.getFunctions();
3265 
3266 	setViewport(gl, viewport);
3267 	gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
3268 	gl.useProgram(programGL);
3269 
3270 	log << TestLog::Message << "Note: input patch size is " << INPUT_PATCH_SIZE << ", output patch size is " << OUTPUT_PATCH_SIZE << TestLog::EndMessage;
3271 
3272 	{
3273 		const int numPrimitives = m_caseType == CASETYPE_PRIMITIVE_ID_TCS || m_caseType == CASETYPE_PRIMITIVE_ID_TES ? 8 : 1;
3274 
3275 		vector<float> attributeData;
3276 		attributeData.reserve(numPrimitives*INPUT_PATCH_SIZE);
3277 
3278 		for (int i = 0; i < numPrimitives; i++)
3279 		{
3280 			attributeData.push_back((float)i / (float)numPrimitives);
3281 			for (int j = 0; j < INPUT_PATCH_SIZE-1; j++)
3282 				attributeData.push_back(0.0f);
3283 		}
3284 
3285 		gl.patchParameteri(GL_PATCH_VERTICES, INPUT_PATCH_SIZE);
3286 		gl.clear(GL_COLOR_BUFFER_BIT);
3287 
3288 		gl.uniform1f(gl.getUniformLocation(programGL, "u_xScale"), 1.0f / (float)numPrimitives);
3289 
3290 		const glu::VertexArrayBinding attrBindings[] =
3291 		{
3292 			glu::va::Float("in_v_attr", 1, (int)attributeData.size(), 0, &attributeData[0])
3293 		};
3294 
3295 		glu::draw(m_context.getRenderContext(), programGL, DE_LENGTH_OF_ARRAY(attrBindings), &attrBindings[0],
3296 			glu::pr::Patches(numPrimitives*INPUT_PATCH_SIZE));
3297 		GLU_EXPECT_NO_ERROR(gl.getError(), "Draw failed");
3298 	}
3299 
3300 	{
3301 		const tcu::Surface rendered = getPixels(renderCtx, viewport);
3302 
3303 		if (m_caseType == CASETYPE_PRIMITIVE_ID_TCS || m_caseType == CASETYPE_PRIMITIVE_ID_TES)
3304 		{
3305 			DE_ASSERT(caseTypeUsesRefImageFromFile(m_caseType));
3306 
3307 			const tcu::TextureLevel		reference	= getPNG(m_testCtx.getArchive(), m_referenceImagePath);
3308 			const bool					success		= tcu::fuzzyCompare(log, "ImageComparison", "Image Comparison", reference.getAccess(), rendered.getAccess(), 0.02f, tcu::COMPARE_LOG_RESULT);
3309 
3310 			m_testCtx.setTestResult(success ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, success ? "Pass" : "Image comparison failed");
3311 			return STOP;
3312 		}
3313 		else
3314 		{
3315 			DE_ASSERT(!caseTypeUsesRefImageFromFile(m_caseType));
3316 
3317 			log << TestLog::Image("RenderedImage", "Rendered Image", rendered);
3318 
3319 			for (int y = 0; y < rendered.getHeight();	y++)
3320 			for (int x = 0; x < rendered.getWidth();	x++)
3321 			{
3322 				if (rendered.getPixel(x, y) != tcu::RGBA::white())
3323 				{
3324 					log << TestLog::Message << "Failure: expected all white pixels" << TestLog::EndMessage;
3325 					m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image verification failed");
3326 					return STOP;
3327 				}
3328 			}
3329 
3330 			m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
3331 			return STOP;
3332 		}
3333 	}
3334 }
3335 
3336 // Basic barrier() usage in TCS.
3337 class BarrierCase : public TestCase
3338 {
3339 public:
BarrierCase(Context & context,const char * name,const char * description,const char * referenceImagePath)3340 	BarrierCase (Context& context, const char* name, const char* description, const char* referenceImagePath)
3341 		: TestCase				(context, name, description)
3342 		, m_referenceImagePath	(referenceImagePath)
3343 	{
3344 	}
3345 
3346 	void							init		(void);
3347 	void							deinit		(void);
3348 	IterateResult					iterate		(void);
3349 
3350 private:
3351 	static const int				RENDER_SIZE = 256;
3352 	static const int				NUM_VERTICES;
3353 
3354 	const string					m_referenceImagePath;
3355 
3356 	SharedPtr<const ShaderProgram>	m_program;
3357 };
3358 
3359 const int BarrierCase::NUM_VERTICES = 32;
3360 
init(void)3361 void BarrierCase::init (void)
3362 {
3363 	checkTessellationSupport(m_context);
3364 	checkRenderTargetSize(m_context.getRenderTarget(), RENDER_SIZE);
3365 
3366 	const string numVertsStr = de::toString(NUM_VERTICES);
3367 
3368 	std::string vertexShaderTemplate			("${GLSL_VERSION_DECL}\n"
3369 													 "\n"
3370 													 "in highp float in_v_attr;\n"
3371 													 "\n"
3372 													 "out highp float in_tc_attr;\n"
3373 													 "\n"
3374 													 "void main (void)\n"
3375 													 "{\n"
3376 													 "	in_tc_attr = in_v_attr;\n"
3377 												 "}\n");
3378 	std::string tessellationControlTemplate		("${GLSL_VERSION_DECL}\n"
3379 												 "${TESSELLATION_SHADER_REQUIRE}\n"
3380 													 "\n"
3381 													 "layout (vertices = " + numVertsStr + ") out;\n"
3382 													 "\n"
3383 													 "in highp float in_tc_attr[];\n"
3384 													 "\n"
3385 													 "out highp float in_te_attr[];\n"
3386 													 "patch out highp float in_te_patchAttr;\n"
3387 													 "\n"
3388 													 "void main (void)\n"
3389 													 "{\n"
3390 													 "	in_te_attr[gl_InvocationID] = in_tc_attr[gl_InvocationID];\n"
3391 													 "	in_te_patchAttr = 0.0f;\n"
3392 													 "	barrier();\n"
3393 													 "	if (gl_InvocationID == 5)\n"
3394 													 "		in_te_patchAttr = float(gl_InvocationID)*0.1;\n"
3395 													 "	barrier();\n"
3396 													 "	highp float temp = in_te_patchAttr + in_te_attr[gl_InvocationID];\n"
3397 													 "	barrier();\n"
3398 													 "	if (gl_InvocationID == " + numVertsStr + "-1)\n"
3399 													 "		in_te_patchAttr = float(gl_InvocationID);\n"
3400 													 "	barrier();\n"
3401 													 "	in_te_attr[gl_InvocationID] = temp;\n"
3402 													 "	barrier();\n"
3403 													 "	temp = temp + in_te_attr[(gl_InvocationID+1) % " + numVertsStr + "];\n"
3404 													 "	barrier();\n"
3405 													 "	in_te_attr[gl_InvocationID] = 0.25*temp;\n"
3406 													 "\n"
3407 													 "	gl_TessLevelInner[0] = 32.0;\n"
3408 													 "	gl_TessLevelInner[1] = 32.0;\n"
3409 													 "\n"
3410 													 "	gl_TessLevelOuter[0] = 32.0;\n"
3411 													 "	gl_TessLevelOuter[1] = 32.0;\n"
3412 													 "	gl_TessLevelOuter[2] = 32.0;\n"
3413 													 "	gl_TessLevelOuter[3] = 32.0;\n"
3414 												 "}\n");
3415 	std::string tessellationEvaluationTemplate	("${GLSL_VERSION_DECL}\n"
3416 												 "${TESSELLATION_SHADER_REQUIRE}\n"
3417 													 "\n"
3418 													 + getTessellationEvaluationInLayoutString(TESSPRIMITIVETYPE_QUADS) +
3419 													 "\n"
3420 													 "in highp float in_te_attr[];\n"
3421 													 "patch in highp float in_te_patchAttr;\n"
3422 													 "\n"
3423 													 "out highp float in_f_blue;\n"
3424 													 "\n"
3425 													 "void main (void)\n"
3426 													 "{\n"
3427 													 "	highp float x = gl_TessCoord.x*2.0 - 1.0;\n"
3428 													 "	highp float y = gl_TessCoord.y - in_te_attr[int(round(gl_TessCoord.x*float(" + numVertsStr + "-1)))];\n"
3429 													 "	gl_Position = vec4(x, y, 0.0, 1.0);\n"
3430 													 "	in_f_blue = abs(in_te_patchAttr - float(" + numVertsStr + "-1));\n"
3431 												 "}\n");
3432 	std::string fragmentShaderTemplate			("${GLSL_VERSION_DECL}\n"
3433 													 "\n"
3434 													 "layout (location = 0) out mediump vec4 o_color;\n"
3435 													 "\n"
3436 													 "in highp float in_f_blue;\n"
3437 													 "\n"
3438 													 "void main (void)\n"
3439 													 "{\n"
3440 													 "	o_color = vec4(1.0, 0.0, in_f_blue, 1.0);\n"
3441 												 "}\n");
3442 
3443 	m_program = SharedPtr<const ShaderProgram>(new ShaderProgram(m_context.getRenderContext(), glu::ProgramSources()
3444 			<< glu::VertexSource					(specializeShader(m_context, vertexShaderTemplate.c_str()))
3445 			<< glu::TessellationControlSource		(specializeShader(m_context, tessellationControlTemplate.c_str()))
3446 			<< glu::TessellationEvaluationSource	(specializeShader(m_context, tessellationEvaluationTemplate.c_str()))
3447 			<< glu::FragmentSource					(specializeShader(m_context, fragmentShaderTemplate.c_str()))));
3448 
3449 	m_testCtx.getLog() << *m_program;
3450 	if (!m_program->isOk())
3451 		TCU_FAIL("Program compilation failed");
3452 }
3453 
deinit(void)3454 void BarrierCase::deinit (void)
3455 {
3456 	m_program.clear();
3457 }
3458 
iterate(void)3459 BarrierCase::IterateResult BarrierCase::iterate (void)
3460 {
3461 	TestLog&					log						= m_testCtx.getLog();
3462 	const RenderContext&		renderCtx				= m_context.getRenderContext();
3463 	const RandomViewport		viewport				(renderCtx.getRenderTarget(), RENDER_SIZE, RENDER_SIZE, deStringHash(getName()));
3464 	const deUint32				programGL				= m_program->getProgram();
3465 	const glw::Functions&		gl						= renderCtx.getFunctions();
3466 
3467 	setViewport(gl, viewport);
3468 	gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
3469 	gl.useProgram(programGL);
3470 
3471 	{
3472 		vector<float> attributeData(NUM_VERTICES);
3473 
3474 		for (int i = 0; i < NUM_VERTICES; i++)
3475 			attributeData[i] = (float)i / (float)(NUM_VERTICES-1);
3476 
3477 		gl.patchParameteri(GL_PATCH_VERTICES, NUM_VERTICES);
3478 		gl.clear(GL_COLOR_BUFFER_BIT);
3479 
3480 		const glu::VertexArrayBinding attrBindings[] =
3481 		{
3482 			glu::va::Float("in_v_attr", 1, (int)attributeData.size(), 0, &attributeData[0])
3483 		};
3484 
3485 		glu::draw(m_context.getRenderContext(), programGL, DE_LENGTH_OF_ARRAY(attrBindings), &attrBindings[0],
3486 			glu::pr::Patches(NUM_VERTICES));
3487 		GLU_EXPECT_NO_ERROR(gl.getError(), "Draw failed");
3488 	}
3489 
3490 	{
3491 		const tcu::Surface			rendered	= getPixels(renderCtx, viewport);
3492 		const tcu::TextureLevel		reference	= getPNG(m_testCtx.getArchive(), m_referenceImagePath);
3493 		const bool					success		= tcu::fuzzyCompare(log, "ImageComparison", "Image Comparison", reference.getAccess(), rendered.getAccess(), 0.02f, tcu::COMPARE_LOG_RESULT);
3494 
3495 		m_testCtx.setTestResult(success ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, success ? "Pass" : "Image comparison failed");
3496 		return STOP;
3497 	}
3498 }
3499 
3500 /*--------------------------------------------------------------------*//*!
3501  * \brief Base class for testing invariance of entire primitive set
3502  *
3503  * Draws two patches with identical tessellation levels and compares the
3504  * results. Repeats the same with other programs that are only different
3505  * in irrelevant ways; compares the results between these two programs.
3506  * Also potentially compares to results produced by different tessellation
3507  * levels (see e.g. invariance rule #6).
3508  * Furthermore, repeats the above with multiple different tessellation
3509  * value sets.
3510  *
3511  * The manner of primitive set comparison is defined by subclass. E.g.
3512  * case for invariance rule #1 tests that same vertices come out, in same
3513  * order; rule #5 only requires that the same triangles are output, but
3514  * not necessarily in the same order.
3515  *//*--------------------------------------------------------------------*/
3516 class PrimitiveSetInvarianceCase : public TestCase
3517 {
3518 public:
3519 	enum WindingUsage
3520 	{
3521 		WINDINGUSAGE_CCW = 0,
3522 		WINDINGUSAGE_CW,
3523 		WINDINGUSAGE_VARY,
3524 
3525 		WINDINGUSAGE_LAST
3526 	};
3527 
PrimitiveSetInvarianceCase(Context & context,const char * name,const char * description,TessPrimitiveType primType,SpacingMode spacing,bool usePointMode,WindingUsage windingUsage)3528 	PrimitiveSetInvarianceCase (Context& context, const char* name, const char* description, TessPrimitiveType primType, SpacingMode spacing, bool usePointMode, WindingUsage windingUsage)
3529 		: TestCase			(context, name, description)
3530 		, m_primitiveType	(primType)
3531 		, m_spacing			(spacing)
3532 		, m_usePointMode	(usePointMode)
3533 		, m_windingUsage	(windingUsage)
3534 	{
3535 	}
3536 
3537 	void									init				(void);
3538 	void									deinit				(void);
3539 	IterateResult							iterate				(void);
3540 
3541 protected:
3542 	struct TessLevels
3543 	{
3544 		float inner[2];
3545 		float outer[4];
descriptiondeqp::gles31::Functional::__anon4a9088cf0211::PrimitiveSetInvarianceCase::TessLevels3546 		string description (void) const { return tessellationLevelsString(&inner[0], &outer[0]); }
3547 	};
3548 	struct LevelCase
3549 	{
3550 		vector<TessLevels>	levels;
3551 		int					mem; //!< Subclass-defined arbitrary piece of data, for type of the levelcase, if needed. Passed to compare().
LevelCasedeqp::gles31::Functional::__anon4a9088cf0211::PrimitiveSetInvarianceCase::LevelCase3552 		LevelCase (const TessLevels& lev) : levels(vector<TessLevels>(1, lev)), mem(0) {}
LevelCasedeqp::gles31::Functional::__anon4a9088cf0211::PrimitiveSetInvarianceCase::LevelCase3553 		LevelCase (void) : mem(0) {}
3554 	};
3555 
3556 	virtual vector<LevelCase>	genTessLevelCases	(void) const;
3557 	virtual bool				compare				(const vector<Vec3>& coordsA, const vector<Vec3>& coordsB, int levelCaseMem) const = 0;
3558 
3559 	const TessPrimitiveType		m_primitiveType;
3560 
3561 private:
3562 	struct Program
3563 	{
3564 		Winding							winding;
3565 		SharedPtr<const ShaderProgram>	program;
3566 
Programdeqp::gles31::Functional::__anon4a9088cf0211::PrimitiveSetInvarianceCase::Program3567 				Program			(Winding w, const SharedPtr<const ShaderProgram>& prog) : winding(w), program(prog) {}
3568 
descriptiondeqp::gles31::Functional::__anon4a9088cf0211::PrimitiveSetInvarianceCase::Program3569 		string	description		(void) const { return string() + "winding mode " + getWindingShaderName(winding); };
3570 	};
3571 
3572 	static const int			RENDER_SIZE = 16;
3573 
3574 	const SpacingMode			m_spacing;
3575 	const bool					m_usePointMode;
3576 	const WindingUsage			m_windingUsage;
3577 
3578 	vector<Program>				m_programs;
3579 };
3580 
genTessLevelCases(void) const3581 vector<PrimitiveSetInvarianceCase::LevelCase> PrimitiveSetInvarianceCase::genTessLevelCases (void) const
3582 {
3583 	static const TessLevels basicTessLevelCases[] =
3584 	{
3585 		{ { 1.0f,	1.0f	},	{ 1.0f,		1.0f,	1.0f,	1.0f	} },
3586 		{ { 63.0f,	24.0f	},	{ 15.0f,	42.0f,	10.0f,	12.0f	} },
3587 		{ { 3.0f,	2.0f	},	{ 6.0f,		8.0f,	7.0f,	9.0f	} },
3588 		{ { 4.0f,	6.0f	},	{ 2.0f,		3.0f,	1.0f,	4.0f	} },
3589 		{ { 2.0f,	2.0f	},	{ 6.0f,		8.0f,	7.0f,	9.0f	} },
3590 		{ { 5.0f,	6.0f	},	{ 1.0f,		1.0f,	1.0f,	1.0f	} },
3591 		{ { 1.0f,	6.0f	},	{ 2.0f,		3.0f,	1.0f,	4.0f	} },
3592 		{ { 5.0f,	1.0f	},	{ 2.0f,		3.0f,	1.0f,	4.0f	} },
3593 		{ { 5.2f,	1.6f	},	{ 2.9f,		3.4f,	1.5f,	4.1f	} }
3594 	};
3595 
3596 	vector<LevelCase> result;
3597 	for (int i = 0; i < DE_LENGTH_OF_ARRAY(basicTessLevelCases); i++)
3598 		result.push_back(LevelCase(basicTessLevelCases[i]));
3599 
3600 	{
3601 		de::Random rnd(123);
3602 		for (int i = 0; i < 10; i++)
3603 		{
3604 			TessLevels levels;
3605 			for (int j = 0; j < DE_LENGTH_OF_ARRAY(levels.inner); j++)
3606 				levels.inner[j] = rnd.getFloat(1.0f, 16.0f);
3607 			for (int j = 0; j < DE_LENGTH_OF_ARRAY(levels.outer); j++)
3608 				levels.outer[j] = rnd.getFloat(1.0f, 16.0f);
3609 			result.push_back(LevelCase(levels));
3610 		}
3611 	}
3612 
3613 	return result;
3614 }
3615 
init(void)3616 void PrimitiveSetInvarianceCase::init (void)
3617 {
3618 	const int			numDifferentConstantExprCases = 2;
3619 	vector<Winding>		windings;
3620 	switch (m_windingUsage)
3621 	{
3622 		case WINDINGUSAGE_CCW:		windings.push_back(WINDING_CCW); break;
3623 		case WINDINGUSAGE_CW:		windings.push_back(WINDING_CW); break;
3624 		case WINDINGUSAGE_VARY:		windings.push_back(WINDING_CCW);
3625 									windings.push_back(WINDING_CW); break;
3626 		default: DE_ASSERT(false);
3627 	}
3628 
3629 	checkTessellationSupport(m_context);
3630 	checkRenderTargetSize(m_context.getRenderTarget(), RENDER_SIZE);
3631 
3632 	for (int constantExprCaseNdx = 0; constantExprCaseNdx < numDifferentConstantExprCases; constantExprCaseNdx++)
3633 	{
3634 		for (int windingCaseNdx = 0; windingCaseNdx < (int)windings.size(); windingCaseNdx++)
3635 		{
3636 			const string	floatLit01 = de::floatToString(10.0f / (float)(constantExprCaseNdx + 10), 2);
3637 			const int		programNdx = (int)m_programs.size();
3638 
3639 			std::string vertexShaderTemplate			("${GLSL_VERSION_DECL}\n"
3640 															 "\n"
3641 															 "in highp float in_v_attr;\n"
3642 															 "out highp float in_tc_attr;\n"
3643 															 "\n"
3644 															 "void main (void)\n"
3645 															 "{\n"
3646 															 "	in_tc_attr = in_v_attr;\n"
3647 														 "}\n");
3648 			std::string tessellationControlTemplate		("${GLSL_VERSION_DECL}\n"
3649 														 "${TESSELLATION_SHADER_REQUIRE}\n"
3650 															 "\n"
3651 															 "layout (vertices = " + de::toString(constantExprCaseNdx+1) + ") out;\n"
3652 															 "\n"
3653 															 "in highp float in_tc_attr[];\n"
3654 															 "\n"
3655 															 "patch out highp float in_te_positionOffset;\n"
3656 															 "\n"
3657 															 "void main (void)\n"
3658 															 "{\n"
3659 															 "	in_te_positionOffset = in_tc_attr[6];\n"
3660 															 "\n"
3661 															 "	gl_TessLevelInner[0] = in_tc_attr[0];\n"
3662 															 "	gl_TessLevelInner[1] = in_tc_attr[1];\n"
3663 															 "\n"
3664 															 "	gl_TessLevelOuter[0] = in_tc_attr[2];\n"
3665 															 "	gl_TessLevelOuter[1] = in_tc_attr[3];\n"
3666 															 "	gl_TessLevelOuter[2] = in_tc_attr[4];\n"
3667 															 "	gl_TessLevelOuter[3] = in_tc_attr[5];\n"
3668 														 "}\n");
3669 			std::string tessellationEvaluationTemplate	("${GLSL_VERSION_DECL}\n"
3670 														 "${TESSELLATION_SHADER_REQUIRE}\n"
3671 															 "\n"
3672 															 + getTessellationEvaluationInLayoutString(m_primitiveType, m_spacing, windings[windingCaseNdx], m_usePointMode) +
3673 															 "\n"
3674 															 "patch in highp float in_te_positionOffset;\n"
3675 															 "\n"
3676 															 "out highp vec4 in_f_color;\n"
3677 															 "invariant out highp vec3 out_te_tessCoord;\n"
3678 															 "\n"
3679 															 "void main (void)\n"
3680 															 "{\n"
3681 															 "	gl_Position = vec4(gl_TessCoord.xy*" + floatLit01 + " - in_te_positionOffset + float(gl_PrimitiveID)*0.1, 0.0, 1.0);\n"
3682 															 "	in_f_color = vec4(" + floatLit01 + ");\n"
3683 															 "	out_te_tessCoord = gl_TessCoord;\n"
3684 														 "}\n");
3685 			std::string fragmentShaderTemplate			("${GLSL_VERSION_DECL}\n"
3686 															 "\n"
3687 															 "layout (location = 0) out mediump vec4 o_color;\n"
3688 															 "\n"
3689 															 "in highp vec4 in_f_color;\n"
3690 															 "\n"
3691 															 "void main (void)\n"
3692 															 "{\n"
3693 															 "	o_color = in_f_color;\n"
3694 														 "}\n");
3695 
3696 			m_programs.push_back(Program(windings[windingCaseNdx],
3697 										 SharedPtr<const ShaderProgram>(new ShaderProgram(m_context.getRenderContext(), glu::ProgramSources()
3698 					<< glu::VertexSource					(specializeShader(m_context, vertexShaderTemplate.c_str()))
3699 					<< glu::TessellationControlSource		(specializeShader(m_context, tessellationControlTemplate.c_str()))
3700 					<< glu::TessellationEvaluationSource	(specializeShader(m_context, tessellationEvaluationTemplate.c_str()))
3701 					<< glu::FragmentSource					(specializeShader(m_context, fragmentShaderTemplate.c_str()))
3702 					<< glu::TransformFeedbackVarying		("out_te_tessCoord")
3703 					<< glu::TransformFeedbackMode			(GL_INTERLEAVED_ATTRIBS)))));
3704 
3705 			{
3706 				const tcu::ScopedLogSection section(m_testCtx.getLog(), "Program" + de::toString(programNdx), "Program " + de::toString(programNdx));
3707 
3708 				if (programNdx == 0 || !m_programs.back().program->isOk())
3709 					m_testCtx.getLog() << *m_programs.back().program;
3710 
3711 				if (!m_programs.back().program->isOk())
3712 					TCU_FAIL("Program compilation failed");
3713 
3714 				if (programNdx > 0)
3715 					m_testCtx.getLog() << TestLog::Message << "Note: program " << programNdx << " is similar to above, except some constants are different, and: " << m_programs.back().description() << TestLog::EndMessage;
3716 			}
3717 		}
3718 	}
3719 }
3720 
deinit(void)3721 void PrimitiveSetInvarianceCase::deinit (void)
3722 {
3723 	m_programs.clear();
3724 }
3725 
iterate(void)3726 PrimitiveSetInvarianceCase::IterateResult PrimitiveSetInvarianceCase::iterate (void)
3727 {
3728 	typedef TransformFeedbackHandler<Vec3> TFHandler;
3729 
3730 	TestLog&					log					= m_testCtx.getLog();
3731 	const RenderContext&		renderCtx			= m_context.getRenderContext();
3732 	const RandomViewport		viewport			(renderCtx.getRenderTarget(), RENDER_SIZE, RENDER_SIZE, deStringHash(getName()));
3733 	const glw::Functions&		gl					= renderCtx.getFunctions();
3734 	const vector<LevelCase>		tessLevelCases		= genTessLevelCases();
3735 	vector<vector<int> >		primitiveCounts;
3736 	int							maxNumPrimitives	= -1;
3737 
3738 	for (int caseNdx = 0; caseNdx < (int)tessLevelCases.size(); caseNdx++)
3739 	{
3740 		primitiveCounts.push_back(vector<int>());
3741 		for (int i = 0; i < (int)tessLevelCases[caseNdx].levels.size(); i++)
3742 		{
3743 			const int primCount = referencePrimitiveCount(m_primitiveType, m_spacing, m_usePointMode,
3744 														  &tessLevelCases[caseNdx].levels[i].inner[0], &tessLevelCases[caseNdx].levels[i].outer[0]);
3745 			primitiveCounts.back().push_back(primCount);
3746 			maxNumPrimitives = de::max(maxNumPrimitives, primCount);
3747 		}
3748 	}
3749 
3750 	const deUint32				primitiveTypeGL		= outputPrimitiveTypeGL(m_primitiveType, m_usePointMode);
3751 	const TFHandler				transformFeedback	(m_context.getRenderContext(), 2*maxNumPrimitives*numVerticesPerPrimitive(primitiveTypeGL));
3752 
3753 	setViewport(gl, viewport);
3754 	gl.patchParameteri(GL_PATCH_VERTICES, 7);
3755 
3756 	for (int tessLevelCaseNdx = 0; tessLevelCaseNdx < (int)tessLevelCases.size(); tessLevelCaseNdx++)
3757 	{
3758 		const LevelCase&	levelCase = tessLevelCases[tessLevelCaseNdx];
3759 		vector<Vec3>		firstPrimVertices;
3760 
3761 		{
3762 			string tessLevelsStr;
3763 			for (int i = 0; i < (int)levelCase.levels.size(); i++)
3764 				tessLevelsStr += (levelCase.levels.size() > 1 ? "\n" : "") + levelCase.levels[i].description();
3765 			log << TestLog::Message << "Tessellation level sets: " << tessLevelsStr << TestLog::EndMessage;
3766 		}
3767 
3768 		for (int subTessLevelCaseNdx = 0; subTessLevelCaseNdx < (int)levelCase.levels.size(); subTessLevelCaseNdx++)
3769 		{
3770 			const TessLevels&				tessLevels		= levelCase.levels[subTessLevelCaseNdx];
3771 			const float						(&inner)[2]		= tessLevels.inner;
3772 			const float						(&outer)[4]		= tessLevels.outer;
3773 			const float						attribute[2*7]	= { inner[0], inner[1], outer[0], outer[1], outer[2], outer[3], 0.0f,
3774 																inner[0], inner[1], outer[0], outer[1], outer[2], outer[3], 0.5f };
3775 			const glu::VertexArrayBinding	bindings[]		= { glu::va::Float("in_v_attr", 1, DE_LENGTH_OF_ARRAY(attribute), 0, &attribute[0]) };
3776 
3777 			for (int programNdx = 0; programNdx < (int)m_programs.size(); programNdx++)
3778 			{
3779 				const deUint32				programGL	= m_programs[programNdx].program->getProgram();
3780 				gl.useProgram(programGL);
3781 				const TFHandler::Result		tfResult	= transformFeedback.renderAndGetPrimitives(programGL, primitiveTypeGL, DE_LENGTH_OF_ARRAY(bindings), &bindings[0], DE_LENGTH_OF_ARRAY(attribute));
3782 
3783 				if (tfResult.numPrimitives != 2*primitiveCounts[tessLevelCaseNdx][subTessLevelCaseNdx])
3784 				{
3785 					log << TestLog::Message << "Failure: GL reported GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN to be "
3786 											<< tfResult.numPrimitives << ", reference value is " << 2*primitiveCounts[tessLevelCaseNdx][subTessLevelCaseNdx]
3787 											<< TestLog::EndMessage;
3788 
3789 					m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid set of primitives");
3790 					return STOP;
3791 				}
3792 
3793 				{
3794 					const int			half			= (int)tfResult.varying.size()/2;
3795 					const vector<Vec3>	prim0Vertices	= vector<Vec3>(tfResult.varying.begin(), tfResult.varying.begin() + half);
3796 					const Vec3* const	prim1Vertices	= &tfResult.varying[half];
3797 
3798 					for (int vtxNdx = 0; vtxNdx < (int)prim0Vertices.size(); vtxNdx++)
3799 					{
3800 						if (prim0Vertices[vtxNdx] != prim1Vertices[vtxNdx])
3801 						{
3802 							log << TestLog::Message << "Failure: tessellation coordinate at index " << vtxNdx << " differs between two primitives drawn in one draw call" << TestLog::EndMessage
3803 								<< TestLog::Message << "Note: the coordinate is " << prim0Vertices[vtxNdx] << " for the first primitive and " << prim1Vertices[vtxNdx] << " for the second" << TestLog::EndMessage
3804 								<< TestLog::Message << "Note: tessellation levels for both primitives were: " << tessellationLevelsString(&inner[0], &outer[0]) << TestLog::EndMessage;
3805 							m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid set of primitives");
3806 							return STOP;
3807 						}
3808 					}
3809 
3810 					if (programNdx == 0 && subTessLevelCaseNdx == 0)
3811 						firstPrimVertices = prim0Vertices;
3812 					else
3813 					{
3814 						const bool compareOk = compare(firstPrimVertices, prim0Vertices, levelCase.mem);
3815 						if (!compareOk)
3816 						{
3817 							log << TestLog::Message << "Note: comparison of tessellation coordinates failed; comparison was made between following cases:\n"
3818 													<< "  - case A: program 0, tessellation levels: " << tessLevelCases[tessLevelCaseNdx].levels[0].description() << "\n"
3819 													<< "  - case B: program " << programNdx << ", tessellation levels: " << tessLevels.description() << TestLog::EndMessage;
3820 							m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid set of primitives");
3821 							return STOP;
3822 						}
3823 					}
3824 				}
3825 			}
3826 		}
3827 	}
3828 
3829 	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
3830 	return STOP;
3831 }
3832 
3833 /*--------------------------------------------------------------------*//*!
3834  * \brief Test invariance rule #1
3835  *
3836  * Test that the sequence of primitives input to the TES only depends on
3837  * the tessellation levels, tessellation mode, spacing mode, winding, and
3838  * point mode.
3839  *//*--------------------------------------------------------------------*/
3840 class InvariantPrimitiveSetCase : public PrimitiveSetInvarianceCase
3841 {
3842 public:
InvariantPrimitiveSetCase(Context & context,const char * name,const char * description,TessPrimitiveType primType,SpacingMode spacing,Winding winding,bool usePointMode)3843 	InvariantPrimitiveSetCase (Context& context, const char* name, const char* description, TessPrimitiveType primType, SpacingMode spacing, Winding winding, bool usePointMode)
3844 		: PrimitiveSetInvarianceCase(context, name, description, primType, spacing, usePointMode, winding == WINDING_CCW	? WINDINGUSAGE_CCW
3845 																								: winding == WINDING_CW		? WINDINGUSAGE_CW
3846 																								: WINDINGUSAGE_LAST)
3847 	{
3848 	}
3849 
3850 protected:
compare(const vector<Vec3> & coordsA,const vector<Vec3> & coordsB,int) const3851 	virtual bool compare (const vector<Vec3>& coordsA, const vector<Vec3>& coordsB, int) const
3852 	{
3853 		for (int vtxNdx = 0; vtxNdx < (int)coordsA.size(); vtxNdx++)
3854 		{
3855 			if (coordsA[vtxNdx] != coordsB[vtxNdx])
3856 			{
3857 				m_testCtx.getLog() << TestLog::Message << "Failure: tessellation coordinate at index " << vtxNdx << " differs between two programs" << TestLog::EndMessage
3858 								   << TestLog::Message << "Note: the coordinate is " << coordsA[vtxNdx] << " for the first program and " << coordsB[vtxNdx] << " for the other" << TestLog::EndMessage;
3859 				return false;
3860 			}
3861 		}
3862 		return true;
3863 	}
3864 };
3865 
3866 /*--------------------------------------------------------------------*//*!
3867  * \brief Test invariance rule #2
3868  *
3869  * Test that the set of vertices along an outer edge of a quad or triangle
3870  * only depends on that edge's tessellation level, and spacing.
3871  *
3872  * For each (outer) edge in the quad or triangle, draw multiple patches
3873  * with identical tessellation levels for that outer edge but with
3874  * different values for the other outer edges; compare, among the
3875  * primitives, the vertices generated for that outer edge. Repeat with
3876  * different programs, using different winding etc. settings. Compare
3877  * the edge's vertices between different programs.
3878  *//*--------------------------------------------------------------------*/
3879 class InvariantOuterEdgeCase : public TestCase
3880 {
3881 public:
InvariantOuterEdgeCase(Context & context,const char * name,const char * description,TessPrimitiveType primType,SpacingMode spacing)3882 	InvariantOuterEdgeCase (Context& context, const char* name, const char* description, TessPrimitiveType primType, SpacingMode spacing)
3883 		: TestCase			(context, name, description)
3884 		, m_primitiveType	(primType)
3885 		, m_spacing			(spacing)
3886 	{
3887 		DE_ASSERT(primType == TESSPRIMITIVETYPE_TRIANGLES || primType == TESSPRIMITIVETYPE_QUADS);
3888 	}
3889 
3890 	void						init		(void);
3891 	void						deinit		(void);
3892 	IterateResult				iterate		(void);
3893 
3894 private:
3895 	struct Program
3896 	{
3897 		Winding							winding;
3898 		bool							usePointMode;
3899 		SharedPtr<const ShaderProgram>	program;
3900 
Programdeqp::gles31::Functional::__anon4a9088cf0211::InvariantOuterEdgeCase::Program3901 				Program			(Winding w, bool point, const SharedPtr<const ShaderProgram>& prog) : winding(w), usePointMode(point), program(prog) {}
3902 
descriptiondeqp::gles31::Functional::__anon4a9088cf0211::InvariantOuterEdgeCase::Program3903 		string	description		(void) const { return string() + "winding mode " + getWindingShaderName(winding) + ", " + (usePointMode ? "" : "don't ") + "use point mode"; };
3904 	};
3905 
3906 	static vector<float>		generatePatchTessLevels (int numPatches, int constantOuterLevelIndex, float constantOuterLevel);
3907 
3908 	static const int			RENDER_SIZE = 16;
3909 
3910 	const TessPrimitiveType		m_primitiveType;
3911 	const SpacingMode			m_spacing;
3912 
3913 	vector<Program>				m_programs;
3914 };
3915 
generatePatchTessLevels(int numPatches,int constantOuterLevelIndex,float constantOuterLevel)3916 vector<float> InvariantOuterEdgeCase::generatePatchTessLevels (int numPatches, int constantOuterLevelIndex, float constantOuterLevel)
3917 {
3918 	de::Random rnd(123);
3919 	return generateRandomPatchTessLevels(numPatches, constantOuterLevelIndex, constantOuterLevel, rnd);
3920 }
3921 
init(void)3922 void InvariantOuterEdgeCase::init (void)
3923 {
3924 	checkTessellationSupport(m_context);
3925 	checkRenderTargetSize(m_context.getRenderTarget(), RENDER_SIZE);
3926 
3927 	for (int windingI = 0; windingI < WINDING_LAST; windingI++)
3928 	{
3929 		const Winding winding = (Winding)windingI;
3930 
3931 		for (int usePointModeI = 0; usePointModeI <= 1; usePointModeI++)
3932 		{
3933 			const bool		usePointMode	= usePointModeI != 0;
3934 			const int		programNdx		= (int)m_programs.size();
3935 			const string	floatLit01		= de::floatToString(10.0f / (float)(programNdx + 10), 2);
3936 
3937 			std::string vertexShaderTemplate			("${GLSL_VERSION_DECL}\n"
3938 														 "\n"
3939 														 "in highp float in_v_attr;\n"
3940 														 "out highp float in_tc_attr;\n"
3941 														 "\n"
3942 														 "void main (void)\n"
3943 														 "{\n"
3944 														 "	in_tc_attr = in_v_attr;\n"
3945 														 "}\n");
3946 			std::string tessellationControlTemplate		("${GLSL_VERSION_DECL}\n"
3947 														 "${TESSELLATION_SHADER_REQUIRE}\n"
3948 														 "\n"
3949 														 "layout (vertices = " + de::toString(programNdx+1) + ") out;\n"
3950 														 "\n"
3951 														 "in highp float in_tc_attr[];\n"
3952 														 "\n"
3953 														 "void main (void)\n"
3954 														 "{\n"
3955 														 "	gl_TessLevelInner[0] = in_tc_attr[0];\n"
3956 														 "	gl_TessLevelInner[1] = in_tc_attr[1];\n"
3957 														 "\n"
3958 														 "	gl_TessLevelOuter[0] = in_tc_attr[2];\n"
3959 														 "	gl_TessLevelOuter[1] = in_tc_attr[3];\n"
3960 														 "	gl_TessLevelOuter[2] = in_tc_attr[4];\n"
3961 														 "	gl_TessLevelOuter[3] = in_tc_attr[5];\n"
3962 														 "}\n");
3963 			std::string tessellationEvaluationTemplate	("${GLSL_VERSION_DECL}\n"
3964 														 "${TESSELLATION_SHADER_REQUIRE}\n"
3965 														 "\n"
3966 														 + getTessellationEvaluationInLayoutString(m_primitiveType, m_spacing, winding, usePointMode) +
3967 														 "\n"
3968 														 "out highp vec4 in_f_color;\n"
3969 														 "invariant out highp vec3 out_te_tessCoord;\n"
3970 														 "\n"
3971 														 "void main (void)\n"
3972 														 "{\n"
3973 														 "	gl_Position = vec4(gl_TessCoord.xy*" + floatLit01 + " - float(gl_PrimitiveID)*0.05, 0.0, 1.0);\n"
3974 														 "	in_f_color = vec4(" + floatLit01 + ");\n"
3975 														 "	out_te_tessCoord = gl_TessCoord;\n"
3976 														 "}\n");
3977 			std::string fragmentShaderTemplate			("${GLSL_VERSION_DECL}\n"
3978 														 "\n"
3979 														 "layout (location = 0) out mediump vec4 o_color;\n"
3980 														 "\n"
3981 														 "in highp vec4 in_f_color;\n"
3982 														 "\n"
3983 														 "void main (void)\n"
3984 														 "{\n"
3985 														 "	o_color = in_f_color;\n"
3986 														 "}\n");
3987 
3988 			m_programs.push_back(Program(winding, usePointMode,
3989 										 SharedPtr<const ShaderProgram>(new ShaderProgram(m_context.getRenderContext(), glu::ProgramSources()
3990 				<< glu::VertexSource					(specializeShader(m_context, vertexShaderTemplate.c_str()))
3991 				<< glu::TessellationControlSource		(specializeShader(m_context, tessellationControlTemplate.c_str()))
3992 				<< glu::TessellationEvaluationSource	(specializeShader(m_context, tessellationEvaluationTemplate.c_str()))
3993 				<< glu::FragmentSource					(specializeShader(m_context, fragmentShaderTemplate.c_str()))
3994 				<< glu::TransformFeedbackVarying		("out_te_tessCoord")
3995 				<< glu::TransformFeedbackMode			(GL_INTERLEAVED_ATTRIBS)))));
3996 
3997 			{
3998 				const tcu::ScopedLogSection section(m_testCtx.getLog(), "Program" + de::toString(programNdx), "Program " + de::toString(programNdx));
3999 
4000 				if (programNdx == 0 || !m_programs.back().program->isOk())
4001 					m_testCtx.getLog() << *m_programs.back().program;
4002 
4003 				if (!m_programs.back().program->isOk())
4004 					TCU_FAIL("Program compilation failed");
4005 
4006 				if (programNdx > 0)
4007 					m_testCtx.getLog() << TestLog::Message << "Note: program " << programNdx << " is similar to above, except some constants are different, and: " << m_programs.back().description() << TestLog::EndMessage;
4008 			}
4009 		}
4010 	}
4011 }
4012 
deinit(void)4013 void InvariantOuterEdgeCase::deinit (void)
4014 {
4015 	m_programs.clear();
4016 }
4017 
iterate(void)4018 InvariantOuterEdgeCase::IterateResult InvariantOuterEdgeCase::iterate (void)
4019 {
4020 	typedef TransformFeedbackHandler<Vec3> TFHandler;
4021 
4022 	TestLog&							log							= m_testCtx.getLog();
4023 	const RenderContext&				renderCtx					= m_context.getRenderContext();
4024 	const RandomViewport				viewport					(renderCtx.getRenderTarget(), RENDER_SIZE, RENDER_SIZE, deStringHash(getName()));
4025 	const glw::Functions&				gl							= renderCtx.getFunctions();
4026 
4027 	static const float					singleOuterEdgeLevels[]		= { 1.0f, 1.2f, 1.9f, 2.3f, 2.8f, 3.3f, 3.8f, 10.2f, 1.6f, 24.4f, 24.7f, 63.0f };
4028 	const int							numPatchesPerDrawCall		= 10;
4029 	const vector<OuterEdgeDescription>	edgeDescriptions			= outerEdgeDescriptions(m_primitiveType);
4030 
4031 	{
4032 		// Compute the number vertices in the largest draw call, so we can allocate the TF buffer just once.
4033 		int maxNumVerticesInDrawCall = 0;
4034 		{
4035 			const vector<float> patchTessLevels = generatePatchTessLevels(numPatchesPerDrawCall, 0 /* outer-edge index doesn't affect vertex count */, arrayMax(singleOuterEdgeLevels));
4036 
4037 			for (int usePointModeI = 0; usePointModeI <= 1; usePointModeI++)
4038 				maxNumVerticesInDrawCall = de::max(maxNumVerticesInDrawCall,
4039 												   multiplePatchReferenceVertexCount(m_primitiveType, m_spacing, usePointModeI != 0, &patchTessLevels[0], numPatchesPerDrawCall));
4040 		}
4041 
4042 		{
4043 			const TFHandler tfHandler(m_context.getRenderContext(), maxNumVerticesInDrawCall);
4044 
4045 			setViewport(gl, viewport);
4046 			gl.patchParameteri(GL_PATCH_VERTICES, 6);
4047 
4048 			for (int outerEdgeIndex = 0; outerEdgeIndex < (int)edgeDescriptions.size(); outerEdgeIndex++)
4049 			{
4050 				const OuterEdgeDescription& edgeDesc = edgeDescriptions[outerEdgeIndex];
4051 
4052 				for (int outerEdgeLevelCaseNdx = 0; outerEdgeLevelCaseNdx < DE_LENGTH_OF_ARRAY(singleOuterEdgeLevels); outerEdgeLevelCaseNdx++)
4053 				{
4054 					typedef std::set<Vec3, VecLexLessThan<3> > Vec3Set;
4055 
4056 					const vector<float>				patchTessLevels		= generatePatchTessLevels(numPatchesPerDrawCall, outerEdgeIndex, singleOuterEdgeLevels[outerEdgeLevelCaseNdx]);
4057 					const glu::VertexArrayBinding	bindings[]			= { glu::va::Float("in_v_attr", 1, (int)patchTessLevels.size(), 0, &patchTessLevels[0]) };
4058 					Vec3Set							firstOuterEdgeVertices; // Vertices of the outer edge of the first patch of the first program's draw call; used for comparison with other patches.
4059 
4060 					log << TestLog::Message << "Testing with outer tessellation level " << singleOuterEdgeLevels[outerEdgeLevelCaseNdx]
4061 											<< " for the " << edgeDesc.description() << " edge, and with various levels for other edges, and with all programs" << TestLog::EndMessage;
4062 
4063 					for (int programNdx = 0; programNdx < (int)m_programs.size(); programNdx++)
4064 					{
4065 						const Program& program		= m_programs[programNdx];
4066 						const deUint32 programGL	= program.program->getProgram();
4067 
4068 						gl.useProgram(programGL);
4069 
4070 						{
4071 							const TFHandler::Result		tfResult			= tfHandler.renderAndGetPrimitives(programGL, outputPrimitiveTypeGL(m_primitiveType, program.usePointMode),
4072 																											   DE_LENGTH_OF_ARRAY(bindings), &bindings[0], (int)patchTessLevels.size());
4073 							const int					refNumVertices		= multiplePatchReferenceVertexCount(m_primitiveType, m_spacing, program.usePointMode, &patchTessLevels[0], numPatchesPerDrawCall);
4074 							int							numVerticesRead		= 0;
4075 
4076 							if ((int)tfResult.varying.size() != refNumVertices)
4077 							{
4078 								log << TestLog::Message << "Failure: the number of vertices returned by transform feedback is "
4079 														<< tfResult.varying.size() << ", expected " << refNumVertices << TestLog::EndMessage
4080 									<< TestLog::Message << "Note: rendered " << numPatchesPerDrawCall
4081 														<< " patches in one draw call; tessellation levels for each patch are (in order [inner0, inner1, outer0, outer1, outer2, outer3]):\n"
4082 														<< containerStr(patchTessLevels, 6) << TestLog::EndMessage;
4083 
4084 								m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid set of vertices");
4085 								return STOP;
4086 							}
4087 
4088 							// Check the vertices of each patch.
4089 
4090 							for (int patchNdx = 0; patchNdx < numPatchesPerDrawCall; patchNdx++)
4091 							{
4092 								const float* const	innerLevels			= &patchTessLevels[6*patchNdx + 0];
4093 								const float* const	outerLevels			= &patchTessLevels[6*patchNdx + 2];
4094 								const int			patchNumVertices	= referenceVertexCount(m_primitiveType, m_spacing, program.usePointMode, innerLevels, outerLevels);
4095 								Vec3Set				outerEdgeVertices;
4096 
4097 								// We're interested in just the vertices on the current outer edge.
4098 								for(int vtxNdx = numVerticesRead; vtxNdx < numVerticesRead + patchNumVertices; vtxNdx++)
4099 								{
4100 									const Vec3& vtx = tfResult.varying[vtxNdx];
4101 									if (edgeDesc.contains(vtx))
4102 										outerEdgeVertices.insert(tfResult.varying[vtxNdx]);
4103 								}
4104 
4105 								// Check that the outer edge contains an appropriate number of vertices.
4106 								{
4107 									const int refNumVerticesOnOuterEdge = 1 + getClampedRoundedTessLevel(m_spacing, singleOuterEdgeLevels[outerEdgeLevelCaseNdx]);
4108 
4109 									if ((int)outerEdgeVertices.size() != refNumVerticesOnOuterEdge)
4110 									{
4111 										log << TestLog::Message << "Failure: the number of vertices on outer edge is " << outerEdgeVertices.size()
4112 																<< ", expected " << refNumVerticesOnOuterEdge << TestLog::EndMessage
4113 											<< TestLog::Message << "Note: vertices on the outer edge are:\n" << containerStr(outerEdgeVertices, 5, 0) << TestLog::EndMessage
4114 											<< TestLog::Message << "Note: the following parameters were used: " << program.description()
4115 																<< ", tessellation levels: " << tessellationLevelsString(innerLevels, outerLevels) << TestLog::EndMessage;
4116 										m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid set of vertices");
4117 										return STOP;
4118 									}
4119 								}
4120 
4121 								// Compare the vertices to those of the first patch (unless this is the first patch).
4122 
4123 								if (programNdx == 0 && patchNdx == 0)
4124 									firstOuterEdgeVertices = outerEdgeVertices;
4125 								else
4126 								{
4127 									if (firstOuterEdgeVertices != outerEdgeVertices)
4128 									{
4129 										log << TestLog::Message << "Failure: vertices generated for the edge differ between the following cases:\n"
4130 																<< "  - case A: " << m_programs[0].description() << ", tessellation levels: "
4131 																				  << tessellationLevelsString(&patchTessLevels[0], &patchTessLevels[2]) << "\n"
4132 																<< "  - case B: " << program.description() << ", tessellation levels: "
4133 																				  << tessellationLevelsString(innerLevels, outerLevels) << TestLog::EndMessage;
4134 
4135 										log << TestLog::Message << "Note: resulting vertices for the edge for the cases were:\n"
4136 																<< "  - case A: " << containerStr(firstOuterEdgeVertices, 5, 14) << "\n"
4137 																<< "  - case B: " << containerStr(outerEdgeVertices, 5, 14) << TestLog::EndMessage;
4138 
4139 										m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid set of vertices");
4140 										return STOP;
4141 									}
4142 								}
4143 
4144 								numVerticesRead += patchNumVertices;
4145 							}
4146 
4147 							DE_ASSERT(numVerticesRead == (int)tfResult.varying.size());
4148 						}
4149 					}
4150 				}
4151 			}
4152 		}
4153 	}
4154 
4155 	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
4156 	return STOP;
4157 }
4158 
4159 /*--------------------------------------------------------------------*//*!
4160  * \brief Test invariance rule #3
4161  *
4162  * Test that the vertices along an outer edge are placed symmetrically.
4163  *
4164  * Draw multiple patches with different tessellation levels and different
4165  * point_mode, winding etc. Before outputting tesscoords with TF, mirror
4166  * the vertices in the TES such that every vertex on an outer edge -
4167  * except the possible middle vertex - should be duplicated in the output.
4168  * Check that appropriate duplicates exist.
4169  *//*--------------------------------------------------------------------*/
4170 class SymmetricOuterEdgeCase : public TestCase
4171 {
4172 public:
SymmetricOuterEdgeCase(Context & context,const char * name,const char * description,TessPrimitiveType primType,SpacingMode spacing,Winding winding,bool usePointMode)4173 	SymmetricOuterEdgeCase (Context& context, const char* name, const char* description, TessPrimitiveType primType, SpacingMode spacing, Winding winding, bool usePointMode)
4174 		: TestCase			(context, name, description)
4175 		, m_primitiveType	(primType)
4176 		, m_spacing			(spacing)
4177 		, m_winding			(winding)
4178 		, m_usePointMode	(usePointMode)
4179 	{
4180 	}
4181 
4182 	void									init		(void);
4183 	void									deinit		(void);
4184 	IterateResult							iterate		(void);
4185 
4186 private:
4187 	static vector<float>					generatePatchTessLevels (int numPatches, int constantOuterLevelIndex, float constantOuterLevel);
4188 
4189 	static const int						RENDER_SIZE = 16;
4190 
4191 	const TessPrimitiveType					m_primitiveType;
4192 	const SpacingMode						m_spacing;
4193 	const Winding							m_winding;
4194 	const bool								m_usePointMode;
4195 
4196 	SharedPtr<const glu::ShaderProgram>		m_program;
4197 };
4198 
generatePatchTessLevels(int numPatches,int constantOuterLevelIndex,float constantOuterLevel)4199 vector<float> SymmetricOuterEdgeCase::generatePatchTessLevels (int numPatches, int constantOuterLevelIndex, float constantOuterLevel)
4200 {
4201 	de::Random rnd(123);
4202 	return generateRandomPatchTessLevels(numPatches, constantOuterLevelIndex, constantOuterLevel, rnd);
4203 }
4204 
init(void)4205 void SymmetricOuterEdgeCase::init (void)
4206 {
4207 	checkTessellationSupport(m_context);
4208 	checkRenderTargetSize(m_context.getRenderTarget(), RENDER_SIZE);
4209 
4210 	std::string vertexShaderTemplate			("${GLSL_VERSION_DECL}\n"
4211 												 "\n"
4212 												 "in highp float in_v_attr;\n"
4213 												 "out highp float in_tc_attr;\n"
4214 												 "\n"
4215 												 "void main (void)\n"
4216 												 "{\n"
4217 												 "	in_tc_attr = in_v_attr;\n"
4218 												 "}\n");
4219 	std::string tessellationControlTemplate		("${GLSL_VERSION_DECL}\n"
4220 												 "${TESSELLATION_SHADER_REQUIRE}\n"
4221 												 "\n"
4222 												 "layout (vertices = 1) out;\n"
4223 												 "\n"
4224 												 "in highp float in_tc_attr[];\n"
4225 												 "\n"
4226 												 "void main (void)\n"
4227 												 "{\n"
4228 												 "	gl_TessLevelInner[0] = in_tc_attr[0];\n"
4229 												 "	gl_TessLevelInner[1] = in_tc_attr[1];\n"
4230 												 "\n"
4231 												 "	gl_TessLevelOuter[0] = in_tc_attr[2];\n"
4232 												 "	gl_TessLevelOuter[1] = in_tc_attr[3];\n"
4233 												 "	gl_TessLevelOuter[2] = in_tc_attr[4];\n"
4234 												 "	gl_TessLevelOuter[3] = in_tc_attr[5];\n"
4235 												 "}\n");
4236 	std::string tessellationEvaluationTemplate	("${GLSL_VERSION_DECL}\n"
4237 												 "${TESSELLATION_SHADER_REQUIRE}\n"
4238 												 "\n"
4239 												 + getTessellationEvaluationInLayoutString(m_primitiveType, m_spacing, m_winding, m_usePointMode) +
4240 												 "\n"
4241 												 "out highp vec4 in_f_color;\n"
4242 												 "out highp vec4 out_te_tessCoord_isMirrored;\n"
4243 												 "\n"
4244 												 "void main (void)\n"
4245 												 "{\n"
4246 												 + (m_primitiveType == TESSPRIMITIVETYPE_TRIANGLES ?
4247 													"	float x = gl_TessCoord.x;\n"
4248 													"	float y = gl_TessCoord.y;\n"
4249 													"	float z = gl_TessCoord.z;\n"
4250 													"	// Mirror one half of each outer edge onto the other half, except the endpoints (because they belong to two edges)\n"
4251 													"	out_te_tessCoord_isMirrored = z == 0.0 && x > 0.5 && x != 1.0 ? vec4(1.0-x,  1.0-y,    0.0, 1.0)\n"
4252 													"	                            : y == 0.0 && z > 0.5 && z != 1.0 ? vec4(1.0-x,    0.0,  1.0-z, 1.0)\n"
4253 													"	                            : x == 0.0 && y > 0.5 && y != 1.0 ? vec4(  0.0,  1.0-y,  1.0-z, 1.0)\n"
4254 													"	                            : vec4(x, y, z, 0.0);\n"
4255 												  : m_primitiveType == TESSPRIMITIVETYPE_QUADS ?
4256 													"	float x = gl_TessCoord.x;\n"
4257 													"	float y = gl_TessCoord.y;\n"
4258 													"	// Mirror one half of each outer edge onto the other half, except the endpoints (because they belong to two edges)\n"
4259 													"	out_te_tessCoord_isMirrored = (x == 0.0 || x == 1.0) && y > 0.5 && y != 1.0 ? vec4(    x, 1.0-y, 0.0, 1.0)\n"
4260 													"	                            : (y == 0.0 || y == 1.0) && x > 0.5 && x != 1.0 ? vec4(1.0-x,     y, 0.0, 1.0)\n"
4261 													"	                            : vec4(x, y, 0.0, 0.0);\n"
4262 												  : m_primitiveType == TESSPRIMITIVETYPE_ISOLINES ?
4263 													"	float x = gl_TessCoord.x;\n"
4264 													"	float y = gl_TessCoord.y;\n"
4265 													"	// Mirror one half of each outer edge onto the other half\n"
4266 													"	out_te_tessCoord_isMirrored = (x == 0.0 || x == 1.0) && y > 0.5 ? vec4(x, 1.0-y, 0.0, 1.0)\n"
4267 													"	                            : vec4(x, y, 0.0, 0.0f);\n"
4268 												  : DE_NULL) +
4269 												 "\n"
4270 												 "	gl_Position = vec4(gl_TessCoord.xy, 0.0, 1.0);\n"
4271 												 "	in_f_color = vec4(1.0);\n"
4272 												 "}\n");
4273 	std::string fragmentShaderTemplate			("${GLSL_VERSION_DECL}\n"
4274 												 "\n"
4275 												 "layout (location = 0) out mediump vec4 o_color;\n"
4276 												 "\n"
4277 												 "in highp vec4 in_f_color;\n"
4278 												 "\n"
4279 												 "void main (void)\n"
4280 												 "{\n"
4281 												 "	o_color = in_f_color;\n"
4282 												 "}\n");
4283 
4284 	m_program = SharedPtr<const ShaderProgram>(new ShaderProgram(m_context.getRenderContext(), glu::ProgramSources()
4285 		<< glu::VertexSource					(specializeShader(m_context, vertexShaderTemplate.c_str()))
4286 		<< glu::TessellationControlSource		(specializeShader(m_context, tessellationControlTemplate.c_str()))
4287 		<< glu::TessellationEvaluationSource	(specializeShader(m_context, tessellationEvaluationTemplate.c_str()))
4288 		<< glu::FragmentSource					(specializeShader(m_context, fragmentShaderTemplate.c_str()))
4289 		<< glu::TransformFeedbackVarying		("out_te_tessCoord_isMirrored")
4290 		<< glu::TransformFeedbackMode			(GL_INTERLEAVED_ATTRIBS)));
4291 
4292 	m_testCtx.getLog() << *m_program;
4293 	if (!m_program->isOk())
4294 		TCU_FAIL("Program compilation failed");
4295 }
4296 
deinit(void)4297 void SymmetricOuterEdgeCase::deinit (void)
4298 {
4299 	m_program.clear();
4300 }
4301 
iterate(void)4302 SymmetricOuterEdgeCase::IterateResult SymmetricOuterEdgeCase::iterate (void)
4303 {
4304 	typedef TransformFeedbackHandler<Vec4> TFHandler;
4305 
4306 	TestLog&							log							= m_testCtx.getLog();
4307 	const RenderContext&				renderCtx					= m_context.getRenderContext();
4308 	const RandomViewport				viewport					(renderCtx.getRenderTarget(), RENDER_SIZE, RENDER_SIZE, deStringHash(getName()));
4309 	const glw::Functions&				gl							= renderCtx.getFunctions();
4310 
4311 	static const float					singleOuterEdgeLevels[]		= { 1.0f, 1.2f, 1.9f, 2.3f, 2.8f, 3.3f, 3.8f, 10.2f, 1.6f, 24.4f, 24.7f, 63.0f };
4312 	const vector<OuterEdgeDescription>	edgeDescriptions			= outerEdgeDescriptions(m_primitiveType);
4313 
4314 	{
4315 		// Compute the number vertices in the largest draw call, so we can allocate the TF buffer just once.
4316 		int maxNumVerticesInDrawCall;
4317 		{
4318 			const vector<float> patchTessLevels = generatePatchTessLevels(1, 0 /* outer-edge index doesn't affect vertex count */, arrayMax(singleOuterEdgeLevels));
4319 			maxNumVerticesInDrawCall = referenceVertexCount(m_primitiveType, m_spacing, m_usePointMode, &patchTessLevels[0], &patchTessLevels[2]);
4320 		}
4321 
4322 		{
4323 			const TFHandler tfHandler(m_context.getRenderContext(), maxNumVerticesInDrawCall);
4324 
4325 			setViewport(gl, viewport);
4326 			gl.patchParameteri(GL_PATCH_VERTICES, 6);
4327 
4328 			for (int outerEdgeIndex = 0; outerEdgeIndex < (int)edgeDescriptions.size(); outerEdgeIndex++)
4329 			{
4330 				const OuterEdgeDescription& edgeDesc = edgeDescriptions[outerEdgeIndex];
4331 
4332 				for (int outerEdgeLevelCaseNdx = 0; outerEdgeLevelCaseNdx < DE_LENGTH_OF_ARRAY(singleOuterEdgeLevels); outerEdgeLevelCaseNdx++)
4333 				{
4334 					typedef std::set<Vec3, VecLexLessThan<3> > Vec3Set;
4335 
4336 					const vector<float>				patchTessLevels		= generatePatchTessLevels(1, outerEdgeIndex, singleOuterEdgeLevels[outerEdgeLevelCaseNdx]);
4337 					const glu::VertexArrayBinding	bindings[]			= { glu::va::Float("in_v_attr", 1, (int)patchTessLevels.size(), 0, &patchTessLevels[0]) };
4338 
4339 					log << TestLog::Message << "Testing with outer tessellation level " << singleOuterEdgeLevels[outerEdgeLevelCaseNdx]
4340 											<< " for the " << edgeDesc.description() << " edge, and with various levels for other edges" << TestLog::EndMessage;
4341 
4342 					{
4343 						const deUint32 programGL = m_program->getProgram();
4344 
4345 						gl.useProgram(programGL);
4346 
4347 						{
4348 							const TFHandler::Result		tfResult		= tfHandler.renderAndGetPrimitives(programGL, outputPrimitiveTypeGL(m_primitiveType, m_usePointMode),
4349 																										   DE_LENGTH_OF_ARRAY(bindings), &bindings[0], (int)patchTessLevels.size());
4350 							const int					refNumVertices	= referenceVertexCount(m_primitiveType, m_spacing, m_usePointMode, &patchTessLevels[0], &patchTessLevels[2]);
4351 
4352 							if ((int)tfResult.varying.size() != refNumVertices)
4353 							{
4354 								log << TestLog::Message << "Failure: the number of vertices returned by transform feedback is "
4355 														<< tfResult.varying.size() << ", expected " << refNumVertices << TestLog::EndMessage
4356 									<< TestLog::Message << "Note: rendered 1 patch, tessellation levels are (in order [inner0, inner1, outer0, outer1, outer2, outer3]):\n"
4357 														<< containerStr(patchTessLevels, 6) << TestLog::EndMessage;
4358 
4359 								m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid set of vertices");
4360 								return STOP;
4361 							}
4362 
4363 							// Check the vertices.
4364 
4365 							{
4366 								Vec3Set nonMirroredEdgeVertices;
4367 								Vec3Set mirroredEdgeVertices;
4368 
4369 								// We're interested in just the vertices on the current outer edge.
4370 								for(int vtxNdx = 0; vtxNdx < refNumVertices; vtxNdx++)
4371 								{
4372 									const Vec3& vtx = tfResult.varying[vtxNdx].swizzle(0,1,2);
4373 									if (edgeDesc.contains(vtx))
4374 									{
4375 										// Ignore the middle vertex of the outer edge, as it's exactly at the mirroring point;
4376 										// for isolines, also ignore (0, 0) and (1, 0) because there's no mirrored counterpart for them.
4377 										if (m_primitiveType == TESSPRIMITIVETYPE_TRIANGLES && vtx == tcu::select(Vec3(0.0f), Vec3(0.5f), singleTrueMask<3>(edgeDesc.constantCoordinateIndex)))
4378 											continue;
4379 										if (m_primitiveType == TESSPRIMITIVETYPE_QUADS && vtx.swizzle(0,1) == tcu::select(Vec2(edgeDesc.constantCoordinateValueChoices[0]),
4380 																															   Vec2(0.5f),
4381 																															   singleTrueMask<2>(edgeDesc.constantCoordinateIndex)))
4382 											continue;
4383 										if (m_primitiveType == TESSPRIMITIVETYPE_ISOLINES && (vtx == Vec3(0.0f, 0.5f, 0.0f) || vtx == Vec3(1.0f, 0.5f, 0.0f) ||
4384 																							  vtx == Vec3(0.0f, 0.0f, 0.0f) || vtx == Vec3(1.0f, 0.0f, 0.0f)))
4385 											continue;
4386 
4387 										const bool isMirrored = tfResult.varying[vtxNdx].w() > 0.5f;
4388 										if (isMirrored)
4389 											mirroredEdgeVertices.insert(vtx);
4390 										else
4391 											nonMirroredEdgeVertices.insert(vtx);
4392 									}
4393 								}
4394 
4395 								if (m_primitiveType != TESSPRIMITIVETYPE_ISOLINES)
4396 								{
4397 									// Check that both endpoints are present. Note that endpoints aren't mirrored by the shader, since they belong to more than one edge.
4398 
4399 									Vec3 endpointA;
4400 									Vec3 endpointB;
4401 
4402 									if (m_primitiveType == TESSPRIMITIVETYPE_TRIANGLES)
4403 									{
4404 										endpointA = tcu::select(Vec3(1.0f), Vec3(0.0f), singleTrueMask<3>((edgeDesc.constantCoordinateIndex + 1) % 3));
4405 										endpointB = tcu::select(Vec3(1.0f), Vec3(0.0f), singleTrueMask<3>((edgeDesc.constantCoordinateIndex + 2) % 3));
4406 									}
4407 									else if (m_primitiveType == TESSPRIMITIVETYPE_QUADS)
4408 									{
4409 										endpointA.xy() = tcu::select(Vec2(edgeDesc.constantCoordinateValueChoices[0]), Vec2(0.0f), singleTrueMask<2>(edgeDesc.constantCoordinateIndex));
4410 										endpointB.xy() = tcu::select(Vec2(edgeDesc.constantCoordinateValueChoices[0]), Vec2(1.0f), singleTrueMask<2>(edgeDesc.constantCoordinateIndex));
4411 									}
4412 									else
4413 										DE_ASSERT(false);
4414 
4415 									if (!contains(nonMirroredEdgeVertices, endpointA) ||
4416 										!contains(nonMirroredEdgeVertices, endpointB))
4417 									{
4418 										log << TestLog::Message << "Failure: edge doesn't contain both endpoints, " << endpointA << " and " << endpointB << TestLog::EndMessage
4419 											<< TestLog::Message << "Note: non-mirrored vertices:\n" << containerStr(nonMirroredEdgeVertices, 5)
4420 																<< "\nmirrored vertices:\n" << containerStr(mirroredEdgeVertices, 5) << TestLog::EndMessage;
4421 										m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid set of vertices");
4422 										return STOP;
4423 									}
4424 									nonMirroredEdgeVertices.erase(endpointA);
4425 									nonMirroredEdgeVertices.erase(endpointB);
4426 								}
4427 
4428 								if (nonMirroredEdgeVertices != mirroredEdgeVertices)
4429 								{
4430 									log << TestLog::Message << "Failure: the set of mirrored edges isn't equal to the set of non-mirrored edges (ignoring endpoints and possible middle)" << TestLog::EndMessage
4431 										<< TestLog::Message << "Note: non-mirrored vertices:\n" << containerStr(nonMirroredEdgeVertices, 5)
4432 																<< "\nmirrored vertices:\n" << containerStr(mirroredEdgeVertices, 5) << TestLog::EndMessage;
4433 									m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid set of vertices");
4434 									return STOP;
4435 								}
4436 							}
4437 						}
4438 					}
4439 				}
4440 			}
4441 		}
4442 	}
4443 
4444 	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
4445 	return STOP;
4446 }
4447 
4448 /*--------------------------------------------------------------------*//*!
4449  * \brief Test invariance rule #4
4450  *
4451  * Test that the vertices on an outer edge don't depend on which of the
4452  * edges it is, other than with respect to component order.
4453  *//*--------------------------------------------------------------------*/
4454 class OuterEdgeVertexSetIndexIndependenceCase : public TestCase
4455 {
4456 public:
OuterEdgeVertexSetIndexIndependenceCase(Context & context,const char * name,const char * description,TessPrimitiveType primType,SpacingMode spacing,Winding winding,bool usePointMode)4457 	OuterEdgeVertexSetIndexIndependenceCase (Context& context, const char* name, const char* description, TessPrimitiveType primType, SpacingMode spacing, Winding winding, bool usePointMode)
4458 		: TestCase			(context, name, description)
4459 		, m_primitiveType	(primType)
4460 		, m_spacing			(spacing)
4461 		, m_winding			(winding)
4462 		, m_usePointMode	(usePointMode)
4463 	{
4464 		DE_ASSERT(primType == TESSPRIMITIVETYPE_TRIANGLES || primType == TESSPRIMITIVETYPE_QUADS);
4465 	}
4466 
4467 	void									init		(void);
4468 	void									deinit		(void);
4469 	IterateResult							iterate		(void);
4470 
4471 private:
4472 	static vector<float>					generatePatchTessLevels (int numPatches, int constantOuterLevelIndex, float constantOuterLevel);
4473 
4474 	static const int						RENDER_SIZE = 16;
4475 
4476 	const TessPrimitiveType					m_primitiveType;
4477 	const SpacingMode						m_spacing;
4478 	const Winding							m_winding;
4479 	const bool								m_usePointMode;
4480 
4481 	SharedPtr<const glu::ShaderProgram>		m_program;
4482 };
4483 
generatePatchTessLevels(int numPatches,int constantOuterLevelIndex,float constantOuterLevel)4484 vector<float> OuterEdgeVertexSetIndexIndependenceCase::generatePatchTessLevels (int numPatches, int constantOuterLevelIndex, float constantOuterLevel)
4485 {
4486 	de::Random rnd(123);
4487 	return generateRandomPatchTessLevels(numPatches, constantOuterLevelIndex, constantOuterLevel, rnd);
4488 }
4489 
init(void)4490 void OuterEdgeVertexSetIndexIndependenceCase::init (void)
4491 {
4492 	checkTessellationSupport(m_context);
4493 	checkRenderTargetSize(m_context.getRenderTarget(), RENDER_SIZE);
4494 
4495 	std::string vertexShaderTemplate			("${GLSL_VERSION_DECL}\n"
4496 												 "\n"
4497 												 "in highp float in_v_attr;\n"
4498 												 "out highp float in_tc_attr;\n"
4499 												 "\n"
4500 												 "void main (void)\n"
4501 												 "{\n"
4502 												 "	in_tc_attr = in_v_attr;\n"
4503 												 "}\n");
4504 	std::string tessellationControlTemplate		("${GLSL_VERSION_DECL}\n"
4505 												 "${TESSELLATION_SHADER_REQUIRE}\n"
4506 												 "\n"
4507 												 "layout (vertices = 1) out;\n"
4508 												 "\n"
4509 												 "in highp float in_tc_attr[];\n"
4510 												 "\n"
4511 												 "void main (void)\n"
4512 												 "{\n"
4513 												 "	gl_TessLevelInner[0] = in_tc_attr[0];\n"
4514 												 "	gl_TessLevelInner[1] = in_tc_attr[1];\n"
4515 												 "\n"
4516 												 "	gl_TessLevelOuter[0] = in_tc_attr[2];\n"
4517 												 "	gl_TessLevelOuter[1] = in_tc_attr[3];\n"
4518 												 "	gl_TessLevelOuter[2] = in_tc_attr[4];\n"
4519 												 "	gl_TessLevelOuter[3] = in_tc_attr[5];\n"
4520 												 "}\n");
4521 	std::string tessellationEvaluationTemplate	("${GLSL_VERSION_DECL}\n"
4522 												 "${TESSELLATION_SHADER_REQUIRE}\n"
4523 												 "\n"
4524 												 + getTessellationEvaluationInLayoutString(m_primitiveType, m_spacing, m_winding, m_usePointMode) +
4525 												 "\n"
4526 												 "out highp vec4 in_f_color;\n"
4527 												 "out highp vec3 out_te_tessCoord;\n"
4528 												 "\n"
4529 												 "void main (void)\n"
4530 												 "{\n"
4531 												 "	out_te_tessCoord = gl_TessCoord;"
4532 												 "	gl_Position = vec4(gl_TessCoord.xy, 0.0, 1.0);\n"
4533 												 "	in_f_color = vec4(1.0);\n"
4534 												 "}\n");
4535 	std::string fragmentShaderTemplate			("${GLSL_VERSION_DECL}\n"
4536 												 "\n"
4537 												 "layout (location = 0) out mediump vec4 o_color;\n"
4538 												 "\n"
4539 												 "in highp vec4 in_f_color;\n"
4540 												 "\n"
4541 												 "void main (void)\n"
4542 												 "{\n"
4543 												 "	o_color = in_f_color;\n"
4544 												 "}\n");
4545 
4546 	m_program = SharedPtr<const ShaderProgram>(new ShaderProgram(m_context.getRenderContext(), glu::ProgramSources()
4547 		<< glu::VertexSource					(specializeShader(m_context, vertexShaderTemplate.c_str()))
4548 		<< glu::TessellationControlSource		(specializeShader(m_context, tessellationControlTemplate.c_str()))
4549 		<< glu::TessellationEvaluationSource	(specializeShader(m_context, tessellationEvaluationTemplate.c_str()))
4550 		<< glu::FragmentSource					(specializeShader(m_context, fragmentShaderTemplate.c_str()))
4551 		<< glu::TransformFeedbackVarying		("out_te_tessCoord")
4552 		<< glu::TransformFeedbackMode			(GL_INTERLEAVED_ATTRIBS)));
4553 
4554 	m_testCtx.getLog() << *m_program;
4555 	if (!m_program->isOk())
4556 		TCU_FAIL("Program compilation failed");
4557 }
4558 
deinit(void)4559 void OuterEdgeVertexSetIndexIndependenceCase::deinit (void)
4560 {
4561 	m_program.clear();
4562 }
4563 
iterate(void)4564 OuterEdgeVertexSetIndexIndependenceCase::IterateResult OuterEdgeVertexSetIndexIndependenceCase::iterate (void)
4565 {
4566 	typedef TransformFeedbackHandler<Vec3> TFHandler;
4567 
4568 	TestLog&							log							= m_testCtx.getLog();
4569 	const RenderContext&				renderCtx					= m_context.getRenderContext();
4570 	const RandomViewport				viewport					(renderCtx.getRenderTarget(), RENDER_SIZE, RENDER_SIZE, deStringHash(getName()));
4571 	const glw::Functions&				gl							= renderCtx.getFunctions();
4572 	const deUint32						programGL					= m_program->getProgram();
4573 
4574 	static const float					singleOuterEdgeLevels[]		= { 1.0f, 1.2f, 1.9f, 2.3f, 2.8f, 3.3f, 3.8f, 10.2f, 1.6f, 24.4f, 24.7f, 63.0f };
4575 	const vector<OuterEdgeDescription>	edgeDescriptions			= outerEdgeDescriptions(m_primitiveType);
4576 
4577 	gl.useProgram(programGL);
4578 	setViewport(gl, viewport);
4579 	gl.patchParameteri(GL_PATCH_VERTICES, 6);
4580 
4581 	{
4582 		// Compute the number vertices in the largest draw call, so we can allocate the TF buffer just once.
4583 		int maxNumVerticesInDrawCall = 0;
4584 		{
4585 			const vector<float> patchTessLevels = generatePatchTessLevels(1, 0 /* outer-edge index doesn't affect vertex count */, arrayMax(singleOuterEdgeLevels));
4586 			maxNumVerticesInDrawCall = referenceVertexCount(m_primitiveType, m_spacing, m_usePointMode, &patchTessLevels[0], &patchTessLevels[2]);
4587 		}
4588 
4589 		{
4590 			const TFHandler tfHandler(m_context.getRenderContext(), maxNumVerticesInDrawCall);
4591 
4592 			for (int outerEdgeLevelCaseNdx = 0; outerEdgeLevelCaseNdx < DE_LENGTH_OF_ARRAY(singleOuterEdgeLevels); outerEdgeLevelCaseNdx++)
4593 			{
4594 				typedef std::set<Vec3, VecLexLessThan<3> > Vec3Set;
4595 
4596 				Vec3Set firstEdgeVertices;
4597 
4598 				for (int outerEdgeIndex = 0; outerEdgeIndex < (int)edgeDescriptions.size(); outerEdgeIndex++)
4599 				{
4600 					const OuterEdgeDescription&		edgeDesc			= edgeDescriptions[outerEdgeIndex];
4601 					const vector<float>				patchTessLevels		= generatePatchTessLevels(1, outerEdgeIndex, singleOuterEdgeLevels[outerEdgeLevelCaseNdx]);
4602 					const glu::VertexArrayBinding	bindings[]			= { glu::va::Float("in_v_attr", 1, (int)patchTessLevels.size(), 0, &patchTessLevels[0]) };
4603 
4604 					log << TestLog::Message << "Testing with outer tessellation level " << singleOuterEdgeLevels[outerEdgeLevelCaseNdx]
4605 											<< " for the " << edgeDesc.description() << " edge, and with various levels for other edges" << TestLog::EndMessage;
4606 
4607 					{
4608 						const TFHandler::Result		tfResult		= tfHandler.renderAndGetPrimitives(programGL, outputPrimitiveTypeGL(m_primitiveType, m_usePointMode),
4609 																										DE_LENGTH_OF_ARRAY(bindings), &bindings[0], (int)patchTessLevels.size());
4610 						const int					refNumVertices	= referenceVertexCount(m_primitiveType, m_spacing, m_usePointMode, &patchTessLevels[0], &patchTessLevels[2]);
4611 
4612 						if ((int)tfResult.varying.size() != refNumVertices)
4613 						{
4614 							log << TestLog::Message << "Failure: the number of vertices returned by transform feedback is "
4615 													<< tfResult.varying.size() << ", expected " << refNumVertices << TestLog::EndMessage
4616 								<< TestLog::Message << "Note: rendered 1 patch, tessellation levels are (in order [inner0, inner1, outer0, outer1, outer2, outer3]):\n"
4617 													<< containerStr(patchTessLevels, 6) << TestLog::EndMessage;
4618 
4619 							m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid set of vertices");
4620 							return STOP;
4621 						}
4622 
4623 						{
4624 							Vec3Set currentEdgeVertices;
4625 
4626 							// Get the vertices on the current outer edge.
4627 							for(int vtxNdx = 0; vtxNdx < refNumVertices; vtxNdx++)
4628 							{
4629 								const Vec3& vtx = tfResult.varying[vtxNdx];
4630 								if (edgeDesc.contains(vtx))
4631 								{
4632 									// Swizzle components to match the order of the first edge.
4633 									if (m_primitiveType == TESSPRIMITIVETYPE_TRIANGLES)
4634 									{
4635 										currentEdgeVertices.insert(outerEdgeIndex == 0 ? vtx
4636 																	: outerEdgeIndex == 1 ? vtx.swizzle(1, 0, 2)
4637 																	: outerEdgeIndex == 2 ? vtx.swizzle(2, 1, 0)
4638 																	: Vec3(-1.0f));
4639 									}
4640 									else if (m_primitiveType == TESSPRIMITIVETYPE_QUADS)
4641 									{
4642 										currentEdgeVertices.insert(Vec3(outerEdgeIndex == 0 ? vtx.y()
4643 																		: outerEdgeIndex == 1 ? vtx.x()
4644 																		: outerEdgeIndex == 2 ? vtx.y()
4645 																		: outerEdgeIndex == 3 ? vtx.x()
4646 																		: -1.0f,
4647 																		0.0f, 0.0f));
4648 									}
4649 									else
4650 										DE_ASSERT(false);
4651 								}
4652 							}
4653 
4654 							if (outerEdgeIndex == 0)
4655 								firstEdgeVertices = currentEdgeVertices;
4656 							else
4657 							{
4658 								// Compare vertices of this edge to those of the first edge.
4659 
4660 								if (currentEdgeVertices != firstEdgeVertices)
4661 								{
4662 									const char* const swizzleDesc = m_primitiveType == TESSPRIMITIVETYPE_TRIANGLES ? (outerEdgeIndex == 1 ? "(y, x, z)"
4663 																													: outerEdgeIndex == 2 ? "(z, y, x)"
4664 																													: DE_NULL)
4665 																	: m_primitiveType == TESSPRIMITIVETYPE_QUADS ? (outerEdgeIndex == 1 ? "(x, 0)"
4666 																												: outerEdgeIndex == 2 ? "(y, 0)"
4667 																												: outerEdgeIndex == 3 ? "(x, 0)"
4668 																												: DE_NULL)
4669 																	: DE_NULL;
4670 
4671 									log << TestLog::Message << "Failure: the set of vertices on the " << edgeDesc.description() << " edge"
4672 															<< " doesn't match the set of vertices on the " << edgeDescriptions[0].description() << " edge" << TestLog::EndMessage
4673 										<< TestLog::Message << "Note: set of vertices on " << edgeDesc.description() << " edge, components swizzled like " << swizzleDesc
4674 															<< " to match component order on first edge:\n" << containerStr(currentEdgeVertices, 5)
4675 															<< "\non " << edgeDescriptions[0].description() << " edge:\n" << containerStr(firstEdgeVertices, 5) << TestLog::EndMessage;
4676 									m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid set of vertices");
4677 									return STOP;
4678 								}
4679 							}
4680 						}
4681 					}
4682 				}
4683 			}
4684 		}
4685 	}
4686 
4687 	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
4688 	return STOP;
4689 }
4690 
4691 /*--------------------------------------------------------------------*//*!
4692  * \brief Test invariance rule #5
4693  *
4694  * Test that the set of triangles input to the TES only depends on the
4695  * tessellation levels, tessellation mode and spacing mode. Specifically,
4696  * winding doesn't change the set of triangles, though it can change the
4697  * order in which they are input to TES, and can (and will) change the
4698  * vertex order within a triangle.
4699  *//*--------------------------------------------------------------------*/
4700 class InvariantTriangleSetCase : public PrimitiveSetInvarianceCase
4701 {
4702 public:
InvariantTriangleSetCase(Context & context,const char * name,const char * description,TessPrimitiveType primType,SpacingMode spacing)4703 	InvariantTriangleSetCase (Context& context, const char* name, const char* description, TessPrimitiveType primType, SpacingMode spacing)
4704 		: PrimitiveSetInvarianceCase(context, name, description, primType, spacing, false, WINDINGUSAGE_VARY)
4705 	{
4706 		DE_ASSERT(primType == TESSPRIMITIVETYPE_TRIANGLES || primType == TESSPRIMITIVETYPE_QUADS);
4707 	}
4708 
4709 protected:
compare(const vector<Vec3> & coordsA,const vector<Vec3> & coordsB,int) const4710 	virtual bool compare (const vector<Vec3>& coordsA, const vector<Vec3>& coordsB, int) const
4711 	{
4712 		return compareTriangleSets(coordsA, coordsB, m_testCtx.getLog());
4713 	}
4714 };
4715 
4716 /*--------------------------------------------------------------------*//*!
4717  * \brief Test invariance rule #6
4718  *
4719  * Test that the set of inner triangles input to the TES only depends on
4720  * the inner tessellation levels, tessellation mode and spacing mode.
4721  *//*--------------------------------------------------------------------*/
4722 class InvariantInnerTriangleSetCase : public PrimitiveSetInvarianceCase
4723 {
4724 public:
InvariantInnerTriangleSetCase(Context & context,const char * name,const char * description,TessPrimitiveType primType,SpacingMode spacing)4725 	InvariantInnerTriangleSetCase (Context& context, const char* name, const char* description, TessPrimitiveType primType, SpacingMode spacing)
4726 		: PrimitiveSetInvarianceCase(context, name, description, primType, spacing, false, WINDINGUSAGE_VARY)
4727 	{
4728 		DE_ASSERT(primType == TESSPRIMITIVETYPE_TRIANGLES || primType == TESSPRIMITIVETYPE_QUADS);
4729 	}
4730 
4731 protected:
genTessLevelCases(void) const4732 	virtual vector<LevelCase> genTessLevelCases (void) const
4733 	{
4734 		const int					numSubCases		= 4;
4735 		const vector<LevelCase>		baseResults		= PrimitiveSetInvarianceCase::genTessLevelCases();
4736 		vector<LevelCase>			result;
4737 		de::Random					rnd				(123);
4738 
4739 		// Generate variants with different values for irrelevant levels.
4740 		for (int baseNdx = 0; baseNdx < (int)baseResults.size(); baseNdx++)
4741 		{
4742 			const TessLevels&	base	= baseResults[baseNdx].levels[0];
4743 			TessLevels			levels	= base;
4744 			LevelCase			levelCase;
4745 
4746 			for (int subNdx = 0; subNdx < numSubCases; subNdx++)
4747 			{
4748 				levelCase.levels.push_back(levels);
4749 
4750 				for (int i = 0; i < DE_LENGTH_OF_ARRAY(levels.outer); i++)
4751 					levels.outer[i] = rnd.getFloat(2.0f, 16.0f);
4752 				if (m_primitiveType == TESSPRIMITIVETYPE_TRIANGLES)
4753 					levels.inner[1] = rnd.getFloat(2.0f, 16.0f);
4754 			}
4755 
4756 			result.push_back(levelCase);
4757 		}
4758 
4759 		return result;
4760 	}
4761 
4762 	struct IsInnerTriangleTriangle
4763 	{
operator ()deqp::gles31::Functional::__anon4a9088cf0211::InvariantInnerTriangleSetCase::IsInnerTriangleTriangle4764 		bool operator() (const Vec3* vertices) const
4765 		{
4766 			for (int v = 0; v < 3; v++)
4767 				for (int c = 0; c < 3; c++)
4768 					if (vertices[v][c] == 0.0f)
4769 						return false;
4770 			return true;
4771 		}
4772 	};
4773 
4774 	struct IsInnerQuadTriangle
4775 	{
operator ()deqp::gles31::Functional::__anon4a9088cf0211::InvariantInnerTriangleSetCase::IsInnerQuadTriangle4776 		bool operator() (const Vec3* vertices) const
4777 		{
4778 			for (int v = 0; v < 3; v++)
4779 				for (int c = 0; c < 2; c++)
4780 					if (vertices[v][c] == 0.0f || vertices[v][c] == 1.0f)
4781 						return false;
4782 			return true;
4783 		}
4784 	};
4785 
compare(const vector<Vec3> & coordsA,const vector<Vec3> & coordsB,int) const4786 	virtual bool compare (const vector<Vec3>& coordsA, const vector<Vec3>& coordsB, int) const
4787 	{
4788 		if (m_primitiveType == TESSPRIMITIVETYPE_TRIANGLES)
4789 			return compareTriangleSets(coordsA, coordsB, m_testCtx.getLog(), IsInnerTriangleTriangle(), "outer triangles");
4790 		else if (m_primitiveType == TESSPRIMITIVETYPE_QUADS)
4791 			return compareTriangleSets(coordsA, coordsB, m_testCtx.getLog(), IsInnerQuadTriangle(), "outer triangles");
4792 		else
4793 		{
4794 			DE_ASSERT(false);
4795 			return false;
4796 		}
4797 	}
4798 };
4799 
4800 /*--------------------------------------------------------------------*//*!
4801  * \brief Test invariance rule #7
4802  *
4803  * Test that the set of outer triangles input to the TES only depends on
4804  * tessellation mode, spacing mode and the inner and outer tessellation
4805  * levels corresponding to the inner and outer edges relevant to that
4806  * triangle.
4807  *//*--------------------------------------------------------------------*/
4808 class InvariantOuterTriangleSetCase : public PrimitiveSetInvarianceCase
4809 {
4810 public:
InvariantOuterTriangleSetCase(Context & context,const char * name,const char * description,TessPrimitiveType primType,SpacingMode spacing)4811 	InvariantOuterTriangleSetCase (Context& context, const char* name, const char* description, TessPrimitiveType primType, SpacingMode spacing)
4812 		: PrimitiveSetInvarianceCase(context, name, description, primType, spacing, false, WINDINGUSAGE_VARY)
4813 	{
4814 		DE_ASSERT(primType == TESSPRIMITIVETYPE_TRIANGLES || primType == TESSPRIMITIVETYPE_QUADS);
4815 	}
4816 
4817 protected:
genTessLevelCases(void) const4818 	virtual vector<LevelCase> genTessLevelCases (void) const
4819 	{
4820 		const int					numSubCasesPerEdge	= 4;
4821 		const int					numEdges			= m_primitiveType == TESSPRIMITIVETYPE_TRIANGLES	? 3
4822 														: m_primitiveType == TESSPRIMITIVETYPE_QUADS		? 4
4823 														: -1;
4824 		const vector<LevelCase>		baseResult			= PrimitiveSetInvarianceCase::genTessLevelCases();
4825 		vector<LevelCase>			result;
4826 		de::Random					rnd					(123);
4827 
4828 		// Generate variants with different values for irrelevant levels.
4829 		for (int baseNdx = 0; baseNdx < (int)baseResult.size(); baseNdx++)
4830 		{
4831 			const TessLevels& base = baseResult[baseNdx].levels[0];
4832 			if (base.inner[0] == 1.0f || (m_primitiveType == TESSPRIMITIVETYPE_QUADS && base.inner[1] == 1.0f))
4833 				continue;
4834 
4835 			for (int edgeNdx = 0; edgeNdx < numEdges; edgeNdx++)
4836 			{
4837 				TessLevels	levels = base;
4838 				LevelCase	levelCase;
4839 				levelCase.mem = edgeNdx;
4840 
4841 				for (int subCaseNdx = 0; subCaseNdx < numSubCasesPerEdge; subCaseNdx++)
4842 				{
4843 					levelCase.levels.push_back(levels);
4844 
4845 					for (int i = 0; i < DE_LENGTH_OF_ARRAY(levels.outer); i++)
4846 					{
4847 						if (i != edgeNdx)
4848 							levels.outer[i] = rnd.getFloat(2.0f, 16.0f);
4849 					}
4850 
4851 					if (m_primitiveType == TESSPRIMITIVETYPE_TRIANGLES)
4852 						levels.inner[1] = rnd.getFloat(2.0f, 16.0f);
4853 				}
4854 
4855 				result.push_back(levelCase);
4856 			}
4857 		}
4858 
4859 		return result;
4860 	}
4861 
4862 	class IsTriangleTriangleOnOuterEdge
4863 	{
4864 	public:
IsTriangleTriangleOnOuterEdge(int edgeNdx)4865 		IsTriangleTriangleOnOuterEdge (int edgeNdx) : m_edgeNdx(edgeNdx) {}
operator ()(const Vec3 * vertices) const4866 		bool operator() (const Vec3* vertices) const
4867 		{
4868 			bool touchesAppropriateEdge = false;
4869 			for (int v = 0; v < 3; v++)
4870 				if (vertices[v][m_edgeNdx] == 0.0f)
4871 					touchesAppropriateEdge = true;
4872 
4873 			if (touchesAppropriateEdge)
4874 			{
4875 				const Vec3 avg = (vertices[0] + vertices[1] + vertices[2]) / 3.0f;
4876 				return avg[m_edgeNdx] < avg[(m_edgeNdx+1)%3] &&
4877 					   avg[m_edgeNdx] < avg[(m_edgeNdx+2)%3];
4878 			}
4879 			return false;
4880 		}
4881 
4882 	private:
4883 		int m_edgeNdx;
4884 	};
4885 
4886 	class IsQuadTriangleOnOuterEdge
4887 	{
4888 	public:
IsQuadTriangleOnOuterEdge(int edgeNdx)4889 		IsQuadTriangleOnOuterEdge (int edgeNdx) : m_edgeNdx(edgeNdx) {}
4890 
onEdge(const Vec3 & v) const4891 		bool onEdge (const Vec3& v) const
4892 		{
4893 			return v[m_edgeNdx%2] == (m_edgeNdx <= 1 ? 0.0f : 1.0f);
4894 		}
4895 
onAnyEdge(const Vec3 & v)4896 		static inline bool onAnyEdge (const Vec3& v)
4897 		{
4898 			return v[0] == 0.0f || v[0] == 1.0f || v[1] == 0.0f || v[1] == 1.0f;
4899 		}
4900 
operator ()(const Vec3 * vertices) const4901 		bool operator() (const Vec3* vertices) const
4902 		{
4903 			for (int v = 0; v < 3; v++)
4904 			{
4905 				const Vec3& a = vertices[v];
4906 				const Vec3& b = vertices[(v+1)%3];
4907 				const Vec3& c = vertices[(v+2)%3];
4908 				if (onEdge(a) && onEdge(b))
4909 					return true;
4910 				if (onEdge(c) && !onAnyEdge(a) && !onAnyEdge(b) && a[m_edgeNdx%2] == b[m_edgeNdx%2])
4911 					return true;
4912 			}
4913 
4914 			return false;
4915 		}
4916 
4917 	private:
4918 		int m_edgeNdx;
4919 	};
4920 
compare(const vector<Vec3> & coordsA,const vector<Vec3> & coordsB,int outerEdgeNdx) const4921 	virtual bool compare (const vector<Vec3>& coordsA, const vector<Vec3>& coordsB, int outerEdgeNdx) const
4922 	{
4923 		if (m_primitiveType == TESSPRIMITIVETYPE_TRIANGLES)
4924 		{
4925 			return compareTriangleSets(coordsA, coordsB, m_testCtx.getLog(),
4926 									   IsTriangleTriangleOnOuterEdge(outerEdgeNdx),
4927 									   ("inner triangles, and outer triangles corresponding to other edge than edge "
4928 										+ outerEdgeDescriptions(m_primitiveType)[outerEdgeNdx].description()).c_str());
4929 		}
4930 		else if (m_primitiveType == TESSPRIMITIVETYPE_QUADS)
4931 		{
4932 			return compareTriangleSets(coordsA, coordsB, m_testCtx.getLog(),
4933 									   IsQuadTriangleOnOuterEdge(outerEdgeNdx),
4934 									   ("inner triangles, and outer triangles corresponding to other edge than edge "
4935 										+ outerEdgeDescriptions(m_primitiveType)[outerEdgeNdx].description()).c_str());
4936 		}
4937 		else
4938 			DE_ASSERT(false);
4939 
4940 		return true;
4941 	}
4942 };
4943 
4944 /*--------------------------------------------------------------------*//*!
4945  * \brief Base class for testing individual components of tess coords
4946  *
4947  * Useful for testing parts of invariance rule #8.
4948  *//*--------------------------------------------------------------------*/
4949 class TessCoordComponentInvarianceCase : public TestCase
4950 {
4951 public:
TessCoordComponentInvarianceCase(Context & context,const char * name,const char * description,TessPrimitiveType primType,SpacingMode spacing,Winding winding,bool usePointMode)4952 	TessCoordComponentInvarianceCase (Context& context, const char* name, const char* description, TessPrimitiveType primType, SpacingMode spacing, Winding winding, bool usePointMode)
4953 		: TestCase			(context, name, description)
4954 		, m_primitiveType	(primType)
4955 		, m_spacing			(spacing)
4956 		, m_winding			(winding)
4957 		, m_usePointMode	(usePointMode)
4958 	{
4959 	}
4960 
4961 	void									init		(void);
4962 	void									deinit		(void);
4963 	IterateResult							iterate		(void);
4964 
4965 protected:
4966 	virtual string							tessEvalOutputComponentStatements	(const char* tessCoordComponentName, const char* outputComponentName) const = 0;
4967 	virtual bool							checkTessCoordComponent				(float component) const = 0;
4968 
4969 private:
4970 	static vector<float>					genTessLevelCases (int numCases);
4971 
4972 	static const int						RENDER_SIZE = 16;
4973 
4974 	const TessPrimitiveType					m_primitiveType;
4975 	const SpacingMode						m_spacing;
4976 	const Winding							m_winding;
4977 	const bool								m_usePointMode;
4978 
4979 	SharedPtr<const glu::ShaderProgram>		m_program;
4980 };
4981 
init(void)4982 void TessCoordComponentInvarianceCase::init (void)
4983 {
4984 	checkTessellationSupport(m_context);
4985 	checkRenderTargetSize(m_context.getRenderTarget(), RENDER_SIZE);
4986 
4987 	std::string vertexShaderTemplate			("${GLSL_VERSION_DECL}\n"
4988 												 "\n"
4989 												 "in highp float in_v_attr;\n"
4990 												 "out highp float in_tc_attr;\n"
4991 												 "\n"
4992 												 "void main (void)\n"
4993 												 "{\n"
4994 												 "	in_tc_attr = in_v_attr;\n"
4995 												 "}\n");
4996 	std::string tessellationControlTemplate		("${GLSL_VERSION_DECL}\n"
4997 												 "${TESSELLATION_SHADER_REQUIRE}\n"
4998 												 "\n"
4999 												 "layout (vertices = 1) out;\n"
5000 												 "\n"
5001 												 "in highp float in_tc_attr[];\n"
5002 												 "\n"
5003 												 "void main (void)\n"
5004 												 "{\n"
5005 												 "	gl_TessLevelInner[0] = in_tc_attr[0];\n"
5006 												 "	gl_TessLevelInner[1] = in_tc_attr[1];\n"
5007 												 "\n"
5008 												 "	gl_TessLevelOuter[0] = in_tc_attr[2];\n"
5009 												 "	gl_TessLevelOuter[1] = in_tc_attr[3];\n"
5010 												 "	gl_TessLevelOuter[2] = in_tc_attr[4];\n"
5011 												 "	gl_TessLevelOuter[3] = in_tc_attr[5];\n"
5012 												 "}\n");
5013 	std::string tessellationEvaluationTemplate	("${GLSL_VERSION_DECL}\n"
5014 												 "${TESSELLATION_SHADER_REQUIRE}\n"
5015 												 "\n"
5016 												 + getTessellationEvaluationInLayoutString(m_primitiveType, m_spacing, m_winding, m_usePointMode) +
5017 												 "\n"
5018 												 "out highp vec4 in_f_color;\n"
5019 												 "out highp vec3 out_te_output;\n"
5020 												 "\n"
5021 												 "void main (void)\n"
5022 												 "{\n"
5023 												 + tessEvalOutputComponentStatements("gl_TessCoord.x", "out_te_output.x")
5024 												 + tessEvalOutputComponentStatements("gl_TessCoord.y", "out_te_output.y")
5025 
5026 												 + (m_primitiveType == TESSPRIMITIVETYPE_TRIANGLES ?
5027 													tessEvalOutputComponentStatements("gl_TessCoord.z", "out_te_output.z") :
5028 													"	out_te_output.z = 0.0f;\n") +
5029 												 "	gl_Position = vec4(gl_TessCoord.xy, 0.0, 1.0);\n"
5030 												 "	in_f_color = vec4(1.0);\n"
5031 												 "}\n");
5032 	std::string fragmentShaderTemplate			("${GLSL_VERSION_DECL}\n"
5033 												 "\n"
5034 												 "layout (location = 0) out mediump vec4 o_color;\n"
5035 												 "\n"
5036 												 "in highp vec4 in_f_color;\n"
5037 												 "\n"
5038 												 "void main (void)\n"
5039 												 "{\n"
5040 												 "	o_color = in_f_color;\n"
5041 												 "}\n");
5042 
5043 	m_program = SharedPtr<const ShaderProgram>(new ShaderProgram(m_context.getRenderContext(), glu::ProgramSources()
5044 		<< glu::VertexSource					(specializeShader(m_context, vertexShaderTemplate.c_str()))
5045 		<< glu::TessellationControlSource		(specializeShader(m_context, tessellationControlTemplate.c_str()))
5046 		<< glu::TessellationEvaluationSource	(specializeShader(m_context, tessellationEvaluationTemplate.c_str()))
5047 		<< glu::FragmentSource					(specializeShader(m_context, fragmentShaderTemplate.c_str()))
5048 		<< glu::TransformFeedbackVarying		("out_te_output")
5049 		<< glu::TransformFeedbackMode			(GL_INTERLEAVED_ATTRIBS)));
5050 
5051 	m_testCtx.getLog() << *m_program;
5052 	if (!m_program->isOk())
5053 		TCU_FAIL("Program compilation failed");
5054 }
5055 
deinit(void)5056 void TessCoordComponentInvarianceCase::deinit (void)
5057 {
5058 	m_program.clear();
5059 }
5060 
genTessLevelCases(int numCases)5061 vector<float> TessCoordComponentInvarianceCase::genTessLevelCases (int numCases)
5062 {
5063 	de::Random		rnd(123);
5064 	vector<float>	result;
5065 
5066 	for (int i = 0; i < numCases; i++)
5067 		for (int j = 0; j < 6; j++)
5068 			result.push_back(rnd.getFloat(1.0f, 63.0f));
5069 
5070 	return result;
5071 }
5072 
iterate(void)5073 TessCoordComponentInvarianceCase::IterateResult TessCoordComponentInvarianceCase::iterate (void)
5074 {
5075 	typedef TransformFeedbackHandler<Vec3> TFHandler;
5076 
5077 	TestLog&				log					= m_testCtx.getLog();
5078 	const RenderContext&	renderCtx			= m_context.getRenderContext();
5079 	const RandomViewport	viewport			(renderCtx.getRenderTarget(), RENDER_SIZE, RENDER_SIZE, deStringHash(getName()));
5080 	const glw::Functions&	gl					= renderCtx.getFunctions();
5081 	const int				numTessLevelCases	= 32;
5082 	const vector<float>		tessLevels			= genTessLevelCases(numTessLevelCases);
5083 	const deUint32			programGL			= m_program->getProgram();
5084 
5085 	gl.useProgram(programGL);
5086 	setViewport(gl, viewport);
5087 	gl.patchParameteri(GL_PATCH_VERTICES, 6);
5088 
5089 	{
5090 		// Compute the number vertices in the largest draw call, so we can allocate the TF buffer just once.
5091 		int maxNumVerticesInDrawCall = 0;
5092 		for (int i = 0; i < numTessLevelCases; i++)
5093 			maxNumVerticesInDrawCall = de::max(maxNumVerticesInDrawCall, referenceVertexCount(m_primitiveType, m_spacing, m_usePointMode, &tessLevels[6*i+0], &tessLevels[6*i+2]));
5094 
5095 		{
5096 			const TFHandler tfHandler(m_context.getRenderContext(), maxNumVerticesInDrawCall);
5097 
5098 			for (int tessLevelCaseNdx = 0; tessLevelCaseNdx < numTessLevelCases; tessLevelCaseNdx++)
5099 			{
5100 				log << TestLog::Message << "Testing with tessellation levels: " << tessellationLevelsString(&tessLevels[6*tessLevelCaseNdx+0], &tessLevels[6*tessLevelCaseNdx+2]) << TestLog::EndMessage;
5101 
5102 				const glu::VertexArrayBinding bindings[] = { glu::va::Float("in_v_attr", 1, (int)6, 0, &tessLevels[6*tessLevelCaseNdx]) };
5103 				const TFHandler::Result tfResult = tfHandler.renderAndGetPrimitives(programGL, outputPrimitiveTypeGL(m_primitiveType, m_usePointMode),
5104 																					DE_LENGTH_OF_ARRAY(bindings), &bindings[0], 6);
5105 
5106 				for (int vtxNdx = 0; vtxNdx < (int)tfResult.varying.size(); vtxNdx++)
5107 				{
5108 					const Vec3&		vec			= tfResult.varying[vtxNdx];
5109 					const int		numComps	= m_primitiveType == TESSPRIMITIVETYPE_TRIANGLES ? 3 : 2;
5110 
5111 					for (int compNdx = 0; compNdx < numComps; compNdx++)
5112 					{
5113 						if (!checkTessCoordComponent(vec[compNdx]))
5114 						{
5115 							log << TestLog::Message << "Note: output value at index " << vtxNdx << " is "
5116 													<< (m_primitiveType == TESSPRIMITIVETYPE_TRIANGLES ? de::toString(vec) : de::toString(vec.swizzle(0,1)))
5117 													<< TestLog::EndMessage;
5118 							m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid tessellation coordinate component");
5119 							return STOP;
5120 						}
5121 					}
5122 				}
5123 			}
5124 		}
5125 	}
5126 
5127 	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
5128 	return STOP;
5129 }
5130 
5131 /*--------------------------------------------------------------------*//*!
5132  * \brief Test first part of invariance rule #8
5133  *
5134  * Test that all (relevant) components of tess coord are in [0,1].
5135  *//*--------------------------------------------------------------------*/
5136 class TessCoordComponentRangeCase : public TessCoordComponentInvarianceCase
5137 {
5138 public:
TessCoordComponentRangeCase(Context & context,const char * name,const char * description,TessPrimitiveType primType,SpacingMode spacing,Winding winding,bool usePointMode)5139 	TessCoordComponentRangeCase (Context& context, const char* name, const char* description, TessPrimitiveType primType, SpacingMode spacing, Winding winding, bool usePointMode)
5140 		: TessCoordComponentInvarianceCase(context, name, description, primType, spacing, winding, usePointMode)
5141 	{
5142 	}
5143 
5144 protected:
tessEvalOutputComponentStatements(const char * tessCoordComponentName,const char * outputComponentName) const5145 	virtual string tessEvalOutputComponentStatements (const char* tessCoordComponentName, const char* outputComponentName) const
5146 	{
5147 		return string() + "\t" + outputComponentName + " = " + tessCoordComponentName + ";\n";
5148 	}
5149 
checkTessCoordComponent(float component) const5150 	virtual bool checkTessCoordComponent (float component) const
5151 	{
5152 		if (!de::inRange(component, 0.0f, 1.0f))
5153 		{
5154 			m_testCtx.getLog() << TestLog::Message << "Failure: tess coord component isn't in range [0,1]" << TestLog::EndMessage;
5155 			return false;
5156 		}
5157 		return true;
5158 	}
5159 };
5160 
5161 /*--------------------------------------------------------------------*//*!
5162  * \brief Test second part of invariance rule #8
5163  *
5164  * Test that all (relevant) components of tess coord are in [0,1] and
5165  * 1.0-c is exact for every such component c.
5166  *//*--------------------------------------------------------------------*/
5167 class OneMinusTessCoordComponentCase : public TessCoordComponentInvarianceCase
5168 {
5169 public:
OneMinusTessCoordComponentCase(Context & context,const char * name,const char * description,TessPrimitiveType primType,SpacingMode spacing,Winding winding,bool usePointMode)5170 	OneMinusTessCoordComponentCase (Context& context, const char* name, const char* description, TessPrimitiveType primType, SpacingMode spacing, Winding winding, bool usePointMode)
5171 		: TessCoordComponentInvarianceCase(context, name, description, primType, spacing, winding, usePointMode)
5172 	{
5173 	}
5174 
5175 protected:
tessEvalOutputComponentStatements(const char * tessCoordComponentName,const char * outputComponentName) const5176 	virtual string tessEvalOutputComponentStatements (const char* tessCoordComponentName, const char* outputComponentName) const
5177 	{
5178 		return string() + "	{\n"
5179 						  "		float oneMinusComp = 1.0 - " + tessCoordComponentName + ";\n"
5180 						  "		" + outputComponentName + " = " + tessCoordComponentName + " + oneMinusComp;\n"
5181 						  "	}\n";
5182 	}
5183 
checkTessCoordComponent(float component) const5184 	virtual bool checkTessCoordComponent (float component) const
5185 	{
5186 		if (component != 1.0f)
5187 		{
5188 			m_testCtx.getLog() << TestLog::Message << "Failure: comp + (1.0-comp) doesn't equal 1.0 for some component of tessellation coordinate" << TestLog::EndMessage;
5189 			return false;
5190 		}
5191 		return true;
5192 	}
5193 };
5194 
5195 /*--------------------------------------------------------------------*//*!
5196  * \brief Test that patch is discarded if relevant outer level <= 0.0
5197  *
5198  * Draws patches with different combinations of tessellation levels,
5199  * varying which levels are negative. Verifies by checking that colored
5200  * pixels exist inside the area of valid primitives, and only black pixels
5201  * exist inside the area of discarded primitives. An additional sanity
5202  * test is done, checking that the number of primitives written by TF is
5203  * correct.
5204  *//*--------------------------------------------------------------------*/
5205 class PrimitiveDiscardCase : public TestCase
5206 {
5207 public:
PrimitiveDiscardCase(Context & context,const char * name,const char * description,TessPrimitiveType primType,SpacingMode spacing,Winding winding,bool usePointMode)5208 	PrimitiveDiscardCase (Context& context, const char* name, const char* description, TessPrimitiveType primType, SpacingMode spacing, Winding winding, bool usePointMode)
5209 		: TestCase			(context, name, description)
5210 		, m_primitiveType	(primType)
5211 		, m_spacing			(spacing)
5212 		, m_winding			(winding)
5213 		, m_usePointMode	(usePointMode)
5214 	{
5215 	}
5216 
5217 	void									init		(void);
5218 	void									deinit		(void);
5219 	IterateResult							iterate		(void);
5220 
5221 private:
5222 	static vector<float>					genAttributes (void);
5223 
5224 	static const int						RENDER_SIZE = 256;
5225 
5226 	const TessPrimitiveType					m_primitiveType;
5227 	const SpacingMode						m_spacing;
5228 	const Winding							m_winding;
5229 	const bool								m_usePointMode;
5230 
5231 	SharedPtr<const glu::ShaderProgram>		m_program;
5232 };
5233 
init(void)5234 void PrimitiveDiscardCase::init (void)
5235 {
5236 	checkTessellationSupport(m_context);
5237 	checkRenderTargetSize(m_context.getRenderTarget(), RENDER_SIZE);
5238 
5239 	std::string vertexShaderTemplate			("${GLSL_VERSION_DECL}\n"
5240 												 "\n"
5241 												 "in highp float in_v_attr;\n"
5242 												 "out highp float in_tc_attr;\n"
5243 												 "\n"
5244 												 "void main (void)\n"
5245 												 "{\n"
5246 												 "	in_tc_attr = in_v_attr;\n"
5247 												 "}\n");
5248 	std::string tessellationControlTemplate		("${GLSL_VERSION_DECL}\n"
5249 												 "${TESSELLATION_SHADER_REQUIRE}\n"
5250 												 "\n"
5251 												 "layout (vertices = 1) out;\n"
5252 												 "\n"
5253 												 "in highp float in_tc_attr[];\n"
5254 												 "\n"
5255 												 "patch out highp vec2 in_te_positionScale;\n"
5256 												 "patch out highp vec2 in_te_positionOffset;\n"
5257 												 "\n"
5258 												 "void main (void)\n"
5259 												 "{\n"
5260 												 "	in_te_positionScale  = vec2(in_tc_attr[6], in_tc_attr[7]);\n"
5261 												 "	in_te_positionOffset = vec2(in_tc_attr[8], in_tc_attr[9]);\n"
5262 												 "\n"
5263 												 "	gl_TessLevelInner[0] = in_tc_attr[0];\n"
5264 												 "	gl_TessLevelInner[1] = in_tc_attr[1];\n"
5265 												 "\n"
5266 												 "	gl_TessLevelOuter[0] = in_tc_attr[2];\n"
5267 												 "	gl_TessLevelOuter[1] = in_tc_attr[3];\n"
5268 												 "	gl_TessLevelOuter[2] = in_tc_attr[4];\n"
5269 												 "	gl_TessLevelOuter[3] = in_tc_attr[5];\n"
5270 												 "}\n");
5271 	std::string tessellationEvaluationTemplate	("${GLSL_VERSION_DECL}\n"
5272 												 "${TESSELLATION_SHADER_REQUIRE}\n"
5273 												 "\n"
5274 												 + getTessellationEvaluationInLayoutString(m_primitiveType, m_spacing, m_winding, m_usePointMode) +
5275 												 "\n"
5276 												 "patch in highp vec2 in_te_positionScale;\n"
5277 												 "patch in highp vec2 in_te_positionOffset;\n"
5278 												 "\n"
5279 												 "out highp vec3 out_te_tessCoord;\n"
5280 												 "\n"
5281 												 "void main (void)\n"
5282 												 "{\n"
5283 												 "	out_te_tessCoord = gl_TessCoord;\n"
5284 												 "	gl_Position = vec4(gl_TessCoord.xy*in_te_positionScale + in_te_positionOffset, 0.0, 1.0);\n"
5285 												 "}\n");
5286 	std::string fragmentShaderTemplate			("${GLSL_VERSION_DECL}\n"
5287 												 "\n"
5288 												 "layout (location = 0) out mediump vec4 o_color;\n"
5289 												 "\n"
5290 												 "void main (void)\n"
5291 												 "{\n"
5292 												 "	o_color = vec4(1.0);\n"
5293 												 "}\n");
5294 
5295 	m_program = SharedPtr<const ShaderProgram>(new ShaderProgram(m_context.getRenderContext(), glu::ProgramSources()
5296 		<< glu::VertexSource					(specializeShader(m_context, vertexShaderTemplate.c_str()))
5297 		<< glu::TessellationControlSource		(specializeShader(m_context, tessellationControlTemplate.c_str()))
5298 		<< glu::TessellationEvaluationSource	(specializeShader(m_context, tessellationEvaluationTemplate.c_str()))
5299 		<< glu::FragmentSource					(specializeShader(m_context, fragmentShaderTemplate.c_str()))
5300 		<< glu::TransformFeedbackVarying		("out_te_tessCoord")
5301 		<< glu::TransformFeedbackMode			(GL_INTERLEAVED_ATTRIBS)));
5302 
5303 	m_testCtx.getLog() << *m_program;
5304 	if (!m_program->isOk())
5305 		TCU_FAIL("Program compilation failed");
5306 }
5307 
deinit(void)5308 void PrimitiveDiscardCase::deinit (void)
5309 {
5310 	m_program.clear();
5311 }
5312 
genAttributes(void)5313 vector<float> PrimitiveDiscardCase::genAttributes (void)
5314 {
5315 	// Generate input attributes (tessellation levels, and position scale and
5316 	// offset) for a number of primitives. Each primitive has a different
5317 	// combination of tessellatio levels; each level is either a valid
5318 	// value or an "invalid" value (negative or zero, chosen from
5319 	// invalidTessLevelChoices).
5320 
5321 	// \note The attributes are generated in such an order that all of the
5322 	//		 valid attribute tuples come before the first invalid one both
5323 	//		 in the result vector, and when scanning the resulting 2d grid
5324 	//		 of primitives is scanned in y-major order. This makes
5325 	//		 verification somewhat simpler.
5326 
5327 	static const float	baseTessLevels[6]			= { 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f };
5328 	static const float	invalidTessLevelChoices[]	= { -0.42f, 0.0f };
5329 	const int			numChoices					= 1 + DE_LENGTH_OF_ARRAY(invalidTessLevelChoices);
5330 	float				choices[6][numChoices];
5331 	vector<float>		result;
5332 
5333 	for (int levelNdx = 0; levelNdx < 6; levelNdx++)
5334 		for (int choiceNdx = 0; choiceNdx < numChoices; choiceNdx++)
5335 			choices[levelNdx][choiceNdx] = choiceNdx == 0 ? baseTessLevels[levelNdx] : invalidTessLevelChoices[choiceNdx-1];
5336 
5337 	{
5338 		const int	numCols			= intPow(numChoices, 6/2); // sqrt(numChoices**6) == sqrt(number of primitives)
5339 		const int	numRows			= numCols;
5340 		int			index			= 0;
5341 		int			i[6];
5342 		// We could do this with some generic combination-generation function, but meh, it's not that bad.
5343 		for (i[2] = 0; i[2] < numChoices; i[2]++) // First  outer
5344 		for (i[3] = 0; i[3] < numChoices; i[3]++) // Second outer
5345 		for (i[4] = 0; i[4] < numChoices; i[4]++) // Third  outer
5346 		for (i[5] = 0; i[5] < numChoices; i[5]++) // Fourth outer
5347 		for (i[0] = 0; i[0] < numChoices; i[0]++) // First  inner
5348 		for (i[1] = 0; i[1] < numChoices; i[1]++) // Second inner
5349 		{
5350 			for (int j = 0; j < 6; j++)
5351 				result.push_back(choices[j][i[j]]);
5352 
5353 			{
5354 				const int col = index % numCols;
5355 				const int row = index / numCols;
5356 				// Position scale.
5357 				result.push_back((float)2.0f / (float)numCols);
5358 				result.push_back((float)2.0f / (float)numRows);
5359 				// Position offset.
5360 				result.push_back((float)col / (float)numCols * 2.0f - 1.0f);
5361 				result.push_back((float)row / (float)numRows * 2.0f - 1.0f);
5362 			}
5363 
5364 			index++;
5365 		}
5366 	}
5367 
5368 	return result;
5369 }
5370 
iterate(void)5371 PrimitiveDiscardCase::IterateResult PrimitiveDiscardCase::iterate (void)
5372 {
5373 	typedef TransformFeedbackHandler<Vec3> TFHandler;
5374 
5375 	TestLog&				log						= m_testCtx.getLog();
5376 	const RenderContext&	renderCtx				= m_context.getRenderContext();
5377 	const RandomViewport	viewport				(renderCtx.getRenderTarget(), RENDER_SIZE, RENDER_SIZE, deStringHash(getName()));
5378 	const glw::Functions&	gl						= renderCtx.getFunctions();
5379 	const vector<float>		attributes				= genAttributes();
5380 	const int				numAttribsPerPrimitive	= 6+2+2; // Tess levels, scale, offset.
5381 	const int				numPrimitives			= (int)attributes.size() / numAttribsPerPrimitive;
5382 	const deUint32			programGL				= m_program->getProgram();
5383 
5384 	gl.useProgram(programGL);
5385 	setViewport(gl, viewport);
5386 	gl.patchParameteri(GL_PATCH_VERTICES, numAttribsPerPrimitive);
5387 
5388 	gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
5389 	gl.clear(GL_COLOR_BUFFER_BIT);
5390 
5391 	// Check the convenience assertion that all discarded patches come after the last non-discarded patch.
5392 	{
5393 		bool discardedPatchEncountered = false;
5394 		for (int patchNdx = 0; patchNdx < numPrimitives; patchNdx++)
5395 		{
5396 			const bool discard = isPatchDiscarded(m_primitiveType, &attributes[numAttribsPerPrimitive*patchNdx + 2]);
5397 			DE_ASSERT(discard || !discardedPatchEncountered);
5398 			discardedPatchEncountered = discard;
5399 		}
5400 		DE_UNREF(discardedPatchEncountered);
5401 	}
5402 
5403 	{
5404 		int numVerticesInDrawCall = 0;
5405 		for (int patchNdx = 0; patchNdx < numPrimitives; patchNdx++)
5406 			numVerticesInDrawCall += referenceVertexCount(m_primitiveType, m_spacing, m_usePointMode, &attributes[numAttribsPerPrimitive*patchNdx+0], &attributes[numAttribsPerPrimitive*patchNdx+2]);
5407 
5408 		log << TestLog::Message << "Note: rendering " << numPrimitives << " patches; first patches have valid relevant outer levels, "
5409 								<< "but later patches have one or more invalid (i.e. less than or equal to 0.0) relevant outer levels" << TestLog::EndMessage;
5410 
5411 		{
5412 			const TFHandler					tfHandler	(m_context.getRenderContext(), numVerticesInDrawCall);
5413 			const glu::VertexArrayBinding	bindings[]	= { glu::va::Float("in_v_attr", 1, (int)attributes.size(), 0, &attributes[0]) };
5414 			const TFHandler::Result			tfResult	= tfHandler.renderAndGetPrimitives(programGL, outputPrimitiveTypeGL(m_primitiveType, m_usePointMode),
5415 																						   DE_LENGTH_OF_ARRAY(bindings), &bindings[0], (int)attributes.size());
5416 			const tcu::Surface				pixels		= getPixels(renderCtx, viewport);
5417 
5418 			log << TestLog::Image("RenderedImage", "Rendered image", pixels);
5419 
5420 			if ((int)tfResult.varying.size() != numVerticesInDrawCall)
5421 			{
5422 				log << TestLog::Message << "Failure: expected " << numVerticesInDrawCall << " vertices from transform feedback, got " << tfResult.varying.size() << TestLog::EndMessage;
5423 				m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Wrong number of tessellation coordinates");
5424 				return STOP;
5425 			}
5426 
5427 			// Check that white pixels are found around every non-discarded
5428 			// patch, and that only black pixels are found after the last
5429 			// non-discarded patch.
5430 			{
5431 				int lastWhitePixelRow									= 0;
5432 				int secondToLastWhitePixelRow							= 0;
5433 				int	lastWhitePixelColumnOnSecondToLastWhitePixelRow		= 0;
5434 
5435 				for (int patchNdx = 0; patchNdx < numPrimitives; patchNdx++)
5436 				{
5437 					const float* const	attr			= &attributes[numAttribsPerPrimitive*patchNdx];
5438 					const bool			validLevels		= !isPatchDiscarded(m_primitiveType, &attr[2]);
5439 
5440 					if (validLevels)
5441 					{
5442 						// Not a discarded patch; check that at least one white pixel is found in its area.
5443 
5444 						const float* const	scale		= &attr[6];
5445 						const float* const	offset		= &attr[8];
5446 						const int			x0			= (int)((			offset[0] + 1.0f)*0.5f*(float)pixels.getWidth()) - 1;
5447 						const int			x1			= (int)((scale[0] + offset[0] + 1.0f)*0.5f*(float)pixels.getWidth()) + 1;
5448 						const int			y0			= (int)((			offset[1] + 1.0f)*0.5f*(float)pixels.getHeight()) - 1;
5449 						const int			y1			= (int)((scale[1] + offset[1] + 1.0f)*0.5f*(float)pixels.getHeight()) + 1;
5450 						const bool			isMSAA		= renderCtx.getRenderTarget().getNumSamples() > 1;
5451 						bool				pixelOk		= false;
5452 
5453 						if (y1 > lastWhitePixelRow)
5454 						{
5455 							secondToLastWhitePixelRow	= lastWhitePixelRow;
5456 							lastWhitePixelRow			= y1;
5457 						}
5458 						lastWhitePixelColumnOnSecondToLastWhitePixelRow = x1;
5459 
5460 						for (int y = y0; y <= y1 && !pixelOk; y++)
5461 						for (int x = x0; x <= x1 && !pixelOk; x++)
5462 						{
5463 							if (!de::inBounds(x, 0, pixels.getWidth()) || !de::inBounds(y, 0, pixels.getHeight()))
5464 								continue;
5465 
5466 							if (isMSAA)
5467 							{
5468 								if (pixels.getPixel(x, y) != tcu::RGBA::black())
5469 									pixelOk = true;
5470 							}
5471 							else
5472 							{
5473 								if (pixels.getPixel(x, y) == tcu::RGBA::white())
5474 									pixelOk = true;
5475 							}
5476 						}
5477 
5478 						if (!pixelOk)
5479 						{
5480 							log << TestLog::Message << "Failure: expected at least one " << (isMSAA ? "non-black" : "white") << " pixel in the rectangle "
5481 													<< "[x0=" << x0 << ", y0=" << y0 << ", x1=" << x1 << ", y1=" << y1 << "]" << TestLog::EndMessage
5482 								<< TestLog::Message << "Note: the rectangle approximately corresponds to the patch with these tessellation levels: "
5483 													<< tessellationLevelsString(&attr[0], &attr[1]) << TestLog::EndMessage;
5484 							m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image verification failed");
5485 							return STOP;
5486 						}
5487 					}
5488 					else
5489 					{
5490 						// First discarded primitive patch; the remaining are guaranteed to be discarded ones as well.
5491 
5492 						for (int y = 0; y < pixels.getHeight(); y++)
5493 						for (int x = 0; x < pixels.getWidth(); x++)
5494 						{
5495 							if (y > lastWhitePixelRow || (y > secondToLastWhitePixelRow && x > lastWhitePixelColumnOnSecondToLastWhitePixelRow))
5496 							{
5497 								if (pixels.getPixel(x, y) != tcu::RGBA::black())
5498 								{
5499 									log << TestLog::Message << "Failure: expected all pixels to be black in the area "
5500 															<< (lastWhitePixelColumnOnSecondToLastWhitePixelRow < pixels.getWidth()-1
5501 																	? string() + "y > " + de::toString(lastWhitePixelRow) + " || (y > " + de::toString(secondToLastWhitePixelRow)
5502 																			   + " && x > " + de::toString(lastWhitePixelColumnOnSecondToLastWhitePixelRow) + ")"
5503 																	: string() + "y > " + de::toString(lastWhitePixelRow))
5504 															<< " (they all correspond to patches that should be discarded)" << TestLog::EndMessage
5505 										<< TestLog::Message << "Note: pixel " << tcu::IVec2(x, y) << " isn't black" << TestLog::EndMessage;
5506 									m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image verification failed");
5507 									return STOP;
5508 								}
5509 							}
5510 						}
5511 
5512 						break;
5513 					}
5514 				}
5515 			}
5516 		}
5517 	}
5518 
5519 	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
5520 	return STOP;
5521 }
5522 
5523 /*--------------------------------------------------------------------*//*!
5524  * \brief Case testing user-defined IO between TCS and TES
5525  *
5526  * TCS outputs various values to TES, including aggregates. The outputs
5527  * can be per-patch or per-vertex, and if per-vertex, they can also be in
5528  * an IO block. Per-vertex input array size can be left implicit (i.e.
5529  * inputArray[]) or explicit either by gl_MaxPatchVertices or an integer
5530  * literal whose value is queried from GL.
5531  *
5532  * The values output are generated in TCS and verified in TES against
5533  * similarly generated values. In case a verification of a value fails, the
5534  * index of the invalid value is output with TF.
5535  * As a sanity check, also the rendering result is verified (against pre-
5536  * rendered reference).
5537  *//*--------------------------------------------------------------------*/
5538 class UserDefinedIOCase : public TestCase
5539 {
5540 public:
5541 	enum IOType
5542 	{
5543 		IO_TYPE_PER_PATCH = 0,
5544 		IO_TYPE_PER_PATCH_ARRAY,
5545 		IO_TYPE_PER_PATCH_BLOCK,
5546 		IO_TYPE_PER_PATCH_BLOCK_ARRAY,
5547 		IO_TYPE_PER_VERTEX,
5548 		IO_TYPE_PER_VERTEX_BLOCK,
5549 
5550 		IO_TYPE_LAST
5551 	};
5552 
5553 	enum VertexIOArraySize
5554 	{
5555 		VERTEX_IO_ARRAY_SIZE_IMPLICIT = 0,
5556 		VERTEX_IO_ARRAY_SIZE_EXPLICIT_SHADER_BUILTIN,		//!< Use gl_MaxPatchVertices as size for per-vertex input array.
5557 		VERTEX_IO_ARRAY_SIZE_EXPLICIT_QUERY,				//!< Query GL_MAX_PATCH_VERTICES, and use that as size for per-vertex input array.
5558 
5559 		VERTEX_IO_ARRAY_SIZE_LAST
5560 	};
5561 
5562 	enum TessControlOutArraySize
5563 	{
5564 		TESS_CONTROL_OUT_ARRAY_SIZE_IMPLICIT = 0,
5565 		TESS_CONTROL_OUT_ARRAY_SIZE_LAYOUT,
5566 		TESS_CONTROL_OUT_ARRAY_SIZE_QUERY,
5567 		TESS_CONTROL_OUT_ARRAY_SIZE_SHADER_BUILTIN
5568 	};
5569 
UserDefinedIOCase(Context & context,const char * name,const char * description,TessPrimitiveType primType,IOType ioType,VertexIOArraySize vertexIOArraySize,TessControlOutArraySize tessControlOutArraySize,const char * referenceImagePath)5570 	UserDefinedIOCase (Context& context, const char* name, const char* description, TessPrimitiveType primType, IOType ioType, VertexIOArraySize vertexIOArraySize, TessControlOutArraySize tessControlOutArraySize, const char* referenceImagePath)
5571 		: TestCase					(context, name, description)
5572 		, m_primitiveType			(primType)
5573 		, m_ioType					(ioType)
5574 		, m_vertexIOArraySize		(vertexIOArraySize)
5575 		, m_tessControlOutArraySize	(tessControlOutArraySize)
5576 		, m_referenceImagePath		(referenceImagePath)
5577 	{
5578 	}
5579 
5580 	void									init		(void);
5581 	void									deinit		(void);
5582 	IterateResult							iterate		(void);
5583 
5584 private:
5585 	typedef string (*BasicTypeVisitFunc)(const string& name, glu::DataType type, int indentationDepth); //!< See glslTraverseBasicTypes below.
5586 
5587 	class TopLevelObject
5588 	{
5589 	public:
~TopLevelObject(void)5590 		virtual			~TopLevelObject					(void) {}
5591 
5592 		virtual string	name							(void) const = 0;
5593 		virtual string	declare							(void) const = 0;
5594 		virtual string	declareArray					(const string& arraySizeExpr) const = 0;
5595 		virtual string	glslTraverseBasicTypeArray		(int numArrayElements, //!< If negative, traverse just array[gl_InvocationID], not all indices.
5596 														 int indentationDepth,
5597 														 BasicTypeVisitFunc) const = 0;
5598 		virtual string	glslTraverseBasicType			(int indentationDepth,
5599 														 BasicTypeVisitFunc) const = 0;
5600 		virtual int		numBasicSubobjectsInElementType	(void) const = 0;
5601 		virtual string	basicSubobjectAtIndex			(int index, int arraySize) const = 0;
5602 	};
5603 
5604 	class Variable : public TopLevelObject
5605 	{
5606 	public:
Variable(const string & name_,const glu::VarType & type,bool isArray)5607 		Variable (const string& name_, const glu::VarType& type, bool isArray)
5608 			: m_name		(name_)
5609 			, m_type		(type)
5610 			, m_isArray		(isArray)
5611 		{
5612 			DE_ASSERT(!type.isArrayType());
5613 		}
5614 
name(void) const5615 		string	name								(void) const { return m_name; }
5616 		string	declare								(void) const;
5617 		string	declareArray						(const string& arraySizeExpr) const;
5618 		string	glslTraverseBasicTypeArray			(int numArrayElements, int indentationDepth, BasicTypeVisitFunc) const;
5619 		string	glslTraverseBasicType				(int indentationDepth, BasicTypeVisitFunc) const;
5620 		int		numBasicSubobjectsInElementType		(void) const;
5621 		string	basicSubobjectAtIndex				(int index, int arraySize) const;
5622 
5623 	private:
5624 		string			m_name;
5625 		glu::VarType	m_type; //!< If this Variable is an array element, m_type is the element type; otherwise just the variable type.
5626 		const bool		m_isArray;
5627 	};
5628 
5629 	class IOBlock : public TopLevelObject
5630 	{
5631 	public:
5632 		struct Member
5633 		{
5634 			string			name;
5635 			glu::VarType	type;
Memberdeqp::gles31::Functional::__anon4a9088cf0211::UserDefinedIOCase::IOBlock::Member5636 			Member (const string& n, const glu::VarType& t) : name(n), type(t) {}
5637 		};
5638 
IOBlock(const string & blockName,const string & interfaceName,const vector<Member> & members)5639 		IOBlock (const string& blockName, const string& interfaceName, const vector<Member>& members)
5640 			: m_blockName		(blockName)
5641 			, m_interfaceName	(interfaceName)
5642 			, m_members			(members)
5643 		{
5644 		}
5645 
name(void) const5646 		string	name								(void) const { return m_interfaceName; }
5647 		string	declare								(void) const;
5648 		string	declareArray						(const string& arraySizeExpr) const;
5649 		string	glslTraverseBasicTypeArray			(int numArrayElements, int indentationDepth, BasicTypeVisitFunc) const;
5650 		string	glslTraverseBasicType				(int indentationDepth, BasicTypeVisitFunc) const;
5651 		int		numBasicSubobjectsInElementType		(void) const;
5652 		string	basicSubobjectAtIndex				(int index, int arraySize) const;
5653 
5654 	private:
5655 		string			m_blockName;
5656 		string			m_interfaceName;
5657 		vector<Member>	m_members;
5658 	};
5659 
5660 	static string							glslTraverseBasicTypes				(const string&			rootName,
5661 																				 const glu::VarType&	rootType,
5662 																				 int					arrayNestingDepth,
5663 																				 int					indentationDepth,
5664 																				 BasicTypeVisitFunc		visit);
5665 
5666 	static string							glslAssignBasicTypeObject			(const string& name, glu::DataType, int indentationDepth);
5667 	static string							glslCheckBasicTypeObject			(const string& name, glu::DataType, int indentationDepth);
5668 	static int								numBasicSubobjectsInElementType		(const vector<SharedPtr<TopLevelObject> >&);
5669 	static string							basicSubobjectAtIndex				(int index, const vector<SharedPtr<TopLevelObject> >&, int topLevelArraySizes);
5670 
5671 	enum
5672 	{
5673 		RENDER_SIZE = 256
5674 	};
5675 	enum
5676 	{
5677 		NUM_OUTPUT_VERTICES = 5
5678 	};
5679 	enum
5680 	{
5681 		NUM_PER_PATCH_ARRAY_ELEMS = 3
5682 	};
5683 	enum
5684 	{
5685 		NUM_PER_PATCH_BLOCKS = 2
5686 	};
5687 
5688 	const TessPrimitiveType					m_primitiveType;
5689 	const IOType							m_ioType;
5690 	const VertexIOArraySize					m_vertexIOArraySize;
5691 	const TessControlOutArraySize			m_tessControlOutArraySize;
5692 	const string							m_referenceImagePath;
5693 
5694 	vector<glu::StructType>					m_structTypes;
5695 	vector<SharedPtr<TopLevelObject> >		m_tcsOutputs;
5696 	vector<SharedPtr<TopLevelObject> >		m_tesInputs;
5697 
5698 	SharedPtr<const glu::ShaderProgram>		m_program;
5699 };
5700 
5701 /*--------------------------------------------------------------------*//*!
5702  * \brief Generate GLSL code to traverse (possibly aggregate) object
5703  *
5704  * Generates a string that represents GLSL code that traverses the
5705  * basic-type subobjects in a rootType-typed object named rootName. Arrays
5706  * are traversed with loops and struct members are each traversed
5707  * separately. The code for each basic-type subobject is generated with
5708  * the function given as the 'visit' argument.
5709  *//*--------------------------------------------------------------------*/
glslTraverseBasicTypes(const string & rootName,const glu::VarType & rootType,int arrayNestingDepth,int indentationDepth,BasicTypeVisitFunc visit)5710 string UserDefinedIOCase::glslTraverseBasicTypes (const string&			rootName,
5711 												  const glu::VarType&	rootType,
5712 												  int					arrayNestingDepth,
5713 												  int					indentationDepth,
5714 												  BasicTypeVisitFunc	visit)
5715 {
5716 	if (rootType.isBasicType())
5717 		return visit(rootName, rootType.getBasicType(), indentationDepth);
5718 	else if (rootType.isArrayType())
5719 	{
5720 		const string indentation	= string(indentationDepth, '\t');
5721 		const string loopIndexName	= "i" + de::toString(arrayNestingDepth);
5722 		const string arrayLength	= de::toString(rootType.getArraySize());
5723 		return indentation + "for (int " + loopIndexName + " = 0; " + loopIndexName + " < " + de::toString(rootType.getArraySize()) + "; " + loopIndexName + "++)\n" +
5724 			   indentation + "{\n" +
5725 			   glslTraverseBasicTypes(rootName + "[" + loopIndexName + "]", rootType.getElementType(), arrayNestingDepth+1, indentationDepth+1, visit) +
5726 			   indentation + "}\n";
5727 	}
5728 	else if (rootType.isStructType())
5729 	{
5730 		const glu::StructType&	structType = *rootType.getStructPtr();
5731 		const int				numMembers = structType.getNumMembers();
5732 		string					result;
5733 
5734 		for (int membNdx = 0; membNdx < numMembers; membNdx++)
5735 		{
5736 			const glu::StructMember& member = structType.getMember(membNdx);
5737 			result += glslTraverseBasicTypes(rootName + "." + member.getName(), member.getType(), arrayNestingDepth, indentationDepth, visit);
5738 		}
5739 
5740 		return result;
5741 	}
5742 	else
5743 	{
5744 		DE_ASSERT(false);
5745 		return DE_NULL;
5746 	}
5747 }
5748 
declare(void) const5749 string UserDefinedIOCase::Variable::declare (void) const
5750 {
5751 	DE_ASSERT(!m_isArray);
5752 	return de::toString(glu::declare(m_type, m_name)) + ";\n";
5753 }
5754 
declareArray(const string & sizeExpr) const5755 string UserDefinedIOCase::Variable::declareArray (const string& sizeExpr) const
5756 {
5757 	DE_ASSERT(m_isArray);
5758 	return de::toString(glu::declare(m_type, m_name)) + "[" + sizeExpr + "];\n";
5759 }
5760 
declare(void) const5761 string UserDefinedIOCase::IOBlock::declare (void) const
5762 {
5763 	std::ostringstream buf;
5764 
5765 	buf << m_blockName << "\n"
5766 		<< "{\n";
5767 
5768 	for (int i = 0; i < (int)m_members.size(); i++)
5769 		buf << "\t" << glu::declare(m_members[i].type, m_members[i].name) << ";\n";
5770 
5771 	buf << "} " << m_interfaceName << ";\n";
5772 	return buf.str();
5773 }
5774 
declareArray(const string & sizeExpr) const5775 string UserDefinedIOCase::IOBlock::declareArray (const string& sizeExpr) const
5776 {
5777 	std::ostringstream buf;
5778 
5779 	buf << m_blockName << "\n"
5780 		<< "{\n";
5781 
5782 	for (int i = 0; i < (int)m_members.size(); i++)
5783 		buf << "\t" << glu::declare(m_members[i].type, m_members[i].name) << ";\n";
5784 
5785 	buf << "} " << m_interfaceName << "[" << sizeExpr << "];\n";
5786 	return buf.str();
5787 }
5788 
glslTraverseBasicTypeArray(int numArrayElements,int indentationDepth,BasicTypeVisitFunc visit) const5789 string UserDefinedIOCase::Variable::glslTraverseBasicTypeArray (int numArrayElements, int indentationDepth, BasicTypeVisitFunc visit) const
5790 {
5791 	DE_ASSERT(m_isArray);
5792 
5793 	const bool				traverseAsArray		= numArrayElements >= 0;
5794 	const string			traversedName		= m_name + (!traverseAsArray ? "[gl_InvocationID]" : "");
5795 	const glu::VarType		type				= traverseAsArray ? glu::VarType(m_type, numArrayElements) : m_type;
5796 
5797 	return UserDefinedIOCase::glslTraverseBasicTypes(traversedName, type, 0, indentationDepth, visit);
5798 }
5799 
glslTraverseBasicType(int indentationDepth,BasicTypeVisitFunc visit) const5800 string UserDefinedIOCase::Variable::glslTraverseBasicType (int indentationDepth, BasicTypeVisitFunc visit) const
5801 {
5802 	DE_ASSERT(!m_isArray);
5803 
5804 	return UserDefinedIOCase::glslTraverseBasicTypes(m_name, m_type, 0, indentationDepth, visit);
5805 }
5806 
glslTraverseBasicTypeArray(int numArrayElements,int indentationDepth,BasicTypeVisitFunc visit) const5807 string UserDefinedIOCase::IOBlock::glslTraverseBasicTypeArray (int numArrayElements, int indentationDepth, BasicTypeVisitFunc visit) const
5808 {
5809 	if (numArrayElements >= 0)
5810 	{
5811 		const string	indentation			= string(indentationDepth, '\t');
5812 		string			result				= indentation + "for (int i0 = 0; i0 < " + de::toString(numArrayElements) + "; i0++)\n" +
5813 											  indentation + "{\n";
5814 		for (int i = 0; i < (int)m_members.size(); i++)
5815 			result += UserDefinedIOCase::glslTraverseBasicTypes(m_interfaceName + "[i0]." + m_members[i].name, m_members[i].type, 1, indentationDepth+1, visit);
5816 		result += indentation + "}\n";
5817 		return result;
5818 	}
5819 	else
5820 	{
5821 		string result;
5822 		for (int i = 0; i < (int)m_members.size(); i++)
5823 			result += UserDefinedIOCase::glslTraverseBasicTypes(m_interfaceName + "[gl_InvocationID]." + m_members[i].name, m_members[i].type, 0, indentationDepth, visit);
5824 		return result;
5825 	}
5826 }
5827 
5828 
glslTraverseBasicType(int indentationDepth,BasicTypeVisitFunc visit) const5829 string UserDefinedIOCase::IOBlock::glslTraverseBasicType (int indentationDepth, BasicTypeVisitFunc visit) const
5830 {
5831 	string result;
5832 	for (int i = 0; i < (int)m_members.size(); i++)
5833 		result += UserDefinedIOCase::glslTraverseBasicTypes(m_interfaceName + "." + m_members[i].name, m_members[i].type, 0, indentationDepth, visit);
5834 	return result;
5835 }
5836 
numBasicSubobjectsInElementType(void) const5837 int UserDefinedIOCase::Variable::numBasicSubobjectsInElementType (void) const
5838 {
5839 	return numBasicSubobjects(m_type);
5840 }
5841 
numBasicSubobjectsInElementType(void) const5842 int UserDefinedIOCase::IOBlock::numBasicSubobjectsInElementType (void) const
5843 {
5844 	int result = 0;
5845 	for (int i = 0; i < (int)m_members.size(); i++)
5846 		result += numBasicSubobjects(m_members[i].type);
5847 	return result;
5848 }
5849 
basicSubobjectAtIndex(int subobjectIndex,int arraySize) const5850 string UserDefinedIOCase::Variable::basicSubobjectAtIndex (int subobjectIndex, int arraySize) const
5851 {
5852 	const glu::VarType	type			= m_isArray ? glu::VarType(m_type, arraySize) : m_type;
5853 	int					currentIndex	= 0;
5854 
5855 	for (glu::BasicTypeIterator basicIt = glu::BasicTypeIterator::begin(&type);
5856 		 basicIt != glu::BasicTypeIterator::end(&type);
5857 		 ++basicIt)
5858 	{
5859 		if (currentIndex == subobjectIndex)
5860 			return m_name + de::toString(glu::TypeAccessFormat(type, basicIt.getPath()));
5861 		currentIndex++;
5862 	}
5863 	DE_ASSERT(false);
5864 	return DE_NULL;
5865 }
5866 
basicSubobjectAtIndex(int subobjectIndex,int arraySize) const5867 string UserDefinedIOCase::IOBlock::basicSubobjectAtIndex (int subobjectIndex, int arraySize) const
5868 {
5869 	int currentIndex = 0;
5870 	for (int arrayNdx = 0; arrayNdx < arraySize; arrayNdx++)
5871 	{
5872 		for (int memberNdx = 0; memberNdx < (int)m_members.size(); memberNdx++)
5873 		{
5874 			const glu::VarType& membType = m_members[memberNdx].type;
5875 			for (glu::BasicTypeIterator basicIt = glu::BasicTypeIterator::begin(&membType);
5876 				 basicIt != glu::BasicTypeIterator::end(&membType);
5877 				 ++basicIt)
5878 			{
5879 				if (currentIndex == subobjectIndex)
5880 					return m_interfaceName + "[" + de::toString(arrayNdx) + "]." + m_members[memberNdx].name + de::toString(glu::TypeAccessFormat(membType, basicIt.getPath()));
5881 				currentIndex++;
5882 			}
5883 		}
5884 	}
5885 	DE_ASSERT(false);
5886 	return DE_NULL;
5887 }
5888 
5889 // Used as the 'visit' argument for glslTraverseBasicTypes.
glslAssignBasicTypeObject(const string & name,glu::DataType type,int indentationDepth)5890 string UserDefinedIOCase::glslAssignBasicTypeObject (const string& name, glu::DataType type, int indentationDepth)
5891 {
5892 	const int		scalarSize		= glu::getDataTypeScalarSize(type);
5893 	const string	indentation		= string(indentationDepth, '\t');
5894 	string			result;
5895 
5896 	result += indentation + name + " = ";
5897 
5898 	if (type != glu::TYPE_FLOAT)
5899 		result += string() + glu::getDataTypeName(type) + "(";
5900 	for (int i = 0; i < scalarSize; i++)
5901 		result += (i > 0 ? ", v+" + de::floatToString(0.8f*(float)i, 1)
5902 						 : "v");
5903 	if (type != glu::TYPE_FLOAT)
5904 		result += ")";
5905 	result += ";\n" +
5906 			  indentation + "v += 0.4;\n";
5907 	return result;
5908 }
5909 
5910 // Used as the 'visit' argument for glslTraverseBasicTypes.
glslCheckBasicTypeObject(const string & name,glu::DataType type,int indentationDepth)5911 string UserDefinedIOCase::glslCheckBasicTypeObject (const string& name, glu::DataType type, int indentationDepth)
5912 {
5913 	const int		scalarSize		= glu::getDataTypeScalarSize(type);
5914 	const string	indentation		= string(indentationDepth, '\t');
5915 	string			result;
5916 
5917 	result += indentation + "allOk = allOk && compare_" + glu::getDataTypeName(type) + "(" + name + ", ";
5918 
5919 	if (type != glu::TYPE_FLOAT)
5920 		result += string() + glu::getDataTypeName(type) + "(";
5921 	for (int i = 0; i < scalarSize; i++)
5922 		result += (i > 0 ? ", v+" + de::floatToString(0.8f*(float)i, 1)
5923 						 : "v");
5924 	if (type != glu::TYPE_FLOAT)
5925 		result += ")";
5926 	result += ");\n" +
5927 			  indentation + "v += 0.4;\n" +
5928 			  indentation + "if (allOk) firstFailedInputIndex++;\n";
5929 
5930 	return result;
5931 }
5932 
numBasicSubobjectsInElementType(const vector<SharedPtr<TopLevelObject>> & objects)5933 int UserDefinedIOCase::numBasicSubobjectsInElementType (const vector<SharedPtr<TopLevelObject> >& objects)
5934 {
5935 	int result = 0;
5936 	for (int i = 0; i < (int)objects.size(); i++)
5937 		result += objects[i]->numBasicSubobjectsInElementType();
5938 	return result;
5939 }
5940 
basicSubobjectAtIndex(int subobjectIndex,const vector<SharedPtr<TopLevelObject>> & objects,int topLevelArraySize)5941 string UserDefinedIOCase::basicSubobjectAtIndex (int subobjectIndex, const vector<SharedPtr<TopLevelObject> >& objects, int topLevelArraySize)
5942 {
5943 	int currentIndex	= 0;
5944 	int objectIndex		= 0;
5945 	for (; currentIndex < subobjectIndex; objectIndex++)
5946 		currentIndex += objects[objectIndex]->numBasicSubobjectsInElementType() * topLevelArraySize;
5947 	if (currentIndex > subobjectIndex)
5948 	{
5949 		objectIndex--;
5950 		currentIndex -= objects[objectIndex]->numBasicSubobjectsInElementType() * topLevelArraySize;
5951 	}
5952 
5953 	return objects[objectIndex]->basicSubobjectAtIndex(subobjectIndex - currentIndex, topLevelArraySize);
5954 }
5955 
init(void)5956 void UserDefinedIOCase::init (void)
5957 {
5958 	checkTessellationSupport(m_context);
5959 	checkRenderTargetSize(m_context.getRenderTarget(), RENDER_SIZE);
5960 
5961 	const bool			isPerPatchIO				= m_ioType == IO_TYPE_PER_PATCH				||
5962 													  m_ioType == IO_TYPE_PER_PATCH_ARRAY		||
5963 													  m_ioType == IO_TYPE_PER_PATCH_BLOCK		||
5964 													  m_ioType == IO_TYPE_PER_PATCH_BLOCK_ARRAY;
5965 
5966 	const bool			isExplicitVertexArraySize	= m_vertexIOArraySize == VERTEX_IO_ARRAY_SIZE_EXPLICIT_SHADER_BUILTIN ||
5967 													  m_vertexIOArraySize == VERTEX_IO_ARRAY_SIZE_EXPLICIT_QUERY;
5968 
5969 	const string		vertexAttrArrayInputSize	= m_vertexIOArraySize == VERTEX_IO_ARRAY_SIZE_IMPLICIT					? ""
5970 													: m_vertexIOArraySize == VERTEX_IO_ARRAY_SIZE_EXPLICIT_SHADER_BUILTIN	? "gl_MaxPatchVertices"
5971 													: m_vertexIOArraySize == VERTEX_IO_ARRAY_SIZE_EXPLICIT_QUERY			? de::toString(m_context.getContextInfo().getInt(GL_MAX_PATCH_VERTICES))
5972 													: DE_NULL;
5973 
5974 	const char* const	maybePatch					= isPerPatchIO ? "patch " : "";
5975 	const string		outMaybePatch				= string() + maybePatch + "out ";
5976 	const string		inMaybePatch				= string() + maybePatch + "in ";
5977 	const bool			useBlock					= m_ioType == IO_TYPE_PER_VERTEX_BLOCK		||
5978 													  m_ioType == IO_TYPE_PER_PATCH_BLOCK		||
5979 													  m_ioType == IO_TYPE_PER_PATCH_BLOCK_ARRAY;
5980 
5981 	string				tcsDeclarations;
5982 	string				tcsStatements;
5983 
5984 	string				tesDeclarations;
5985 	string				tesStatements;
5986 
5987 	{
5988 		m_structTypes.push_back(glu::StructType("S"));
5989 
5990 		const glu::VarType	highpFloat		(glu::TYPE_FLOAT, glu::PRECISION_HIGHP);
5991 		glu::StructType&	structType		= m_structTypes.back();
5992 		const glu::VarType	structVarType	(&structType);
5993 		bool				usedStruct		= false;
5994 
5995 		structType.addMember("x", glu::VarType(glu::TYPE_INT, glu::PRECISION_HIGHP));
5996 		structType.addMember("y", glu::VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_HIGHP));
5997 
5998 		if (useBlock)
5999 		{
6000 			// It is illegal to have a structure containing an array as an output variable
6001 			structType.addMember("z", glu::VarType(highpFloat, 2));
6002 		}
6003 
6004 		if (useBlock)
6005 		{
6006 			const bool				useLightweightBlock = (m_ioType == IO_TYPE_PER_PATCH_BLOCK_ARRAY); // use leaner block to make sure it is not larger than allowed (per-patch storage is very limited)
6007 			vector<IOBlock::Member>	blockMembers;
6008 
6009 			if (!useLightweightBlock)
6010 				blockMembers.push_back(IOBlock::Member("blockS",	structVarType));
6011 
6012 			blockMembers.push_back(IOBlock::Member("blockFa",	glu::VarType(highpFloat, 3)));
6013 			blockMembers.push_back(IOBlock::Member("blockSa",	glu::VarType(structVarType, 2)));
6014 			blockMembers.push_back(IOBlock::Member("blockF",	highpFloat));
6015 
6016 			m_tcsOutputs.push_back	(SharedPtr<TopLevelObject>(new IOBlock("TheBlock", "tcBlock", blockMembers)));
6017 			m_tesInputs.push_back	(SharedPtr<TopLevelObject>(new IOBlock("TheBlock", "teBlock", blockMembers)));
6018 
6019 			usedStruct = true;
6020 		}
6021 		else
6022 		{
6023 			const Variable var0("in_te_s", structVarType,	m_ioType != IO_TYPE_PER_PATCH);
6024 			const Variable var1("in_te_f", highpFloat,		m_ioType != IO_TYPE_PER_PATCH);
6025 
6026 			if (m_ioType != IO_TYPE_PER_PATCH_ARRAY)
6027 			{
6028 				// Arrays of structures are disallowed, add struct cases only if not arrayed variable
6029 				m_tcsOutputs.push_back	(SharedPtr<TopLevelObject>(new Variable(var0)));
6030 				m_tesInputs.push_back	(SharedPtr<TopLevelObject>(new Variable(var0)));
6031 
6032 				usedStruct = true;
6033 			}
6034 
6035 			m_tcsOutputs.push_back	(SharedPtr<TopLevelObject>(new Variable(var1)));
6036 			m_tesInputs.push_back	(SharedPtr<TopLevelObject>(new Variable(var1)));
6037 		}
6038 
6039 		tcsDeclarations += "in " + Variable("in_tc_attr", highpFloat, true).declareArray(vertexAttrArrayInputSize);
6040 
6041 		if (usedStruct)
6042 			tcsDeclarations += de::toString(glu::declare(structType)) + ";\n";
6043 
6044 		tcsStatements += "\t{\n"
6045 						 "\t\thighp float v = 1.3;\n";
6046 
6047 		for (int tcsOutputNdx = 0; tcsOutputNdx < (int)m_tcsOutputs.size(); tcsOutputNdx++)
6048 		{
6049 			const TopLevelObject&	output		= *m_tcsOutputs[tcsOutputNdx];
6050 			const int				numElements	= !isPerPatchIO								? -1	//!< \note -1 means indexing with gl_InstanceID
6051 												: m_ioType == IO_TYPE_PER_PATCH				? 1
6052 												: m_ioType == IO_TYPE_PER_PATCH_ARRAY		? NUM_PER_PATCH_ARRAY_ELEMS
6053 												: m_ioType == IO_TYPE_PER_PATCH_BLOCK		? 1
6054 												: m_ioType == IO_TYPE_PER_PATCH_BLOCK_ARRAY	? NUM_PER_PATCH_BLOCKS
6055 												: -2;
6056 			const bool				isArray		= (numElements != 1);
6057 
6058 			DE_ASSERT(numElements != -2);
6059 
6060 			if (isArray)
6061 			{
6062 				tcsDeclarations += outMaybePatch + output.declareArray(m_ioType == IO_TYPE_PER_PATCH_ARRAY											? de::toString(int(NUM_PER_PATCH_ARRAY_ELEMS))
6063 																	   : m_ioType == IO_TYPE_PER_PATCH_BLOCK_ARRAY									? de::toString(int(NUM_PER_PATCH_BLOCKS))
6064 																	   : m_tessControlOutArraySize == TESS_CONTROL_OUT_ARRAY_SIZE_LAYOUT			? de::toString(int(NUM_OUTPUT_VERTICES))
6065 																	   : m_tessControlOutArraySize == TESS_CONTROL_OUT_ARRAY_SIZE_QUERY				? de::toString(m_context.getContextInfo().getInt(GL_MAX_PATCH_VERTICES))
6066 																	   : m_tessControlOutArraySize == TESS_CONTROL_OUT_ARRAY_SIZE_SHADER_BUILTIN	? "gl_MaxPatchVertices"
6067 																	   : "");
6068 			}
6069 			else
6070 				tcsDeclarations += outMaybePatch + output.declare();
6071 
6072 			if (!isPerPatchIO)
6073 				tcsStatements += "\t\tv += float(gl_InvocationID)*" + de::floatToString(0.4f * (float)output.numBasicSubobjectsInElementType(), 1) + ";\n";
6074 
6075 			tcsStatements += "\n\t\t// Assign values to output " + output.name() + "\n";
6076 			if (isArray)
6077 				tcsStatements += output.glslTraverseBasicTypeArray(numElements, 2, glslAssignBasicTypeObject);
6078 			else
6079 				tcsStatements += output.glslTraverseBasicType(2, glslAssignBasicTypeObject);
6080 
6081 			if (!isPerPatchIO)
6082 				tcsStatements += "\t\tv += float(" + de::toString(int(NUM_OUTPUT_VERTICES)) + "-gl_InvocationID-1)*" + de::floatToString(0.4f * (float)output.numBasicSubobjectsInElementType(), 1) + ";\n";
6083 		}
6084 		tcsStatements += "\t}\n";
6085 
6086 		if (usedStruct)
6087 			tesDeclarations += de::toString(glu::declare(structType)) + ";\n";
6088 
6089 		tesStatements += "\tbool allOk = true;\n"
6090 						 "\thighp uint firstFailedInputIndex = 0u;\n"
6091 						 "\t{\n"
6092 						 "\t\thighp float v = 1.3;\n";
6093 		for (int tesInputNdx = 0; tesInputNdx < (int)m_tesInputs.size(); tesInputNdx++)
6094 		{
6095 			const TopLevelObject&	input		= *m_tesInputs[tesInputNdx];
6096 			const int				numElements	= !isPerPatchIO								? (int)NUM_OUTPUT_VERTICES
6097 												: m_ioType == IO_TYPE_PER_PATCH				? 1
6098 												: m_ioType == IO_TYPE_PER_PATCH_BLOCK		? 1
6099 												: m_ioType == IO_TYPE_PER_PATCH_ARRAY		? NUM_PER_PATCH_ARRAY_ELEMS
6100 												: m_ioType == IO_TYPE_PER_PATCH_BLOCK_ARRAY	? NUM_PER_PATCH_BLOCKS
6101 												: -2;
6102 			const bool				isArray		= (numElements != 1);
6103 
6104 			DE_ASSERT(numElements != -2);
6105 
6106 			if (isArray)
6107 				tesDeclarations += inMaybePatch + input.declareArray(m_ioType == IO_TYPE_PER_PATCH_ARRAY			? de::toString(int(NUM_PER_PATCH_ARRAY_ELEMS))
6108 																	 : m_ioType == IO_TYPE_PER_PATCH_BLOCK_ARRAY	? de::toString(int(NUM_PER_PATCH_BLOCKS))
6109 																	 : isExplicitVertexArraySize					? de::toString(vertexAttrArrayInputSize)
6110 																	 : "");
6111 			else
6112 				tesDeclarations += inMaybePatch + input.declare();
6113 
6114 			tesStatements += "\n\t\t// Check values in input " + input.name() + "\n";
6115 			if (isArray)
6116 				tesStatements += input.glslTraverseBasicTypeArray(numElements, 2, glslCheckBasicTypeObject);
6117 			else
6118 				tesStatements += input.glslTraverseBasicType(2, glslCheckBasicTypeObject);
6119 		}
6120 		tesStatements += "\t}\n";
6121 	}
6122 
6123 	std::string vertexShaderTemplate			("${GLSL_VERSION_DECL}\n"
6124 												 "\n"
6125 												 "in highp float in_v_attr;\n"
6126 												 "out highp float in_tc_attr;\n"
6127 												 "\n"
6128 												 "void main (void)\n"
6129 												 "{\n"
6130 												 "	in_tc_attr = in_v_attr;\n"
6131 												 "}\n");
6132 	std::string tessellationControlTemplate		("${GLSL_VERSION_DECL}\n"
6133 												 "${TESSELLATION_SHADER_REQUIRE}\n"
6134 												 "\n"
6135 												 "layout (vertices = " + de::toString(int(NUM_OUTPUT_VERTICES)) + ") out;\n"
6136 												 "\n"
6137 												 + tcsDeclarations +
6138 												 "\n"
6139 												 "patch out highp vec2 in_te_positionScale;\n"
6140 												 "patch out highp vec2 in_te_positionOffset;\n"
6141 												 "\n"
6142 												 "void main (void)\n"
6143 												 "{\n"
6144 												 + tcsStatements +
6145 												 "\n"
6146 												 "	in_te_positionScale  = vec2(in_tc_attr[6], in_tc_attr[7]);\n"
6147 												 "	in_te_positionOffset = vec2(in_tc_attr[8], in_tc_attr[9]);\n"
6148 												 "\n"
6149 												 "	gl_TessLevelInner[0] = in_tc_attr[0];\n"
6150 												 "	gl_TessLevelInner[1] = in_tc_attr[1];\n"
6151 												 "\n"
6152 												 "	gl_TessLevelOuter[0] = in_tc_attr[2];\n"
6153 												 "	gl_TessLevelOuter[1] = in_tc_attr[3];\n"
6154 												 "	gl_TessLevelOuter[2] = in_tc_attr[4];\n"
6155 												 "	gl_TessLevelOuter[3] = in_tc_attr[5];\n"
6156 												 "}\n");
6157 	std::string tessellationEvaluationTemplate	("${GLSL_VERSION_DECL}\n"
6158 												 "${TESSELLATION_SHADER_REQUIRE}\n"
6159 												 "\n"
6160 												 + getTessellationEvaluationInLayoutString(m_primitiveType) +
6161 												 "\n"
6162 												 + tesDeclarations +
6163 												 "\n"
6164 												 "patch in highp vec2 in_te_positionScale;\n"
6165 												 "patch in highp vec2 in_te_positionOffset;\n"
6166 												 "\n"
6167 												 "out highp vec4 in_f_color;\n"
6168 												 "// Will contain the index of the first incorrect input,\n"
6169 												 "// or the number of inputs if all are correct\n"
6170 												 "flat out highp uint out_te_firstFailedInputIndex;\n"
6171 												 "\n"
6172 												 "bool compare_int   (int   a, int   b) { return a == b; }\n"
6173 												 "bool compare_float (float a, float b) { return abs(a - b) < 0.01f; }\n"
6174 												 "bool compare_vec4  (vec4  a, vec4  b) { return all(lessThan(abs(a - b), vec4(0.01f))); }\n"
6175 												 "\n"
6176 												 "void main (void)\n"
6177 												 "{\n"
6178 												 + tesStatements +
6179 												 "\n"
6180 												 "	gl_Position = vec4(gl_TessCoord.xy*in_te_positionScale + in_te_positionOffset, 0.0, 1.0);\n"
6181 												 "	in_f_color = allOk ? vec4(0.0, 1.0, 0.0, 1.0)\n"
6182 												 "	                   : vec4(1.0, 0.0, 0.0, 1.0);\n"
6183 												 "	out_te_firstFailedInputIndex = firstFailedInputIndex;\n"
6184 												 "}\n");
6185 	std::string fragmentShaderTemplate			("${GLSL_VERSION_DECL}\n"
6186 												 "\n"
6187 												 "layout (location = 0) out mediump vec4 o_color;\n"
6188 												 "\n"
6189 												 "in highp vec4 in_f_color;\n"
6190 												 "\n"
6191 												 "void main (void)\n"
6192 												 "{\n"
6193 												 "	o_color = in_f_color;\n"
6194 												 "}\n");
6195 
6196 	m_program = SharedPtr<const ShaderProgram>(new ShaderProgram(m_context.getRenderContext(), glu::ProgramSources()
6197 		<< glu::VertexSource					(specializeShader(m_context, vertexShaderTemplate.c_str()))
6198 		<< glu::TessellationControlSource		(specializeShader(m_context, tessellationControlTemplate.c_str()))
6199 		<< glu::TessellationEvaluationSource	(specializeShader(m_context, tessellationEvaluationTemplate.c_str()))
6200 		<< glu::FragmentSource					(specializeShader(m_context, fragmentShaderTemplate.c_str()))
6201 		<< glu::TransformFeedbackVarying		("out_te_firstFailedInputIndex")
6202 		<< glu::TransformFeedbackMode			(GL_INTERLEAVED_ATTRIBS)));
6203 
6204 	m_testCtx.getLog() << *m_program;
6205 	if (!m_program->isOk())
6206 		TCU_FAIL("Program compilation failed");
6207 }
6208 
deinit(void)6209 void UserDefinedIOCase::deinit (void)
6210 {
6211 	m_program.clear();
6212 }
6213 
iterate(void)6214 UserDefinedIOCase::IterateResult UserDefinedIOCase::iterate (void)
6215 {
6216 	typedef TransformFeedbackHandler<deUint32> TFHandler;
6217 
6218 	TestLog&				log						= m_testCtx.getLog();
6219 	const RenderContext&	renderCtx				= m_context.getRenderContext();
6220 	const RandomViewport	viewport				(renderCtx.getRenderTarget(), RENDER_SIZE, RENDER_SIZE, deStringHash(getName()));
6221 	const glw::Functions&	gl						= renderCtx.getFunctions();
6222 	static const float		attributes[6+2+2]		= { /* inner */ 3.0f, 4.0f, /* outer */ 5.0f, 6.0f, 7.0f, 8.0f, /* pos. scale */ 1.2f, 1.3f, /* pos. offset */ -0.3f, -0.4f };
6223 	const deUint32			programGL				= m_program->getProgram();
6224 	const int				numVertices				= referenceVertexCount(m_primitiveType, SPACINGMODE_EQUAL, false, &attributes[0], &attributes[2]);
6225 	const TFHandler			tfHandler				(renderCtx, numVertices);
6226 	tcu::ResultCollector	result;
6227 
6228 	gl.useProgram(programGL);
6229 	setViewport(gl, viewport);
6230 	gl.patchParameteri(GL_PATCH_VERTICES, DE_LENGTH_OF_ARRAY(attributes));
6231 
6232 	gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
6233 	gl.clear(GL_COLOR_BUFFER_BIT);
6234 
6235 	{
6236 		const glu::VertexArrayBinding	bindings[]	= { glu::va::Float("in_v_attr", 1, DE_LENGTH_OF_ARRAY(attributes), 0, &attributes[0]) };
6237 		const TFHandler::Result			tfResult	= tfHandler.renderAndGetPrimitives(programGL, outputPrimitiveTypeGL(m_primitiveType, false),
6238 																					   DE_LENGTH_OF_ARRAY(bindings), &bindings[0], DE_LENGTH_OF_ARRAY(attributes));
6239 
6240 		{
6241 			const tcu::Surface			pixels		= getPixels(renderCtx, viewport);
6242 			const tcu::TextureLevel		reference	= getPNG(m_testCtx.getArchive(), m_referenceImagePath.c_str());
6243 			const bool					success		= tcu::fuzzyCompare(log, "ImageComparison", "Image Comparison", reference.getAccess(), pixels.getAccess(), 0.02f, tcu::COMPARE_LOG_RESULT);
6244 
6245 			if (!success)
6246 				result.fail("Image comparison failed");
6247 		}
6248 
6249 		if ((int)tfResult.varying.size() != numVertices)
6250 		{
6251 			log << TestLog::Message << "Failure: transform feedback returned " << tfResult.varying.size() << " vertices; expected " << numVertices << TestLog::EndMessage;
6252 			result.fail("Wrong number of vertices");
6253 		}
6254 		else
6255 		{
6256 			const int topLevelArraySize		= (m_ioType == IO_TYPE_PER_PATCH				? 1
6257 											 : m_ioType == IO_TYPE_PER_PATCH_ARRAY			? NUM_PER_PATCH_ARRAY_ELEMS
6258 											 : m_ioType == IO_TYPE_PER_PATCH_BLOCK			? 1
6259 											 : m_ioType == IO_TYPE_PER_PATCH_BLOCK_ARRAY	? NUM_PER_PATCH_BLOCKS
6260 											 : (int)NUM_OUTPUT_VERTICES);
6261 			const int numTEInputs			= numBasicSubobjectsInElementType(m_tesInputs) * topLevelArraySize;
6262 
6263 			for (int vertexNdx = 0; vertexNdx < (int)numVertices; vertexNdx++)
6264 			{
6265 				if (tfResult.varying[vertexNdx] > (deUint32)numTEInputs)
6266 				{
6267 					log << TestLog::Message << "Failure: out_te_firstFailedInputIndex has value " << tfResult.varying[vertexNdx]
6268 											<< ", should be in range [0, " << numTEInputs << "]" << TestLog::EndMessage;
6269 					result.fail("Invalid transform feedback output");
6270 				}
6271 				else if (tfResult.varying[vertexNdx] != (deUint32)numTEInputs)
6272 				{
6273 					log << TestLog::Message << "Failure: in tessellation evaluation shader, check for input "
6274 											<< basicSubobjectAtIndex(tfResult.varying[vertexNdx], m_tesInputs, topLevelArraySize) << " failed" << TestLog::EndMessage;
6275 					result.fail("Invalid input value in tessellation evaluation shader");
6276 				}
6277 			}
6278 		}
6279 	}
6280 
6281 	result.setTestContextResult(m_testCtx);
6282 	return STOP;
6283 }
6284 
6285 /*--------------------------------------------------------------------*//*!
6286  * \brief Pass gl_Position between VS and TCS, or between TCS and TES.
6287  *
6288  * In TCS gl_Position is in the gl_out[] block and in TES in the gl_in[]
6289  * block, and has no special semantics in those. Arbitrary vec4 data can
6290  * thus be passed there.
6291  *//*--------------------------------------------------------------------*/
6292 class GLPositionCase : public TestCase
6293 {
6294 public:
6295 	enum CaseType
6296 	{
6297 		CASETYPE_VS_TO_TCS = 0,
6298 		CASETYPE_TCS_TO_TES,
6299 		CASETYPE_VS_TO_TCS_TO_TES,
6300 
6301 		CASETYPE_LAST
6302 	};
6303 
GLPositionCase(Context & context,const char * name,const char * description,CaseType caseType,const char * referenceImagePath)6304 	GLPositionCase (Context& context, const char* name, const char* description, CaseType caseType, const char* referenceImagePath)
6305 		: TestCase				(context, name, description)
6306 		, m_caseType			(caseType)
6307 		, m_referenceImagePath	(referenceImagePath)
6308 	{
6309 	}
6310 
6311 	void									init				(void);
6312 	void									deinit				(void);
6313 	IterateResult							iterate				(void);
6314 
6315 	static const char*						getCaseTypeName		(CaseType type);
6316 
6317 private:
6318 	static const int						RENDER_SIZE = 256;
6319 
6320 	const CaseType							m_caseType;
6321 	const string							m_referenceImagePath;
6322 
6323 	SharedPtr<const glu::ShaderProgram>		m_program;
6324 };
6325 
getCaseTypeName(CaseType type)6326 const char* GLPositionCase::getCaseTypeName (CaseType type)
6327 {
6328 	switch (type)
6329 	{
6330 		case CASETYPE_VS_TO_TCS:			return "gl_position_vs_to_tcs";
6331 		case CASETYPE_TCS_TO_TES:			return "gl_position_tcs_to_tes";
6332 		case CASETYPE_VS_TO_TCS_TO_TES:		return "gl_position_vs_to_tcs_to_tes";
6333 		default:
6334 			DE_ASSERT(false); return DE_NULL;
6335 	}
6336 }
6337 
init(void)6338 void GLPositionCase::init (void)
6339 {
6340 	checkTessellationSupport(m_context);
6341 	checkRenderTargetSize(m_context.getRenderTarget(), RENDER_SIZE);
6342 
6343 	const bool		vsToTCS		= m_caseType == CASETYPE_VS_TO_TCS		|| m_caseType == CASETYPE_VS_TO_TCS_TO_TES;
6344 	const bool		tcsToTES	= m_caseType == CASETYPE_TCS_TO_TES		|| m_caseType == CASETYPE_VS_TO_TCS_TO_TES;
6345 
6346 	const string	tesIn0		= tcsToTES ? "gl_in[0].gl_Position" : "in_te_attr[0]";
6347 	const string	tesIn1		= tcsToTES ? "gl_in[1].gl_Position" : "in_te_attr[1]";
6348 	const string	tesIn2		= tcsToTES ? "gl_in[2].gl_Position" : "in_te_attr[2]";
6349 
6350 	std::string vertexShaderTemplate			("${GLSL_VERSION_DECL}\n"
6351 												 "\n"
6352 												 "in highp vec4 in_v_attr;\n"
6353 												 + string(!vsToTCS ? "out highp vec4 in_tc_attr;\n" : "") +
6354 												 "\n"
6355 												 "void main (void)\n"
6356 												 "{\n"
6357 												 "	" + (vsToTCS ? "gl_Position" : "in_tc_attr") + " = in_v_attr;\n"
6358 												 "}\n");
6359 	std::string tessellationControlTemplate		("${GLSL_VERSION_DECL}\n"
6360 												 "${TESSELLATION_SHADER_REQUIRE}\n"
6361 												 "\n"
6362 												 "layout (vertices = 3) out;\n"
6363 												 "\n"
6364 												 + string(!vsToTCS ? "in highp vec4 in_tc_attr[];\n" : "") +
6365 												 "\n"
6366 												 + (!tcsToTES ? "out highp vec4 in_te_attr[];\n" : "") +
6367 												 "\n"
6368 												 "void main (void)\n"
6369 												 "{\n"
6370 												 "	" + (tcsToTES ? "gl_out[gl_InvocationID].gl_Position" : "in_te_attr[gl_InvocationID]") + " = "
6371 													  + (vsToTCS ? "gl_in[gl_InvocationID].gl_Position" : "in_tc_attr[gl_InvocationID]") + ";\n"
6372 												 "\n"
6373 												 "	gl_TessLevelInner[0] = 2.0;\n"
6374 												 "	gl_TessLevelInner[1] = 3.0;\n"
6375 												 "\n"
6376 												 "	gl_TessLevelOuter[0] = 4.0;\n"
6377 												 "	gl_TessLevelOuter[1] = 5.0;\n"
6378 												 "	gl_TessLevelOuter[2] = 6.0;\n"
6379 												 "	gl_TessLevelOuter[3] = 7.0;\n"
6380 												 "}\n");
6381 	std::string tessellationEvaluationTemplate	("${GLSL_VERSION_DECL}\n"
6382 												 "${TESSELLATION_SHADER_REQUIRE}\n"
6383 												 "\n"
6384 												 + getTessellationEvaluationInLayoutString(TESSPRIMITIVETYPE_TRIANGLES) +
6385 												 "\n"
6386 												 + (!tcsToTES ? "in highp vec4 in_te_attr[];\n" : "") +
6387 												 "\n"
6388 												 "out highp vec4 in_f_color;\n"
6389 												 "\n"
6390 												 "void main (void)\n"
6391 												 "{\n"
6392 												 "	highp vec2 xy = gl_TessCoord.x * " + tesIn0 + ".xy\n"
6393 												 "	              + gl_TessCoord.y * " + tesIn1 + ".xy\n"
6394 												 "	              + gl_TessCoord.z * " + tesIn2 + ".xy;\n"
6395 												 "	gl_Position = vec4(xy, 0.0, 1.0);\n"
6396 												 "	in_f_color = vec4(" + tesIn0 + ".z + " + tesIn1 + ".w,\n"
6397 												 "	                  " + tesIn2 + ".z + " + tesIn0 + ".w,\n"
6398 												 "	                  " + tesIn1 + ".z + " + tesIn2 + ".w,\n"
6399 												 "	                  1.0);\n"
6400 												 "}\n");
6401 	std::string fragmentShaderTemplate			("${GLSL_VERSION_DECL}\n"
6402 												 "\n"
6403 												 "layout (location = 0) out mediump vec4 o_color;\n"
6404 												 "\n"
6405 												 "in highp vec4 in_f_color;\n"
6406 												 "\n"
6407 												 "void main (void)\n"
6408 												 "{\n"
6409 												 "	o_color = in_f_color;\n"
6410 												 "}\n");
6411 
6412 	m_program = SharedPtr<const ShaderProgram>(new ShaderProgram(m_context.getRenderContext(), glu::ProgramSources()
6413 		<< glu::VertexSource					(specializeShader(m_context, vertexShaderTemplate.c_str()))
6414 		<< glu::TessellationControlSource		(specializeShader(m_context, tessellationControlTemplate.c_str()))
6415 		<< glu::TessellationEvaluationSource	(specializeShader(m_context, tessellationEvaluationTemplate.c_str()))
6416 		<< glu::FragmentSource					(specializeShader(m_context, fragmentShaderTemplate.c_str()))));
6417 
6418 	m_testCtx.getLog() << *m_program;
6419 	if (!m_program->isOk())
6420 		TCU_FAIL("Program compilation failed");
6421 }
6422 
deinit(void)6423 void GLPositionCase::deinit (void)
6424 {
6425 	m_program.clear();
6426 }
6427 
iterate(void)6428 GLPositionCase::IterateResult GLPositionCase::iterate (void)
6429 {
6430 	TestLog&				log						= m_testCtx.getLog();
6431 	const RenderContext&	renderCtx				= m_context.getRenderContext();
6432 	const RandomViewport	viewport				(renderCtx.getRenderTarget(), RENDER_SIZE, RENDER_SIZE, deStringHash(getName()));
6433 	const glw::Functions&	gl						= renderCtx.getFunctions();
6434 	const deUint32			programGL				= m_program->getProgram();
6435 
6436 	static const float attributes[3*4] =
6437 	{
6438 		-0.8f, -0.7f, 0.1f, 0.7f,
6439 		-0.5f,  0.4f, 0.2f, 0.5f,
6440 		 0.3f,  0.2f, 0.3f, 0.45f
6441 	};
6442 
6443 	gl.useProgram(programGL);
6444 	setViewport(gl, viewport);
6445 	gl.patchParameteri(GL_PATCH_VERTICES, 3);
6446 
6447 	gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
6448 	gl.clear(GL_COLOR_BUFFER_BIT);
6449 
6450 	log << TestLog::Message << "Note: input data for in_v_attr:\n" << arrayStr(attributes, 4) << TestLog::EndMessage;
6451 
6452 	{
6453 		const glu::VertexArrayBinding bindings[] = { glu::va::Float("in_v_attr", 4, 3, 0, &attributes[0]) };
6454 		glu::draw(renderCtx, programGL, DE_LENGTH_OF_ARRAY(bindings), &bindings[0], glu::pr::Patches(3));
6455 
6456 		{
6457 			const tcu::Surface			pixels		= getPixels(renderCtx, viewport);
6458 			const tcu::TextureLevel		reference	= getPNG(m_testCtx.getArchive(), m_referenceImagePath.c_str());
6459 			const bool					success		= tcu::fuzzyCompare(log, "ImageComparison", "Image Comparison", reference.getAccess(), pixels.getAccess(), 0.02f, tcu::COMPARE_LOG_RESULT);
6460 
6461 			if (!success)
6462 			{
6463 				m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed");
6464 				return STOP;
6465 			}
6466 		}
6467 	}
6468 
6469 	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
6470 	return STOP;
6471 }
6472 
6473 class LimitQueryCase : public TestCase
6474 {
6475 public:
6476 						LimitQueryCase	(Context& context, const char* name, const char* desc, glw::GLenum target, int minValue);
6477 private:
6478 	IterateResult		iterate			(void);
6479 
6480 	const glw::GLenum	m_target;
6481 	const int			m_minValue;
6482 };
6483 
LimitQueryCase(Context & context,const char * name,const char * desc,glw::GLenum target,int minValue)6484 LimitQueryCase::LimitQueryCase (Context& context, const char* name, const char* desc, glw::GLenum target, int minValue)
6485 	: TestCase			(context, name, desc)
6486 	, m_target			(target)
6487 	, m_minValue		(minValue)
6488 {
6489 }
6490 
iterate(void)6491 LimitQueryCase::IterateResult LimitQueryCase::iterate (void)
6492 {
6493 	checkTessellationSupport(m_context);
6494 
6495 	glu::CallLogWrapper		gl		(m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
6496 	tcu::ResultCollector	result	(m_testCtx.getLog(), " // ERROR: ");
6497 
6498 	gl.enableLogging(true);
6499 	verifyStateIntegerMin(result, gl, m_target, m_minValue, QUERY_INTEGER);
6500 
6501 	{
6502 		const tcu::ScopedLogSection	section(m_testCtx.getLog(), "Types", "Alternative queries");
6503 		verifyStateIntegerMin(result, gl, m_target, m_minValue, QUERY_BOOLEAN);
6504 		verifyStateIntegerMin(result, gl, m_target, m_minValue, QUERY_INTEGER64);
6505 		verifyStateIntegerMin(result, gl, m_target, m_minValue, QUERY_FLOAT);
6506 	}
6507 
6508 	result.setTestContextResult(m_testCtx);
6509 	return STOP;
6510 }
6511 
6512 class CombinedUniformLimitCase : public TestCase
6513 {
6514 public:
6515 						CombinedUniformLimitCase	(Context& context, const char* name, const char* desc, glw::GLenum combined, glw::GLenum numBlocks, glw::GLenum defaultComponents);
6516 private:
6517 	IterateResult		iterate						(void);
6518 
6519 	const glw::GLenum	m_combined;
6520 	const glw::GLenum	m_numBlocks;
6521 	const glw::GLenum	m_defaultComponents;
6522 };
6523 
CombinedUniformLimitCase(Context & context,const char * name,const char * desc,glw::GLenum combined,glw::GLenum numBlocks,glw::GLenum defaultComponents)6524 CombinedUniformLimitCase::CombinedUniformLimitCase (Context& context, const char* name, const char* desc, glw::GLenum combined, glw::GLenum numBlocks, glw::GLenum defaultComponents)
6525 	: TestCase				(context, name, desc)
6526 	, m_combined			(combined)
6527 	, m_numBlocks			(numBlocks)
6528 	, m_defaultComponents	(defaultComponents)
6529 {
6530 }
6531 
iterate(void)6532 CombinedUniformLimitCase::IterateResult CombinedUniformLimitCase::iterate (void)
6533 {
6534 	checkTessellationSupport(m_context);
6535 
6536 	glu::CallLogWrapper		gl		(m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
6537 	tcu::ResultCollector	result	(m_testCtx.getLog(), " // ERROR: ");
6538 
6539 	gl.enableLogging(true);
6540 
6541 	m_testCtx.getLog()	<< tcu::TestLog::Message
6542 						<< "The minimum value of " << glu::getGettableStateStr(m_combined)
6543 						<< " is " << glu::getGettableStateStr(m_numBlocks)
6544 						<< " x MAX_UNIFORM_BLOCK_SIZE / 4 + "
6545 						<< glu::getGettableStateStr(m_defaultComponents)
6546 						<< tcu::TestLog::EndMessage;
6547 
6548 	StateQueryMemoryWriteGuard<glw::GLint> maxUniformBlocks;
6549 	gl.glGetIntegerv(m_numBlocks, &maxUniformBlocks);
6550 	GLS_COLLECT_GL_ERROR(result, gl.glGetError(), "glGetIntegerv");
6551 
6552 	StateQueryMemoryWriteGuard<glw::GLint> maxUniformBlockSize;
6553 	gl.glGetIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE, &maxUniformBlockSize);
6554 	GLS_COLLECT_GL_ERROR(result, gl.glGetError(), "glGetIntegerv");
6555 
6556 	StateQueryMemoryWriteGuard<glw::GLint> maxUniformComponents;
6557 	gl.glGetIntegerv(m_defaultComponents, &maxUniformComponents);
6558 	GLS_COLLECT_GL_ERROR(result, gl.glGetError(), "glGetIntegerv");
6559 
6560 	if (maxUniformBlocks.verifyValidity(result) && maxUniformBlockSize.verifyValidity(result) && maxUniformComponents.verifyValidity(result))
6561 	{
6562 		const int limit = ((int)maxUniformBlocks) * ((int)maxUniformBlockSize) / 4 + (int)maxUniformComponents;
6563 		verifyStateIntegerMin(result, gl, m_combined, limit, QUERY_INTEGER);
6564 
6565 		{
6566 			const tcu::ScopedLogSection	section(m_testCtx.getLog(), "Types", "Alternative queries");
6567 			verifyStateIntegerMin(result, gl, m_combined, limit, QUERY_BOOLEAN);
6568 			verifyStateIntegerMin(result, gl, m_combined, limit, QUERY_INTEGER64);
6569 			verifyStateIntegerMin(result, gl, m_combined, limit, QUERY_FLOAT);
6570 		}
6571 	}
6572 
6573 	result.setTestContextResult(m_testCtx);
6574 	return STOP;
6575 }
6576 
6577 class PatchVerticesStateCase : public TestCase
6578 {
6579 public:
6580 						PatchVerticesStateCase	(Context& context, const char* name, const char* desc);
6581 private:
6582 	IterateResult		iterate					(void);
6583 };
6584 
PatchVerticesStateCase(Context & context,const char * name,const char * desc)6585 PatchVerticesStateCase::PatchVerticesStateCase (Context& context, const char* name, const char* desc)
6586 	: TestCase(context, name, desc)
6587 {
6588 }
6589 
iterate(void)6590 PatchVerticesStateCase::IterateResult PatchVerticesStateCase::iterate (void)
6591 {
6592 	checkTessellationSupport(m_context);
6593 
6594 	glu::CallLogWrapper		gl		(m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
6595 	tcu::ResultCollector	result	(m_testCtx.getLog(), " // ERROR: ");
6596 
6597 	gl.enableLogging(true);
6598 
6599 	// initial
6600 	{
6601 		const tcu::ScopedLogSection section(m_testCtx.getLog(), "initial", "Initial value");
6602 
6603 		verifyStateInteger(result, gl, GL_PATCH_VERTICES, 3, QUERY_INTEGER);
6604 	}
6605 
6606 	// bind
6607 	{
6608 		const tcu::ScopedLogSection section(m_testCtx.getLog(), "set", "After set");
6609 
6610 		gl.glPatchParameteri(GL_PATCH_VERTICES, 22);
6611 		GLS_COLLECT_GL_ERROR(result, gl.glGetError(), "glPatchParameteri");
6612 
6613 		verifyStateInteger(result, gl, GL_PATCH_VERTICES, 22, QUERY_INTEGER);
6614 		{
6615 			const tcu::ScopedLogSection	subsection(m_testCtx.getLog(), "Types", "Alternative queries");
6616 			verifyStateIntegerMin(result, gl, GL_PATCH_VERTICES, 22, QUERY_BOOLEAN);
6617 			verifyStateIntegerMin(result, gl, GL_PATCH_VERTICES, 22, QUERY_INTEGER64);
6618 			verifyStateIntegerMin(result, gl, GL_PATCH_VERTICES, 22, QUERY_FLOAT);
6619 		}
6620 	}
6621 
6622 	result.setTestContextResult(m_testCtx);
6623 	return STOP;
6624 }
6625 
6626 class PrimitiveRestartForPatchesSupportedCase : public TestCase
6627 {
6628 public:
6629 						PrimitiveRestartForPatchesSupportedCase	(Context& context, const char* name, const char* desc);
6630 private:
6631 	IterateResult		iterate									(void);
6632 };
6633 
PrimitiveRestartForPatchesSupportedCase(Context & context,const char * name,const char * desc)6634 PrimitiveRestartForPatchesSupportedCase::PrimitiveRestartForPatchesSupportedCase (Context& context, const char* name, const char* desc)
6635 	: TestCase(context, name, desc)
6636 {
6637 }
6638 
iterate(void)6639 PrimitiveRestartForPatchesSupportedCase::IterateResult PrimitiveRestartForPatchesSupportedCase::iterate (void)
6640 {
6641 	checkTessellationSupport(m_context);
6642 
6643 	glu::CallLogWrapper		gl		(m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
6644 	tcu::ResultCollector	result	(m_testCtx.getLog(), " // ERROR: ");
6645 	QueriedState			state;
6646 
6647 	gl.enableLogging(true);
6648 
6649 	queryState(result, gl, QUERY_BOOLEAN, GL_PRIMITIVE_RESTART_FOR_PATCHES_SUPPORTED, state);
6650 
6651 	if (!state.isUndefined())
6652 	{
6653 		const tcu::ScopedLogSection	subsection(m_testCtx.getLog(), "Types", "Alternative types");
6654 		verifyStateBoolean(result, gl, GL_PRIMITIVE_RESTART_FOR_PATCHES_SUPPORTED, state.getBoolAccess(), QUERY_INTEGER);
6655 		verifyStateBoolean(result, gl, GL_PRIMITIVE_RESTART_FOR_PATCHES_SUPPORTED, state.getBoolAccess(), QUERY_INTEGER64);
6656 		verifyStateBoolean(result, gl, GL_PRIMITIVE_RESTART_FOR_PATCHES_SUPPORTED, state.getBoolAccess(), QUERY_FLOAT);
6657 	}
6658 
6659 	result.setTestContextResult(m_testCtx);
6660 	return STOP;
6661 }
6662 
6663 class TessProgramQueryCase : public TestCase
6664 {
6665 public:
6666 						TessProgramQueryCase	(Context& context, const char* name, const char* desc);
6667 
6668 	std::string			getVertexSource			(void) const;
6669 	std::string			getFragmentSource		(void) const;
6670 	std::string			getTessCtrlSource		(const char* globalLayouts) const;
6671 	std::string			getTessEvalSource		(const char* globalLayouts) const;
6672 };
6673 
TessProgramQueryCase(Context & context,const char * name,const char * desc)6674 TessProgramQueryCase::TessProgramQueryCase (Context& context, const char* name, const char* desc)
6675 	: TestCase(context, name, desc)
6676 {
6677 }
6678 
getVertexSource(void) const6679 std::string TessProgramQueryCase::getVertexSource (void) const
6680 {
6681 	return	"${GLSL_VERSION_DECL}\n"
6682 			"void main (void)\n"
6683 			"{\n"
6684 			"	gl_Position = vec4(float(gl_VertexID), float(gl_VertexID / 2), 0.0, 1.0);\n"
6685 			"}\n";
6686 }
6687 
getFragmentSource(void) const6688 std::string TessProgramQueryCase::getFragmentSource (void) const
6689 {
6690 	return	"${GLSL_VERSION_DECL}\n"
6691 			"layout (location = 0) out mediump vec4 o_color;\n"
6692 			"void main (void)\n"
6693 			"{\n"
6694 			"	o_color = vec4(0.0, 1.0, 0.0, 1.0);\n"
6695 			"}\n";
6696 }
6697 
getTessCtrlSource(const char * globalLayouts) const6698 std::string TessProgramQueryCase::getTessCtrlSource (const char* globalLayouts) const
6699 {
6700 	return	"${GLSL_VERSION_DECL}\n"
6701 			"${TESSELLATION_SHADER_REQUIRE}\n"
6702 			+ std::string(globalLayouts) + ";\n"
6703 			"void main (void)\n"
6704 			"{\n"
6705 			"	gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
6706 			"	gl_TessLevelInner[0] = 2.8;\n"
6707 			"	gl_TessLevelInner[1] = 2.8;\n"
6708 			"	gl_TessLevelOuter[0] = 2.8;\n"
6709 			"	gl_TessLevelOuter[1] = 2.8;\n"
6710 			"	gl_TessLevelOuter[2] = 2.8;\n"
6711 			"	gl_TessLevelOuter[3] = 2.8;\n"
6712 			"}\n";
6713 }
6714 
getTessEvalSource(const char * globalLayouts) const6715 std::string TessProgramQueryCase::getTessEvalSource (const char* globalLayouts) const
6716 {
6717 	return	"${GLSL_VERSION_DECL}\n"
6718 			"${TESSELLATION_SHADER_REQUIRE}\n"
6719 			+ std::string(globalLayouts) + ";\n"
6720 			"void main (void)\n"
6721 			"{\n"
6722 			"	gl_Position = gl_TessCoord.x * gl_in[0].gl_Position\n"
6723 			"	            + gl_TessCoord.y * gl_in[1].gl_Position\n"
6724 			"	            + gl_TessCoord.y * gl_in[2].gl_Position\n"
6725 			"	            + gl_TessCoord.z * gl_in[3].gl_Position;\n"
6726 			"}\n";
6727 }
6728 
6729 class TessControlOutputVerticesCase : public TessProgramQueryCase
6730 {
6731 public:
6732 						TessControlOutputVerticesCase	(Context& context, const char* name, const char* desc);
6733 private:
6734 	IterateResult		iterate							(void);
6735 };
6736 
TessControlOutputVerticesCase(Context & context,const char * name,const char * desc)6737 TessControlOutputVerticesCase::TessControlOutputVerticesCase (Context& context, const char* name, const char* desc)
6738 	: TessProgramQueryCase(context, name, desc)
6739 {
6740 }
6741 
iterate(void)6742 TessControlOutputVerticesCase::IterateResult TessControlOutputVerticesCase::iterate (void)
6743 {
6744 	checkTessellationSupport(m_context);
6745 
6746 	glu::ShaderProgram program (m_context.getRenderContext(), glu::ProgramSources()
6747 																<< glu::VertexSource(specializeShader(m_context, getVertexSource().c_str()))
6748 																<< glu::FragmentSource(specializeShader(m_context, getFragmentSource().c_str()))
6749 																<< glu::TessellationControlSource(specializeShader(m_context, getTessCtrlSource("layout(vertices=4) out").c_str()))
6750 																<< glu::TessellationEvaluationSource(specializeShader(m_context, getTessEvalSource("layout(triangles) in").c_str())));
6751 
6752 	m_testCtx.getLog() << program;
6753 	if (!program.isOk())
6754 		throw tcu::TestError("failed to build program");
6755 
6756 	{
6757 		glu::CallLogWrapper		gl		(m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
6758 		tcu::ResultCollector	result	(m_testCtx.getLog(), " // ERROR: ");
6759 
6760 		gl.enableLogging(true);
6761 		verifyStateProgramInteger(result, gl, program.getProgram(), GL_TESS_CONTROL_OUTPUT_VERTICES, 4, QUERY_PROGRAM_INTEGER);
6762 
6763 		result.setTestContextResult(m_testCtx);
6764 	}
6765 	return STOP;
6766 }
6767 
6768 class TessGenModeQueryCase : public TessProgramQueryCase
6769 {
6770 public:
6771 						TessGenModeQueryCase	(Context& context, const char* name, const char* desc);
6772 private:
6773 	IterateResult		iterate					(void);
6774 };
6775 
TessGenModeQueryCase(Context & context,const char * name,const char * desc)6776 TessGenModeQueryCase::TessGenModeQueryCase (Context& context, const char* name, const char* desc)
6777 	: TessProgramQueryCase(context, name, desc)
6778 {
6779 }
6780 
iterate(void)6781 TessGenModeQueryCase::IterateResult TessGenModeQueryCase::iterate (void)
6782 {
6783 	tcu::ResultCollector	result	(m_testCtx.getLog(), " // ERROR: ");
6784 	glu::CallLogWrapper		gl		(m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
6785 
6786 	static const struct
6787 	{
6788 		const char* description;
6789 		const char* layout;
6790 		glw::GLenum mode;
6791 	} s_modes[] =
6792 	{
6793 		{ "Triangles",	"layout(triangles) in",	GL_TRIANGLES	},
6794 		{ "Isolines",	"layout(isolines) in",	GL_ISOLINES		},
6795 		{ "Quads",		"layout(quads) in",		GL_QUADS		},
6796 	};
6797 
6798 	checkTessellationSupport(m_context);
6799 	gl.enableLogging(true);
6800 
6801 	for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(s_modes); ++ndx)
6802 	{
6803 		const tcu::ScopedLogSection	section(m_testCtx.getLog(), "Type", s_modes[ndx].description);
6804 
6805 		glu::ShaderProgram program (m_context.getRenderContext(), glu::ProgramSources()
6806 																	<< glu::VertexSource(specializeShader(m_context, getVertexSource().c_str()))
6807 																	<< glu::FragmentSource(specializeShader(m_context, getFragmentSource().c_str()))
6808 																	<< glu::TessellationControlSource(specializeShader(m_context, getTessCtrlSource("layout(vertices=6) out").c_str()))
6809 																	<< glu::TessellationEvaluationSource(specializeShader(m_context, getTessEvalSource(s_modes[ndx].layout).c_str())));
6810 
6811 		m_testCtx.getLog() << program;
6812 		if (!program.isOk())
6813 			result.fail("failed to build program");
6814 		else
6815 			verifyStateProgramInteger(result, gl, program.getProgram(), GL_TESS_GEN_MODE, s_modes[ndx].mode, QUERY_PROGRAM_INTEGER);
6816 	}
6817 
6818 	result.setTestContextResult(m_testCtx);
6819 	return STOP;
6820 }
6821 
6822 class TessGenSpacingQueryCase : public TessProgramQueryCase
6823 {
6824 public:
6825 						TessGenSpacingQueryCase	(Context& context, const char* name, const char* desc);
6826 private:
6827 	IterateResult		iterate					(void);
6828 };
6829 
TessGenSpacingQueryCase(Context & context,const char * name,const char * desc)6830 TessGenSpacingQueryCase::TessGenSpacingQueryCase (Context& context, const char* name, const char* desc)
6831 	: TessProgramQueryCase(context, name, desc)
6832 {
6833 }
6834 
iterate(void)6835 TessGenSpacingQueryCase::IterateResult TessGenSpacingQueryCase::iterate (void)
6836 {
6837 	tcu::ResultCollector	result	(m_testCtx.getLog(), " // ERROR: ");
6838 	glu::CallLogWrapper		gl		(m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
6839 
6840 	static const struct
6841 	{
6842 		const char* description;
6843 		const char* layout;
6844 		glw::GLenum spacing;
6845 	} s_modes[] =
6846 	{
6847 		{ "Default spacing",			"layout(triangles) in",								GL_EQUAL			},
6848 		{ "Equal spacing",				"layout(triangles, equal_spacing) in",				GL_EQUAL			},
6849 		{ "Fractional even spacing",	"layout(triangles, fractional_even_spacing) in",	GL_FRACTIONAL_EVEN	},
6850 		{ "Fractional odd spacing",		"layout(triangles, fractional_odd_spacing) in",		GL_FRACTIONAL_ODD	},
6851 	};
6852 
6853 	checkTessellationSupport(m_context);
6854 	gl.enableLogging(true);
6855 
6856 	for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(s_modes); ++ndx)
6857 	{
6858 		const tcu::ScopedLogSection	section(m_testCtx.getLog(), "Type", s_modes[ndx].description);
6859 
6860 		glu::ShaderProgram program (m_context.getRenderContext(), glu::ProgramSources()
6861 																	<< glu::VertexSource(specializeShader(m_context, getVertexSource().c_str()))
6862 																	<< glu::FragmentSource(specializeShader(m_context, getFragmentSource().c_str()))
6863 																	<< glu::TessellationControlSource(specializeShader(m_context, getTessCtrlSource("layout(vertices=6) out").c_str()))
6864 																	<< glu::TessellationEvaluationSource(specializeShader(m_context, getTessEvalSource(s_modes[ndx].layout).c_str())));
6865 
6866 		m_testCtx.getLog() << program;
6867 		if (!program.isOk())
6868 			result.fail("failed to build program");
6869 		else
6870 			verifyStateProgramInteger(result, gl, program.getProgram(), GL_TESS_GEN_SPACING, s_modes[ndx].spacing, QUERY_PROGRAM_INTEGER);
6871 	}
6872 
6873 	result.setTestContextResult(m_testCtx);
6874 	return STOP;
6875 }
6876 
6877 class TessGenVertexOrderQueryCase : public TessProgramQueryCase
6878 {
6879 public:
6880 						TessGenVertexOrderQueryCase	(Context& context, const char* name, const char* desc);
6881 private:
6882 	IterateResult		iterate						(void);
6883 };
6884 
TessGenVertexOrderQueryCase(Context & context,const char * name,const char * desc)6885 TessGenVertexOrderQueryCase::TessGenVertexOrderQueryCase (Context& context, const char* name, const char* desc)
6886 	: TessProgramQueryCase(context, name, desc)
6887 {
6888 }
6889 
iterate(void)6890 TessGenVertexOrderQueryCase::IterateResult TessGenVertexOrderQueryCase::iterate (void)
6891 {
6892 	tcu::ResultCollector	result	(m_testCtx.getLog(), " // ERROR: ");
6893 	glu::CallLogWrapper		gl		(m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
6894 
6895 	static const struct
6896 	{
6897 		const char* description;
6898 		const char* layout;
6899 		glw::GLenum order;
6900 	} s_modes[] =
6901 	{
6902 		{ "Default order",	"layout(triangles) in",			GL_CCW	},
6903 		{ "CW order",		"layout(triangles, cw) in",		GL_CW	},
6904 		{ "CCW order",		"layout(triangles, ccw) in",	GL_CCW	},
6905 	};
6906 
6907 	checkTessellationSupport(m_context);
6908 	gl.enableLogging(true);
6909 
6910 	for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(s_modes); ++ndx)
6911 	{
6912 		const tcu::ScopedLogSection	section(m_testCtx.getLog(), "Type", s_modes[ndx].description);
6913 
6914 		glu::ShaderProgram program (m_context.getRenderContext(), glu::ProgramSources()
6915 																	<< glu::VertexSource(specializeShader(m_context, getVertexSource().c_str()))
6916 																	<< glu::FragmentSource(specializeShader(m_context, getFragmentSource().c_str()))
6917 																	<< glu::TessellationControlSource(specializeShader(m_context, getTessCtrlSource("layout(vertices=6) out").c_str()))
6918 																	<< glu::TessellationEvaluationSource(specializeShader(m_context, getTessEvalSource(s_modes[ndx].layout).c_str())));
6919 
6920 		m_testCtx.getLog() << program;
6921 		if (!program.isOk())
6922 			result.fail("failed to build program");
6923 		else
6924 			verifyStateProgramInteger(result, gl, program.getProgram(), GL_TESS_GEN_VERTEX_ORDER, s_modes[ndx].order, QUERY_PROGRAM_INTEGER);
6925 	}
6926 
6927 	result.setTestContextResult(m_testCtx);
6928 	return STOP;
6929 }
6930 
6931 class TessGenPointModeQueryCase : public TessProgramQueryCase
6932 {
6933 public:
6934 						TessGenPointModeQueryCase	(Context& context, const char* name, const char* desc);
6935 private:
6936 	IterateResult		iterate						(void);
6937 };
6938 
TessGenPointModeQueryCase(Context & context,const char * name,const char * desc)6939 TessGenPointModeQueryCase::TessGenPointModeQueryCase (Context& context, const char* name, const char* desc)
6940 	: TessProgramQueryCase(context, name, desc)
6941 {
6942 }
6943 
iterate(void)6944 TessGenPointModeQueryCase::IterateResult TessGenPointModeQueryCase::iterate (void)
6945 {
6946 	tcu::ResultCollector	result	(m_testCtx.getLog(), " // ERROR: ");
6947 	glu::CallLogWrapper		gl		(m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
6948 
6949 	static const struct
6950 	{
6951 		const char* description;
6952 		const char* layout;
6953 		glw::GLenum mode;
6954 	} s_modes[] =
6955 	{
6956 		{ "Default mode",	"layout(triangles) in",			GL_FALSE	},
6957 		{ "Point mode",		"layout(triangles, point_mode) in",		GL_TRUE		},
6958 	};
6959 
6960 	checkTessellationSupport(m_context);
6961 	gl.enableLogging(true);
6962 
6963 	for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(s_modes); ++ndx)
6964 	{
6965 		const tcu::ScopedLogSection	section(m_testCtx.getLog(), "Type", s_modes[ndx].description);
6966 
6967 		glu::ShaderProgram program (m_context.getRenderContext(), glu::ProgramSources()
6968 																	<< glu::VertexSource(specializeShader(m_context, getVertexSource().c_str()))
6969 																	<< glu::FragmentSource(specializeShader(m_context, getFragmentSource().c_str()))
6970 																	<< glu::TessellationControlSource(specializeShader(m_context, getTessCtrlSource("layout(vertices=6) out").c_str()))
6971 																	<< glu::TessellationEvaluationSource(specializeShader(m_context, getTessEvalSource(s_modes[ndx].layout).c_str())));
6972 
6973 		m_testCtx.getLog() << program;
6974 		if (!program.isOk())
6975 			result.fail("failed to build program");
6976 		else
6977 			verifyStateProgramInteger(result, gl, program.getProgram(), GL_TESS_GEN_POINT_MODE, s_modes[ndx].mode, QUERY_PROGRAM_INTEGER);
6978 	}
6979 
6980 	result.setTestContextResult(m_testCtx);
6981 	return STOP;
6982 }
6983 
6984 class ReferencedByTessellationQueryCase : public TestCase
6985 {
6986 public:
6987 					ReferencedByTessellationQueryCase	(Context& context, const char* name, const char* desc, bool isCtrlCase);
6988 private:
6989 	void			init								(void);
6990 	IterateResult	iterate								(void);
6991 
6992 	std::string		getVertexSource						(void) const;
6993 	std::string		getFragmentSource					(void) const;
6994 	std::string		getTessCtrlSource					(void) const;
6995 	std::string		getTessEvalSource					(void) const;
6996 
6997 	const bool		m_isCtrlCase;
6998 };
6999 
ReferencedByTessellationQueryCase(Context & context,const char * name,const char * desc,bool isCtrlCase)7000 ReferencedByTessellationQueryCase::ReferencedByTessellationQueryCase (Context& context, const char* name, const char* desc, bool isCtrlCase)
7001 	: TestCase		(context, name, desc)
7002 	, m_isCtrlCase	(isCtrlCase)
7003 {
7004 }
7005 
init(void)7006 void ReferencedByTessellationQueryCase::init (void)
7007 {
7008 	checkTessellationSupport(m_context);
7009 }
7010 
iterate(void)7011 ReferencedByTessellationQueryCase::IterateResult ReferencedByTessellationQueryCase::iterate (void)
7012 {
7013 	tcu::ResultCollector	result	(m_testCtx.getLog(), " // ERROR: ");
7014 	glu::CallLogWrapper		gl		(m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
7015 	glu::ShaderProgram		program	(m_context.getRenderContext(), glu::ProgramSources()
7016 																	<< glu::VertexSource(specializeShader(m_context, getVertexSource().c_str()))
7017 																	<< glu::FragmentSource(specializeShader(m_context, getFragmentSource().c_str()))
7018 																	<< glu::TessellationControlSource(specializeShader(m_context, getTessCtrlSource().c_str()))
7019 																	<< glu::TessellationEvaluationSource(specializeShader(m_context, getTessEvalSource().c_str())));
7020 
7021 	gl.enableLogging(true);
7022 
7023 	m_testCtx.getLog() << program;
7024 	if (!program.isOk())
7025 		result.fail("failed to build program");
7026 	else
7027 	{
7028 		const deUint32 props[1] = { (deUint32)((m_isCtrlCase) ? (GL_REFERENCED_BY_TESS_CONTROL_SHADER) : (GL_REFERENCED_BY_TESS_EVALUATION_SHADER)) };
7029 
7030 		{
7031 			const tcu::ScopedLogSection section		(m_testCtx.getLog(), "UnreferencedUniform", "Unreferenced uniform u_unreferenced");
7032 			deUint32					resourcePos;
7033 			glw::GLsizei				length		= 0;
7034 			glw::GLint					referenced	= 0;
7035 
7036 			resourcePos = gl.glGetProgramResourceIndex(program.getProgram(), GL_UNIFORM, "u_unreferenced");
7037 			m_testCtx.getLog() << tcu::TestLog::Message << "u_unreferenced resource index: " << resourcePos << tcu::TestLog::EndMessage;
7038 
7039 			if (resourcePos == GL_INVALID_INDEX)
7040 				result.fail("resourcePos was GL_INVALID_INDEX");
7041 			else
7042 			{
7043 				gl.glGetProgramResourceiv(program.getProgram(), GL_UNIFORM, resourcePos, 1, props, 1, &length, &referenced);
7044 				m_testCtx.getLog()
7045 					<< tcu::TestLog::Message
7046 					<< "Query " << glu::getProgramResourcePropertyStr(props[0])
7047 					<< ", got " << length << " value(s), value[0] = " << glu::getBooleanStr(referenced)
7048 					<< tcu::TestLog::EndMessage;
7049 
7050 				GLS_COLLECT_GL_ERROR(result, gl.glGetError(), "query resource");
7051 
7052 				if (length == 0 || referenced != GL_FALSE)
7053 					result.fail("expected GL_FALSE");
7054 			}
7055 		}
7056 
7057 		{
7058 			const tcu::ScopedLogSection section		(m_testCtx.getLog(), "ReferencedUniform", "Referenced uniform u_referenced");
7059 			deUint32					resourcePos;
7060 			glw::GLsizei				length		= 0;
7061 			glw::GLint					referenced	= 0;
7062 
7063 			resourcePos = gl.glGetProgramResourceIndex(program.getProgram(), GL_UNIFORM, "u_referenced");
7064 			m_testCtx.getLog() << tcu::TestLog::Message << "u_referenced resource index: " << resourcePos << tcu::TestLog::EndMessage;
7065 
7066 			if (resourcePos == GL_INVALID_INDEX)
7067 				result.fail("resourcePos was GL_INVALID_INDEX");
7068 			else
7069 			{
7070 				gl.glGetProgramResourceiv(program.getProgram(), GL_UNIFORM, resourcePos, 1, props, 1, &length, &referenced);
7071 				m_testCtx.getLog()
7072 					<< tcu::TestLog::Message
7073 					<< "Query " << glu::getProgramResourcePropertyStr(props[0])
7074 					<< ", got " << length << " value(s), value[0] = " << glu::getBooleanStr(referenced)
7075 					<< tcu::TestLog::EndMessage;
7076 
7077 				GLU_EXPECT_NO_ERROR(gl.glGetError(), "query resource");
7078 
7079 				if (length == 0 || referenced != GL_TRUE)
7080 					result.fail("expected GL_TRUE");
7081 			}
7082 		}
7083 	}
7084 
7085 	result.setTestContextResult(m_testCtx);
7086 	return STOP;
7087 }
7088 
getVertexSource(void) const7089 std::string ReferencedByTessellationQueryCase::getVertexSource (void) const
7090 {
7091 	return	"${GLSL_VERSION_DECL}\n"
7092 			"void main (void)\n"
7093 			"{\n"
7094 			"	gl_Position = vec4(float(gl_VertexID), float(gl_VertexID / 2), 0.0, 1.0);\n"
7095 			"}\n";
7096 }
7097 
getFragmentSource(void) const7098 std::string ReferencedByTessellationQueryCase::getFragmentSource (void) const
7099 {
7100 	return	"${GLSL_VERSION_DECL}\n"
7101 			"layout (location = 0) out mediump vec4 o_color;\n"
7102 			"void main (void)\n"
7103 			"{\n"
7104 			"	o_color = vec4(0.0, 1.0, 0.0, 1.0);\n"
7105 			"}\n";
7106 }
7107 
getTessCtrlSource(void) const7108 std::string ReferencedByTessellationQueryCase::getTessCtrlSource (void) const
7109 {
7110 	std::ostringstream buf;
7111 	buf <<	"${GLSL_VERSION_DECL}\n"
7112 			"${TESSELLATION_SHADER_REQUIRE}\n"
7113 			"layout(vertices = 3) out;\n"
7114 			"uniform highp vec4 " << ((m_isCtrlCase) ? ("u_referenced") : ("u_unreferenced")) << ";\n"
7115 			"void main (void)\n"
7116 			"{\n"
7117 			"	vec4 offset = " << ((m_isCtrlCase) ? ("u_referenced") : ("u_unreferenced")) << ";\n"
7118 			"	gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position + offset;\n"
7119 			"	gl_TessLevelInner[0] = 2.8;\n"
7120 			"	gl_TessLevelInner[1] = 2.8;\n"
7121 			"	gl_TessLevelOuter[0] = 2.8;\n"
7122 			"	gl_TessLevelOuter[1] = 2.8;\n"
7123 			"	gl_TessLevelOuter[2] = 2.8;\n"
7124 			"	gl_TessLevelOuter[3] = 2.8;\n"
7125 			"}\n";
7126 	return buf.str();
7127 }
7128 
getTessEvalSource(void) const7129 std::string ReferencedByTessellationQueryCase::getTessEvalSource (void) const
7130 {
7131 	std::ostringstream buf;
7132 	buf <<	"${GLSL_VERSION_DECL}\n"
7133 			"${TESSELLATION_SHADER_REQUIRE}\n"
7134 			"layout(triangles) in;\n"
7135 			"uniform highp vec4 " << ((m_isCtrlCase) ? ("u_unreferenced") : ("u_referenced")) << ";\n"
7136 			"void main (void)\n"
7137 			"{\n"
7138 			"	vec4 offset = " << ((m_isCtrlCase) ? ("u_unreferenced") : ("u_referenced")) << ";\n"
7139 			"	gl_Position = gl_TessCoord.x * gl_in[0].gl_Position\n"
7140 			"	            + gl_TessCoord.y * gl_in[1].gl_Position\n"
7141 			"	            + gl_TessCoord.z * gl_in[2].gl_Position\n"
7142 			"	            + offset;\n"
7143 			"}\n";
7144 
7145 	return buf.str();
7146 }
7147 
7148 class IsPerPatchQueryCase : public TestCase
7149 {
7150 public:
7151 					IsPerPatchQueryCase		(Context& context, const char* name, const char* desc);
7152 private:
7153 	void			init					(void);
7154 	IterateResult	iterate					(void);
7155 };
7156 
IsPerPatchQueryCase(Context & context,const char * name,const char * desc)7157 IsPerPatchQueryCase::IsPerPatchQueryCase (Context& context, const char* name, const char* desc)
7158 	: TestCase(context, name, desc)
7159 {
7160 }
7161 
init(void)7162 void IsPerPatchQueryCase::init (void)
7163 {
7164 	checkTessellationSupport(m_context);
7165 }
7166 
iterate(void)7167 IsPerPatchQueryCase::IterateResult IsPerPatchQueryCase::iterate (void)
7168 {
7169 	static const char* const s_controlSource =	"${GLSL_VERSION_DECL}\n"
7170 												"${TESSELLATION_SHADER_REQUIRE}\n"
7171 												"layout(vertices = 3) out;\n"
7172 												"patch out highp vec4 v_perPatch;\n"
7173 												"out highp vec4 v_perVertex[];\n"
7174 												"void main (void)\n"
7175 												"{\n"
7176 												"	gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
7177 												"	v_perPatch = gl_in[0].gl_Position;\n"
7178 												"	v_perVertex[gl_InvocationID] = -gl_in[gl_InvocationID].gl_Position;\n"
7179 												"	gl_TessLevelInner[0] = 2.8;\n"
7180 												"	gl_TessLevelInner[1] = 2.8;\n"
7181 												"	gl_TessLevelOuter[0] = 2.8;\n"
7182 												"	gl_TessLevelOuter[1] = 2.8;\n"
7183 												"	gl_TessLevelOuter[2] = 2.8;\n"
7184 												"	gl_TessLevelOuter[3] = 2.8;\n"
7185 												"}\n";
7186 	tcu::ResultCollector	result	(m_testCtx.getLog(), " // ERROR: ");
7187 	glu::CallLogWrapper		gl		(m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
7188 	glu::ShaderProgram		program	(m_context.getRenderContext(), glu::ProgramSources()
7189 																	<< glu::TessellationControlSource(specializeShader(m_context, s_controlSource))
7190 																	<< glu::ProgramSeparable(true));
7191 
7192 	gl.enableLogging(true);
7193 
7194 	m_testCtx.getLog() << program;
7195 	if (!program.isOk())
7196 		result.fail("failed to build program");
7197 	else
7198 	{
7199 		const deUint32 props[1] = { GL_IS_PER_PATCH };
7200 
7201 		{
7202 			const tcu::ScopedLogSection section		(m_testCtx.getLog(), "PerPatchOutput", "Per patch v_perPatch");
7203 			deUint32					resourcePos;
7204 			glw::GLsizei				length		= 0;
7205 			glw::GLint					referenced	= 0;
7206 
7207 			resourcePos = gl.glGetProgramResourceIndex(program.getProgram(), GL_PROGRAM_OUTPUT, "v_perPatch");
7208 			m_testCtx.getLog() << tcu::TestLog::Message << "v_perPatch resource index: " << resourcePos << tcu::TestLog::EndMessage;
7209 
7210 			if (resourcePos == GL_INVALID_INDEX)
7211 				result.fail("resourcePos was GL_INVALID_INDEX");
7212 			else
7213 			{
7214 				gl.glGetProgramResourceiv(program.getProgram(), GL_PROGRAM_OUTPUT, resourcePos, 1, props, 1, &length, &referenced);
7215 				m_testCtx.getLog()
7216 					<< tcu::TestLog::Message
7217 					<< "Query " << glu::getProgramResourcePropertyStr(props[0])
7218 					<< ", got " << length << " value(s), value[0] = " << glu::getBooleanStr(referenced)
7219 					<< tcu::TestLog::EndMessage;
7220 
7221 				GLS_COLLECT_GL_ERROR(result, gl.glGetError(), "query resource");
7222 
7223 				if (length == 0 || referenced != GL_TRUE)
7224 					result.fail("expected GL_TRUE");
7225 			}
7226 		}
7227 
7228 		{
7229 			const tcu::ScopedLogSection section		(m_testCtx.getLog(), "PerVertexhOutput", "Per vertex v_perVertex");
7230 			deUint32					resourcePos;
7231 			glw::GLsizei				length		= 0;
7232 			glw::GLint					referenced	= 0;
7233 
7234 			resourcePos = gl.glGetProgramResourceIndex(program.getProgram(), GL_PROGRAM_OUTPUT, "v_perVertex");
7235 			m_testCtx.getLog() << tcu::TestLog::Message << "v_perVertex resource index: " << resourcePos << tcu::TestLog::EndMessage;
7236 
7237 			if (resourcePos == GL_INVALID_INDEX)
7238 				result.fail("resourcePos was GL_INVALID_INDEX");
7239 			else
7240 			{
7241 				gl.glGetProgramResourceiv(program.getProgram(), GL_PROGRAM_OUTPUT, resourcePos, 1, props, 1, &length, &referenced);
7242 				m_testCtx.getLog()
7243 					<< tcu::TestLog::Message
7244 					<< "Query " << glu::getProgramResourcePropertyStr(props[0])
7245 					<< ", got " << length << " value(s), value[0] = " << glu::getBooleanStr(referenced)
7246 					<< tcu::TestLog::EndMessage;
7247 
7248 				GLU_EXPECT_NO_ERROR(gl.glGetError(), "query resource");
7249 
7250 				if (length == 0 || referenced != GL_FALSE)
7251 					result.fail("expected GL_FALSE");
7252 			}
7253 		}
7254 	}
7255 
7256 	result.setTestContextResult(m_testCtx);
7257 	return STOP;
7258 }
7259 
7260 } // anonymous
7261 
TessellationTests(Context & context)7262 TessellationTests::TessellationTests (Context& context)
7263 	: TestCaseGroup(context, "tessellation", "Tessellation Tests")
7264 {
7265 }
7266 
~TessellationTests(void)7267 TessellationTests::~TessellationTests (void)
7268 {
7269 }
7270 
init(void)7271 void TessellationTests::init (void)
7272 {
7273 	{
7274 		tcu::TestCaseGroup* const queryGroup = new tcu::TestCaseGroup(m_testCtx, "state_query", "Query tests");
7275 		addChild(queryGroup);
7276 
7277 		// new limits
7278 		queryGroup->addChild(new LimitQueryCase(m_context, "max_patch_vertices",								"Test MAX_PATCH_VERTICES",								GL_MAX_PATCH_VERTICES,							32));
7279 		queryGroup->addChild(new LimitQueryCase(m_context, "max_tess_gen_level",								"Test MAX_TESS_GEN_LEVEL",								GL_MAX_TESS_GEN_LEVEL,							64));
7280 		queryGroup->addChild(new LimitQueryCase(m_context, "max_tess_control_uniform_components",				"Test MAX_TESS_CONTROL_UNIFORM_COMPONENTS",				GL_MAX_TESS_CONTROL_UNIFORM_COMPONENTS,			1024));
7281 		queryGroup->addChild(new LimitQueryCase(m_context, "max_tess_evaluation_uniform_components",			"Test MAX_TESS_EVALUATION_UNIFORM_COMPONENTS",			GL_MAX_TESS_EVALUATION_UNIFORM_COMPONENTS,		1024));
7282 		queryGroup->addChild(new LimitQueryCase(m_context, "max_tess_control_texture_image_units",				"Test MAX_TESS_CONTROL_TEXTURE_IMAGE_UNITS",			GL_MAX_TESS_CONTROL_TEXTURE_IMAGE_UNITS,		16));
7283 		queryGroup->addChild(new LimitQueryCase(m_context, "max_tess_evaluation_texture_image_units",			"Test MAX_TESS_EVALUATION_TEXTURE_IMAGE_UNITS",			GL_MAX_TESS_EVALUATION_TEXTURE_IMAGE_UNITS,		16));
7284 		queryGroup->addChild(new LimitQueryCase(m_context, "max_tess_control_output_components",				"Test MAX_TESS_CONTROL_OUTPUT_COMPONENTS",				GL_MAX_TESS_CONTROL_OUTPUT_COMPONENTS,			64));
7285 		queryGroup->addChild(new LimitQueryCase(m_context, "max_tess_patch_components",							"Test MAX_TESS_PATCH_COMPONENTS",						GL_MAX_TESS_PATCH_COMPONENTS,					120));
7286 		queryGroup->addChild(new LimitQueryCase(m_context, "max_tess_control_total_output_components",			"Test MAX_TESS_CONTROL_TOTAL_OUTPUT_COMPONENTS",		GL_MAX_TESS_CONTROL_TOTAL_OUTPUT_COMPONENTS,	2048));
7287 		queryGroup->addChild(new LimitQueryCase(m_context, "max_tess_evaluation_output_components",				"Test MAX_TESS_EVALUATION_OUTPUT_COMPONENTS",			GL_MAX_TESS_EVALUATION_OUTPUT_COMPONENTS,		64));
7288 		queryGroup->addChild(new LimitQueryCase(m_context, "max_tess_control_uniform_blocks",					"Test MAX_TESS_CONTROL_UNIFORM_BLOCKS",					GL_MAX_TESS_CONTROL_UNIFORM_BLOCKS,				12));
7289 		queryGroup->addChild(new LimitQueryCase(m_context, "max_tess_evaluation_uniform_blocks",				"Test MAX_TESS_EVALUATION_UNIFORM_BLOCKS",				GL_MAX_TESS_EVALUATION_UNIFORM_BLOCKS,			12));
7290 		queryGroup->addChild(new LimitQueryCase(m_context, "max_tess_control_input_components",					"Test MAX_TESS_CONTROL_INPUT_COMPONENTS",				GL_MAX_TESS_CONTROL_INPUT_COMPONENTS,			64));
7291 		queryGroup->addChild(new LimitQueryCase(m_context, "max_tess_evaluation_input_components",				"Test MAX_TESS_EVALUATION_INPUT_COMPONENTS",			GL_MAX_TESS_EVALUATION_INPUT_COMPONENTS,		64));
7292 		queryGroup->addChild(new LimitQueryCase(m_context, "max_tess_control_atomic_counter_buffers",			"Test MAX_TESS_CONTROL_ATOMIC_COUNTER_BUFFERS",			GL_MAX_TESS_CONTROL_ATOMIC_COUNTER_BUFFERS,		0));
7293 		queryGroup->addChild(new LimitQueryCase(m_context, "max_tess_evaluation_atomic_counter_buffers",		"Test MAX_TESS_EVALUATION_ATOMIC_COUNTER_BUFFERS",		GL_MAX_TESS_EVALUATION_ATOMIC_COUNTER_BUFFERS,	0));
7294 		queryGroup->addChild(new LimitQueryCase(m_context, "max_tess_control_atomic_counters",					"Test MAX_TESS_CONTROL_ATOMIC_COUNTERS",				GL_MAX_TESS_CONTROL_ATOMIC_COUNTERS,			0));
7295 		queryGroup->addChild(new LimitQueryCase(m_context, "max_tess_evaluation_atomic_counters",				"Test MAX_TESS_EVALUATION_ATOMIC_COUNTERS",				GL_MAX_TESS_EVALUATION_ATOMIC_COUNTERS,			0));
7296 		queryGroup->addChild(new LimitQueryCase(m_context, "max_tess_control_image_uniforms",					"Test MAX_TESS_CONTROL_IMAGE_UNIFORMS",					GL_MAX_TESS_CONTROL_IMAGE_UNIFORMS,				0));
7297 		queryGroup->addChild(new LimitQueryCase(m_context, "max_tess_evaluation_image_uniforms",				"Test MAX_TESS_EVALUATION_IMAGE_UNIFORMS",				GL_MAX_TESS_EVALUATION_IMAGE_UNIFORMS,			0));
7298 		queryGroup->addChild(new LimitQueryCase(m_context, "max_tess_control_shader_storage_blocks",			"Test MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS",			GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS,		0));
7299 		queryGroup->addChild(new LimitQueryCase(m_context, "max_tess_evaluation_shader_storage_blocks",			"Test MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS",		GL_MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS,	0));
7300 
7301 		// modified limits
7302 		queryGroup->addChild(new LimitQueryCase(m_context, "max_uniform_buffer_bindings",						"Test MAX_UNIFORM_BUFFER_BINDINGS",						GL_MAX_UNIFORM_BUFFER_BINDINGS,					72));
7303 		queryGroup->addChild(new LimitQueryCase(m_context, "max_combined_uniform_blocks",						"Test MAX_COMBINED_UNIFORM_BLOCKS",						GL_MAX_COMBINED_UNIFORM_BLOCKS,					60));
7304 		queryGroup->addChild(new LimitQueryCase(m_context, "max_combined_texture_image_units",					"Test MAX_COMBINED_TEXTURE_IMAGE_UNITS",				GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS,			96));
7305 
7306 		// combined limits
7307 		queryGroup->addChild(new CombinedUniformLimitCase(m_context, "max_combined_tess_control_uniform_components",		"Test MAX_COMBINED_TESS_CONTROL_UNIFORM_COMPONENTS",	GL_MAX_COMBINED_TESS_CONTROL_UNIFORM_COMPONENTS,		GL_MAX_TESS_CONTROL_UNIFORM_BLOCKS,		GL_MAX_TESS_CONTROL_UNIFORM_COMPONENTS));
7308 		queryGroup->addChild(new CombinedUniformLimitCase(m_context, "max_combined_tess_evaluation_uniform_components",		"Test MAX_COMBINED_TESS_EVALUATION_UNIFORM_COMPONENTS",	GL_MAX_COMBINED_TESS_EVALUATION_UNIFORM_COMPONENTS,		GL_MAX_TESS_EVALUATION_UNIFORM_BLOCKS,	GL_MAX_TESS_EVALUATION_UNIFORM_COMPONENTS));
7309 
7310 		// features
7311 		queryGroup->addChild(new PrimitiveRestartForPatchesSupportedCase(m_context, "primitive_restart_for_patches_supported", "Test PRIMITIVE_RESTART_FOR_PATCHES_SUPPORTED"));
7312 
7313 		// states
7314 		queryGroup->addChild(new PatchVerticesStateCase(m_context, "patch_vertices", "Test PATCH_VERTICES"));
7315 
7316 		// program states
7317 		queryGroup->addChild(new TessControlOutputVerticesCase	(m_context, "tess_control_output_vertices",	"Test TESS_CONTROL_OUTPUT_VERTICES"));
7318 		queryGroup->addChild(new TessGenModeQueryCase			(m_context, "tess_gen_mode",				"Test TESS_GEN_MODE"));
7319 		queryGroup->addChild(new TessGenSpacingQueryCase		(m_context, "tess_gen_spacing",				"Test TESS_GEN_SPACING"));
7320 		queryGroup->addChild(new TessGenVertexOrderQueryCase	(m_context, "tess_gen_vertex_order",		"Test TESS_GEN_VERTEX_ORDER"));
7321 		queryGroup->addChild(new TessGenPointModeQueryCase		(m_context, "tess_gen_point_mode",			"Test TESS_GEN_POINT_MODE"));
7322 
7323 		// resource queries
7324 		queryGroup->addChild(new ReferencedByTessellationQueryCase	(m_context, "referenced_by_tess_control_shader",	"Test REFERENCED_BY_TESS_CONTROL_SHADER",		true));
7325 		queryGroup->addChild(new ReferencedByTessellationQueryCase	(m_context, "referenced_by_tess_evaluation_shader",	"Test REFERENCED_BY_TESS_EVALUATION_SHADER",	false));
7326 		queryGroup->addChild(new IsPerPatchQueryCase				(m_context, "is_per_patch",							"Test IS_PER_PATCH"));
7327 	}
7328 
7329 	{
7330 		TestCaseGroup* const tessCoordGroup = new TestCaseGroup(m_context, "tesscoord", "Get tessellation coordinates with transform feedback and validate them");
7331 		addChild(tessCoordGroup);
7332 
7333 		for (int primitiveTypeI = 0; primitiveTypeI < TESSPRIMITIVETYPE_LAST; primitiveTypeI++)
7334 		{
7335 			const TessPrimitiveType primitiveType = (TessPrimitiveType)primitiveTypeI;
7336 
7337 			for (int spacingI = 0; spacingI < SPACINGMODE_LAST; spacingI++)
7338 				tessCoordGroup->addChild(new TessCoordCase(m_context,
7339 														   (string() + getTessPrimitiveTypeShaderName(primitiveType) + "_" + getSpacingModeShaderName((SpacingMode)spacingI)).c_str(), "",
7340 														   primitiveType, (SpacingMode)spacingI));
7341 		}
7342 	}
7343 
7344 	{
7345 		TestCaseGroup* const windingGroup = new TestCaseGroup(m_context, "winding", "Test the cw and ccw input layout qualifiers");
7346 		addChild(windingGroup);
7347 
7348 		for (int primitiveTypeI = 0; primitiveTypeI < TESSPRIMITIVETYPE_LAST; primitiveTypeI++)
7349 		{
7350 			const TessPrimitiveType primitiveType = (TessPrimitiveType)primitiveTypeI;
7351 			if (primitiveType == TESSPRIMITIVETYPE_ISOLINES)
7352 				continue;
7353 
7354 			for (int windingI = 0; windingI < WINDING_LAST; windingI++)
7355 			{
7356 				const Winding winding = (Winding)windingI;
7357 				windingGroup->addChild(new WindingCase(m_context, (string() + getTessPrimitiveTypeShaderName(primitiveType) + "_" + getWindingShaderName(winding)).c_str(), "", primitiveType, winding));
7358 			}
7359 		}
7360 	}
7361 
7362 	{
7363 		TestCaseGroup* const shaderInputOutputGroup = new TestCaseGroup(m_context, "shader_input_output", "Test tessellation control and evaluation shader inputs and outputs");
7364 		addChild(shaderInputOutputGroup);
7365 
7366 		{
7367 			static const struct
7368 			{
7369 				int inPatchSize;
7370 				int outPatchSize;
7371 			} patchVertexCountCases[] =
7372 			{
7373 				{  5, 10 },
7374 				{ 10,  5 }
7375 			};
7376 
7377 			for (int caseNdx = 0; caseNdx < DE_LENGTH_OF_ARRAY(patchVertexCountCases); caseNdx++)
7378 			{
7379 				const int inSize	= patchVertexCountCases[caseNdx].inPatchSize;
7380 				const int outSize	= patchVertexCountCases[caseNdx].outPatchSize;
7381 
7382 				const string caseName = "patch_vertices_" + de::toString(inSize) + "_in_" + de::toString(outSize) + "_out";
7383 
7384 				shaderInputOutputGroup->addChild(new PatchVertexCountCase(m_context, caseName.c_str(), "Test input and output patch vertex counts", inSize, outSize,
7385 																		  ("data/tessellation/" + caseName + "_ref.png").c_str()));
7386 			}
7387 		}
7388 
7389 		for (int caseTypeI = 0; caseTypeI < PerPatchDataCase::CASETYPE_LAST; caseTypeI++)
7390 		{
7391 			const PerPatchDataCase::CaseType	caseType	= (PerPatchDataCase::CaseType)caseTypeI;
7392 			const char* const					caseName	= PerPatchDataCase::getCaseTypeName(caseType);
7393 
7394 			shaderInputOutputGroup->addChild(new PerPatchDataCase(m_context, caseName, PerPatchDataCase::getCaseTypeDescription(caseType), caseType,
7395 																  PerPatchDataCase::caseTypeUsesRefImageFromFile(caseType) ? (string() + "data/tessellation/" + caseName + "_ref.png").c_str() : DE_NULL));
7396 		}
7397 
7398 		for (int caseTypeI = 0; caseTypeI < GLPositionCase::CASETYPE_LAST; caseTypeI++)
7399 		{
7400 			const GLPositionCase::CaseType	caseType	= (GLPositionCase::CaseType)caseTypeI;
7401 			const char* const				caseName	= GLPositionCase::getCaseTypeName(caseType);
7402 
7403 			shaderInputOutputGroup->addChild(new GLPositionCase(m_context, caseName, "", caseType, "data/tessellation/gl_position_ref.png"));
7404 		}
7405 
7406 		shaderInputOutputGroup->addChild(new BarrierCase(m_context, "barrier", "Basic barrier usage", "data/tessellation/barrier_ref.png"));
7407 	}
7408 
7409 	{
7410 		TestCaseGroup* const miscDrawGroup = new TestCaseGroup(m_context, "misc_draw", "Miscellaneous draw-result-verifying cases");
7411 		addChild(miscDrawGroup);
7412 
7413 		for (int primitiveTypeI = 0; primitiveTypeI < TESSPRIMITIVETYPE_LAST; primitiveTypeI++)
7414 		{
7415 			const TessPrimitiveType primitiveType = (TessPrimitiveType)primitiveTypeI;
7416 			if (primitiveType == TESSPRIMITIVETYPE_ISOLINES)
7417 				continue;
7418 
7419 			const char* const primTypeName = getTessPrimitiveTypeShaderName(primitiveType);
7420 
7421 			for (int spacingI = 0; spacingI < SPACINGMODE_LAST; spacingI++)
7422 			{
7423 				const string caseName = string() + "fill_cover_" + primTypeName + "_" + getSpacingModeShaderName((SpacingMode)spacingI);
7424 
7425 				miscDrawGroup->addChild(new BasicTriangleFillCoverCase(m_context,
7426 																	   caseName.c_str(), "Check that there are no obvious gaps in the triangle-filled area of a tessellated shape",
7427 																	   primitiveType, (SpacingMode)spacingI,
7428 																	   ("data/tessellation/" + caseName + "_ref").c_str()));
7429 			}
7430 		}
7431 
7432 		for (int primitiveTypeI = 0; primitiveTypeI < TESSPRIMITIVETYPE_LAST; primitiveTypeI++)
7433 		{
7434 			const TessPrimitiveType primitiveType = (TessPrimitiveType)primitiveTypeI;
7435 			if (primitiveType == TESSPRIMITIVETYPE_ISOLINES)
7436 				continue;
7437 
7438 			const char* const primTypeName = getTessPrimitiveTypeShaderName(primitiveType);
7439 
7440 			for (int spacingI = 0; spacingI < SPACINGMODE_LAST; spacingI++)
7441 			{
7442 				const string caseName = string() + "fill_overlap_" + primTypeName + "_" + getSpacingModeShaderName((SpacingMode)spacingI);
7443 
7444 				miscDrawGroup->addChild(new BasicTriangleFillNonOverlapCase(m_context,
7445 																			caseName.c_str(), "Check that there are no obvious triangle overlaps in the triangle-filled area of a tessellated shape",
7446 																			primitiveType, (SpacingMode)spacingI,
7447 																			("data/tessellation/" + caseName + "_ref").c_str()));
7448 			}
7449 		}
7450 
7451 		for (int spacingI = 0; spacingI < SPACINGMODE_LAST; spacingI++)
7452 		{
7453 			const string caseName = string() + "isolines_" + getSpacingModeShaderName((SpacingMode)spacingI);
7454 
7455 			miscDrawGroup->addChild(new IsolinesRenderCase(m_context,
7456 														   caseName.c_str(), "Basic isolines render test",
7457 														   (SpacingMode)spacingI,
7458 														   ("data/tessellation/" + caseName + "_ref").c_str()));
7459 		}
7460 	}
7461 
7462 	{
7463 		TestCaseGroup* const commonEdgeGroup = new TestCaseGroup(m_context, "common_edge", "Draw multiple adjacent shapes and check that no cracks appear between them");
7464 		addChild(commonEdgeGroup);
7465 
7466 		for (int caseTypeI = 0; caseTypeI < CommonEdgeCase::CASETYPE_LAST; caseTypeI++)
7467 		{
7468 			for (int primitiveTypeI = 0; primitiveTypeI < TESSPRIMITIVETYPE_LAST; primitiveTypeI++)
7469 			{
7470 				const CommonEdgeCase::CaseType	caseType		= (CommonEdgeCase::CaseType)caseTypeI;
7471 				const TessPrimitiveType			primitiveType	= (TessPrimitiveType)primitiveTypeI;
7472 				if (primitiveType == TESSPRIMITIVETYPE_ISOLINES)
7473 						continue;
7474 
7475 				for (int spacingI = 0; spacingI < SPACINGMODE_LAST; spacingI++)
7476 				{
7477 					const SpacingMode	spacing		= (SpacingMode)spacingI;
7478 					const string		caseName	= (string() + getTessPrimitiveTypeShaderName(primitiveType)
7479 																+ "_" + getSpacingModeShaderName(spacing)
7480 																+ (caseType == CommonEdgeCase::CASETYPE_BASIC		? ""
7481 																 : caseType == CommonEdgeCase::CASETYPE_PRECISE		? "_precise"
7482 																 : DE_NULL));
7483 
7484 					commonEdgeGroup->addChild(new CommonEdgeCase(m_context, caseName.c_str(), "", primitiveType, spacing, caseType));
7485 				}
7486 			}
7487 		}
7488 	}
7489 
7490 	{
7491 		TestCaseGroup* const fractionalSpacingModeGroup = new TestCaseGroup(m_context, "fractional_spacing", "Test fractional spacing modes");
7492 		addChild(fractionalSpacingModeGroup);
7493 
7494 		fractionalSpacingModeGroup->addChild(new FractionalSpacingModeCase(m_context, "odd",	"", SPACINGMODE_FRACTIONAL_ODD));
7495 		fractionalSpacingModeGroup->addChild(new FractionalSpacingModeCase(m_context, "even",	"", SPACINGMODE_FRACTIONAL_EVEN));
7496 	}
7497 
7498 	{
7499 		TestCaseGroup* const primitiveDiscardGroup = new TestCaseGroup(m_context, "primitive_discard", "Test primitive discard with relevant outer tessellation level <= 0.0");
7500 		addChild(primitiveDiscardGroup);
7501 
7502 		for (int primitiveTypeI = 0; primitiveTypeI < TESSPRIMITIVETYPE_LAST; primitiveTypeI++)
7503 		{
7504 			for (int spacingI = 0; spacingI < SPACINGMODE_LAST; spacingI++)
7505 			{
7506 				for (int windingI = 0; windingI < WINDING_LAST; windingI++)
7507 				{
7508 					for (int usePointModeI = 0; usePointModeI <= 1; usePointModeI++)
7509 					{
7510 						const TessPrimitiveType		primitiveType	= (TessPrimitiveType)primitiveTypeI;
7511 						const SpacingMode			spacing			= (SpacingMode)spacingI;
7512 						const Winding				winding			= (Winding)windingI;
7513 						const bool					usePointMode	= usePointModeI != 0;
7514 
7515 						primitiveDiscardGroup->addChild(new PrimitiveDiscardCase(m_context, (string() + getTessPrimitiveTypeShaderName(primitiveType)
7516 																									  + "_" + getSpacingModeShaderName(spacing)
7517 																									  + "_" + getWindingShaderName(winding)
7518 																									  + (usePointMode ? "_point_mode" : "")).c_str(), "",
7519 																				 primitiveType, spacing, winding, usePointMode));
7520 					}
7521 				}
7522 			}
7523 		}
7524 	}
7525 
7526 	{
7527 		TestCaseGroup* const invarianceGroup							= new TestCaseGroup(m_context, "invariance",						"Test tessellation invariance rules");
7528 
7529 		TestCaseGroup* const invariantPrimitiveSetGroup					= new TestCaseGroup(m_context, "primitive_set",						"Test invariance rule #1");
7530 		TestCaseGroup* const invariantOuterEdgeGroup					= new TestCaseGroup(m_context, "outer_edge_division",				"Test invariance rule #2");
7531 		TestCaseGroup* const symmetricOuterEdgeGroup					= new TestCaseGroup(m_context, "outer_edge_symmetry",				"Test invariance rule #3");
7532 		TestCaseGroup* const outerEdgeVertexSetIndexIndependenceGroup	= new TestCaseGroup(m_context, "outer_edge_index_independence",		"Test invariance rule #4");
7533 		TestCaseGroup* const invariantTriangleSetGroup					= new TestCaseGroup(m_context, "triangle_set",						"Test invariance rule #5");
7534 		TestCaseGroup* const invariantInnerTriangleSetGroup				= new TestCaseGroup(m_context, "inner_triangle_set",				"Test invariance rule #6");
7535 		TestCaseGroup* const invariantOuterTriangleSetGroup				= new TestCaseGroup(m_context, "outer_triangle_set",				"Test invariance rule #7");
7536 		TestCaseGroup* const tessCoordComponentRangeGroup				= new TestCaseGroup(m_context, "tess_coord_component_range",		"Test invariance rule #8, first part");
7537 		TestCaseGroup* const oneMinusTessCoordComponentGroup			= new TestCaseGroup(m_context, "one_minus_tess_coord_component",	"Test invariance rule #8, second part");
7538 
7539 		addChild(invarianceGroup);
7540 		invarianceGroup->addChild(invariantPrimitiveSetGroup);
7541 		invarianceGroup->addChild(invariantOuterEdgeGroup);
7542 		invarianceGroup->addChild(symmetricOuterEdgeGroup);
7543 		invarianceGroup->addChild(outerEdgeVertexSetIndexIndependenceGroup);
7544 		invarianceGroup->addChild(invariantTriangleSetGroup);
7545 		invarianceGroup->addChild(invariantInnerTriangleSetGroup);
7546 		invarianceGroup->addChild(invariantOuterTriangleSetGroup);
7547 		invarianceGroup->addChild(tessCoordComponentRangeGroup);
7548 		invarianceGroup->addChild(oneMinusTessCoordComponentGroup);
7549 
7550 		for (int primitiveTypeI = 0; primitiveTypeI < TESSPRIMITIVETYPE_LAST; primitiveTypeI++)
7551 		{
7552 			const TessPrimitiveType		primitiveType	= (TessPrimitiveType)primitiveTypeI;
7553 			const string				primName		= getTessPrimitiveTypeShaderName(primitiveType);
7554 			const bool					triOrQuad		= primitiveType == TESSPRIMITIVETYPE_TRIANGLES || primitiveType == TESSPRIMITIVETYPE_QUADS;
7555 
7556 			for (int spacingI = 0; spacingI < SPACINGMODE_LAST; spacingI++)
7557 			{
7558 				const SpacingMode	spacing			= (SpacingMode)spacingI;
7559 				const string		primSpacName	= primName + "_" + getSpacingModeShaderName(spacing);
7560 
7561 				if (triOrQuad)
7562 				{
7563 					invariantOuterEdgeGroup->addChild		(new InvariantOuterEdgeCase			(m_context, primSpacName.c_str(), "", primitiveType, spacing));
7564 					invariantTriangleSetGroup->addChild		(new InvariantTriangleSetCase		(m_context, primSpacName.c_str(), "", primitiveType, spacing));
7565 					invariantInnerTriangleSetGroup->addChild(new InvariantInnerTriangleSetCase	(m_context, primSpacName.c_str(), "", primitiveType, spacing));
7566 					invariantOuterTriangleSetGroup->addChild(new InvariantOuterTriangleSetCase	(m_context, primSpacName.c_str(), "", primitiveType, spacing));
7567 				}
7568 
7569 				for (int windingI = 0; windingI < WINDING_LAST; windingI++)
7570 				{
7571 					const Winding	winding				= (Winding)windingI;
7572 					const string	primSpacWindName	= primSpacName + "_" + getWindingShaderName(winding);
7573 
7574 					for (int usePointModeI = 0; usePointModeI <= 1; usePointModeI++)
7575 					{
7576 						const bool		usePointMode			= usePointModeI != 0;
7577 						const string	primSpacWindPointName	= primSpacWindName + (usePointMode ? "_point_mode" : "");
7578 
7579 						invariantPrimitiveSetGroup->addChild		(new InvariantPrimitiveSetCase			(m_context, primSpacWindPointName.c_str(), "", primitiveType, spacing, winding, usePointMode));
7580 						symmetricOuterEdgeGroup->addChild			(new SymmetricOuterEdgeCase				(m_context, primSpacWindPointName.c_str(), "", primitiveType, spacing, winding, usePointMode));
7581 						tessCoordComponentRangeGroup->addChild		(new TessCoordComponentRangeCase		(m_context, primSpacWindPointName.c_str(), "", primitiveType, spacing, winding, usePointMode));
7582 						oneMinusTessCoordComponentGroup->addChild	(new OneMinusTessCoordComponentCase		(m_context, primSpacWindPointName.c_str(), "", primitiveType, spacing, winding, usePointMode));
7583 
7584 						if (triOrQuad)
7585 							outerEdgeVertexSetIndexIndependenceGroup->addChild(new OuterEdgeVertexSetIndexIndependenceCase(m_context, primSpacWindPointName.c_str(), "",
7586 																														   primitiveType, spacing, winding, usePointMode));
7587 					}
7588 				}
7589 			}
7590 		}
7591 	}
7592 
7593 	{
7594 		static const struct
7595 		{
7596 			const char*					name;
7597 			const char*					description;
7598 			UserDefinedIOCase::IOType	ioType;
7599 		} ioCases[] =
7600 		{
7601 			{ "per_patch",					"Per-patch TCS outputs",					UserDefinedIOCase::IO_TYPE_PER_PATCH				},
7602 			{ "per_patch_array",			"Per-patch array TCS outputs",				UserDefinedIOCase::IO_TYPE_PER_PATCH_ARRAY			},
7603 			{ "per_patch_block",			"Per-patch TCS outputs in IO block",		UserDefinedIOCase::IO_TYPE_PER_PATCH_BLOCK			},
7604 			{ "per_patch_block_array",		"Per-patch TCS outputs in IO block array",	UserDefinedIOCase::IO_TYPE_PER_PATCH_BLOCK_ARRAY	},
7605 			{ "per_vertex",					"Per-vertex TCS outputs",					UserDefinedIOCase::IO_TYPE_PER_VERTEX				},
7606 			{ "per_vertex_block",			"Per-vertex TCS outputs in IO block",		UserDefinedIOCase::IO_TYPE_PER_VERTEX_BLOCK			},
7607 		};
7608 
7609 		TestCaseGroup* const userDefinedIOGroup = new TestCaseGroup(m_context, "user_defined_io", "Test non-built-in per-patch and per-vertex inputs and outputs");
7610 		addChild(userDefinedIOGroup);
7611 
7612 		for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(ioCases); ++ndx)
7613 		{
7614 			TestCaseGroup* const ioTypeGroup = new TestCaseGroup(m_context, ioCases[ndx].name, ioCases[ndx].description);
7615 			userDefinedIOGroup->addChild(ioTypeGroup);
7616 
7617 			for (int vertexArraySizeI = 0; vertexArraySizeI < UserDefinedIOCase::VERTEX_IO_ARRAY_SIZE_LAST; vertexArraySizeI++)
7618 			{
7619 				const UserDefinedIOCase::VertexIOArraySize	vertexArraySize			= (UserDefinedIOCase::VertexIOArraySize)vertexArraySizeI;
7620 				TestCaseGroup* const						vertexArraySizeGroup	= new TestCaseGroup(m_context,
7621 																										vertexArraySizeI == UserDefinedIOCase::VERTEX_IO_ARRAY_SIZE_IMPLICIT
7622 																											? "vertex_io_array_size_implicit"
7623 																									  : vertexArraySizeI == UserDefinedIOCase::VERTEX_IO_ARRAY_SIZE_EXPLICIT_SHADER_BUILTIN
7624 																											? "vertex_io_array_size_shader_builtin"
7625 																									  : vertexArraySizeI == UserDefinedIOCase::VERTEX_IO_ARRAY_SIZE_EXPLICIT_QUERY
7626 																											? "vertex_io_array_size_query"
7627 																									  : DE_NULL,
7628 																									    "");
7629 				ioTypeGroup->addChild(vertexArraySizeGroup);
7630 
7631 				for (int primitiveTypeI = 0; primitiveTypeI < TESSPRIMITIVETYPE_LAST; primitiveTypeI++)
7632 				{
7633 					const TessPrimitiveType primitiveType = (TessPrimitiveType)primitiveTypeI;
7634 					vertexArraySizeGroup->addChild(new UserDefinedIOCase(m_context, getTessPrimitiveTypeShaderName(primitiveType), "", primitiveType, ioCases[ndx].ioType, vertexArraySize, UserDefinedIOCase::TESS_CONTROL_OUT_ARRAY_SIZE_IMPLICIT,
7635 																		 (string() + "data/tessellation/user_defined_io_" + getTessPrimitiveTypeShaderName(primitiveType) + "_ref.png").c_str()));
7636 				}
7637 
7638 				if (ioCases[ndx].ioType == UserDefinedIOCase::IO_TYPE_PER_VERTEX
7639 					|| ioCases[ndx].ioType == UserDefinedIOCase::IO_TYPE_PER_VERTEX_BLOCK)
7640 				{
7641 					for (int primitiveTypeI = 0; primitiveTypeI < TESSPRIMITIVETYPE_LAST; primitiveTypeI++)
7642 					{
7643 						const TessPrimitiveType primitiveType = (TessPrimitiveType)primitiveTypeI;
7644 						vertexArraySizeGroup->addChild(new UserDefinedIOCase(m_context, (string(getTessPrimitiveTypeShaderName(primitiveType)) + "_explicit_tcs_out_size").c_str(), "", primitiveType, ioCases[ndx].ioType, vertexArraySize, UserDefinedIOCase::TESS_CONTROL_OUT_ARRAY_SIZE_LAYOUT,
7645 																			 (string() + "data/tessellation/user_defined_io_" + getTessPrimitiveTypeShaderName(primitiveType) + "_ref.png").c_str()));
7646 					}
7647 				}
7648 			}
7649 		}
7650 
7651 		{
7652 			de::MovePtr<TestCaseGroup>	negativeGroup	(new TestCaseGroup(m_context, "negative", "Negative cases"));
7653 
7654 			{
7655 				de::MovePtr<TestCaseGroup>			es31Group		(new TestCaseGroup(m_context, "es31", "GLSL ES 3.1 Negative cases"));
7656 				gls::ShaderLibrary					shaderLibrary	(m_testCtx, m_context.getRenderContext(), m_context.getContextInfo());
7657 				const std::vector<tcu::TestNode*>	children		= shaderLibrary.loadShaderFile("shaders/es31/tessellation_negative_user_defined_io.test");
7658 
7659 				for (int i = 0; i < (int)children.size(); i++)
7660 					es31Group->addChild(children[i]);
7661 
7662 				negativeGroup->addChild(es31Group.release());
7663 			}
7664 
7665 			{
7666 				de::MovePtr<TestCaseGroup>			es32Group		(new TestCaseGroup(m_context, "es32", "GLSL ES 3.2 Negative cases"));
7667 				gls::ShaderLibrary					shaderLibrary	(m_testCtx, m_context.getRenderContext(), m_context.getContextInfo());
7668 				const std::vector<tcu::TestNode*>	children		= shaderLibrary.loadShaderFile("shaders/es32/tessellation_negative_user_defined_io.test");
7669 
7670 				for (int i = 0; i < (int)children.size(); i++)
7671 					es32Group->addChild(children[i]);
7672 
7673 				negativeGroup->addChild(es32Group.release());
7674 			}
7675 
7676 			userDefinedIOGroup->addChild(negativeGroup.release());
7677 		}
7678 	}
7679 }
7680 
7681 } // Functional
7682 } // gles31
7683 } // deqp
7684