• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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::__anon755cd4500211::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::__anon755cd4500211::TransformFeedbackHandler::Result305 		Result (void)								: numPrimitives(-1) {}
Resultdeqp::gles31::Functional::__anon755cd4500211::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::__anon755cd4500211::OuterEdgeDescription608 	OuterEdgeDescription (int i, float c0)			: constantCoordinateIndex(i), numConstantCoordinateValueChoices(1) { constantCoordinateValueChoices[0] = c0; }
OuterEdgeDescriptiondeqp::gles31::Functional::__anon755cd4500211::OuterEdgeDescription609 	OuterEdgeDescription (int i, float c0, float c1)	: constantCoordinateIndex(i), numConstantCoordinateValueChoices(2) { constantCoordinateValueChoices[0] = c0; constantCoordinateValueChoices[1] = c1; }
610 
descriptiondeqp::gles31::Functional::__anon755cd4500211::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::__anon755cd4500211::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::__anon755cd4500211::VerifyFractionalSpacingSingleInternal::Segment1199 	Segment (void)						: index(-1),		length(-1.0f)	{}
Segmentdeqp::gles31::Functional::__anon755cd4500211::VerifyFractionalSpacingSingleInternal::Segment1200 	Segment (int index_, float length_)	: index(index_),	length(length_)	{}
1201 
lengthsdeqp::gles31::Functional::__anon755cd4500211::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::__anon755cd4500211::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 
supportsES32orGL45(Context & context)1530 static bool supportsES32orGL45(Context& context)
1531 {
1532 	glu::ContextType contextType = context.getRenderContext().getType();
1533 	return glu::contextSupports(contextType, glu::ApiType::es(3, 2)) ||
1534 		   glu::contextSupports(contextType, glu::ApiType::core(4, 5));
1535 }
1536 
checkGPUShader5Support(Context & context)1537 static void checkGPUShader5Support (Context& context)
1538 {
1539 	TCU_CHECK_AND_THROW(NotSupportedError, supportsES32orGL45(context) || context.getContextInfo().isExtensionSupported("GL_EXT_gpu_shader5"), "GL_EXT_gpu_shader5 is not supported");
1540 }
1541 
checkTessellationSupport(Context & context)1542 static void checkTessellationSupport (Context& context)
1543 {
1544 	TCU_CHECK_AND_THROW(NotSupportedError, supportsES32orGL45(context) || context.getContextInfo().isExtensionSupported("GL_EXT_tessellation_shader"), "GL_EXT_tessellation_shader is not supported");
1545 }
1546 
specializeShader(Context & context,const char * code)1547 static std::string specializeShader(Context& context, const char* code)
1548 {
1549 	const glu::ContextType				contextType			= context.getRenderContext().getType();
1550 	const glu::GLSLVersion				glslVersion			= glu::getContextTypeGLSLVersion(contextType);
1551 	const bool							cSupportsES32orGL45	= supportsES32orGL45(context);
1552 
1553 	std::map<std::string, std::string>	specializationMap =
1554 	{
1555 		{ "GLSL_VERSION_DECL",					glu::getGLSLVersionDeclaration(glslVersion) },
1556 		{ "GPU_SHADER5_REQUIRE",				cSupportsES32orGL45 ? "" : "#extension GL_EXT_gpu_shader5 : require" },
1557 		{ "TESSELLATION_SHADER_REQUIRE",		cSupportsES32orGL45 ? "" : "#extension GL_EXT_tessellation_shader : require" },
1558 		{ "GLSL_PER_VERTEX_OUT",				"" },		// needed for GL4.5
1559 		{ "GLSL_PER_VERTEX_IN_ARR",				"" },
1560 		{ "GLSL_PER_VERTEX_OUT_ARR",			"" },
1561 		{ "GLSL_PRECISE_PER_VERTEX_OUT",		"" },
1562 		{ "GLSL_PRECISE_PER_VERTEX_IN_ARR",		"" },
1563 		{ "GLSL_PRECISE_PER_VERTEX_OUT_ARR",	"" }
1564 	};
1565 
1566 	// for gl4.5 we need to add per vertex sections
1567 	if (!glu::isContextTypeES(context.getRenderContext().getType()))
1568 	{
1569 		specializationMap["GLSL_PER_VERTEX_OUT"]				= "out gl_PerVertex { vec4 gl_Position; };\n";
1570 		specializationMap["GLSL_PER_VERTEX_IN_ARR"]				= "in gl_PerVertex { vec4 gl_Position; } gl_in[];\n";
1571 		specializationMap["GLSL_PER_VERTEX_OUT_ARR"]			= "out gl_PerVertex { vec4 gl_Position; } gl_out[];\n";
1572 		specializationMap["GLSL_PRECISE_PER_VERTEX_OUT"]                = "out gl_PerVertex { vec4 gl_Position; };\nprecise gl_Position;\n";
1573 		specializationMap["GLSL_PRECISE_PER_VERTEX_IN_ARR"]             = "in gl_PerVertex { vec4 gl_Position; } gl_in[];\nprecise gl_in;\n";
1574 		specializationMap["GLSL_PRECISE_PER_VERTEX_OUT_ARR"]    = "out gl_PerVertex { vec4 gl_Position; } gl_out[];\nprecise gl_out;\n";
1575 	}
1576 
1577 	return tcu::StringTemplate(code).specialize(specializationMap);
1578 }
1579 
1580 // Draw primitives with shared edges and check that no cracks are visible at the shared edges.
1581 class CommonEdgeCase : public TestCase
1582 {
1583 public:
1584 	enum CaseType
1585 	{
1586 		CASETYPE_BASIC = 0,		//!< Order patch vertices such that when two patches share a vertex, it's at the same index for both.
1587 		CASETYPE_PRECISE,		//!< Vertex indices don't match like for CASETYPE_BASIC, but other measures are taken, using the 'precise' qualifier.
1588 
1589 		CASETYPE_LAST
1590 	};
1591 
CommonEdgeCase(Context & context,const char * name,const char * description,TessPrimitiveType primitiveType,SpacingMode spacing,CaseType caseType)1592 	CommonEdgeCase (Context& context, const char* name, const char* description, TessPrimitiveType primitiveType, SpacingMode spacing, CaseType caseType)
1593 		: TestCase			(context, name, description)
1594 		, m_primitiveType	(primitiveType)
1595 		, m_spacing			(spacing)
1596 		, m_caseType		(caseType)
1597 	{
1598 		DE_ASSERT(m_primitiveType == TESSPRIMITIVETYPE_TRIANGLES || m_primitiveType == TESSPRIMITIVETYPE_QUADS);
1599 	}
1600 
1601 	void							init		(void);
1602 	void							deinit		(void);
1603 	IterateResult					iterate		(void);
1604 
1605 private:
1606 	static const int				RENDER_SIZE = 256;
1607 
1608 	const TessPrimitiveType			m_primitiveType;
1609 	const SpacingMode				m_spacing;
1610 	const CaseType					m_caseType;
1611 
1612 	SharedPtr<const ShaderProgram>	m_program;
1613 };
1614 
init(void)1615 void CommonEdgeCase::init (void)
1616 {
1617 	bool isGL45 = glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 5));
1618 	if (!isGL45)
1619 	{
1620 		checkTessellationSupport(m_context);
1621 		if (m_caseType == CASETYPE_PRECISE)
1622 			checkGPUShader5Support(m_context);
1623 	}
1624 
1625 	checkRenderTargetSize(m_context.getRenderTarget(), RENDER_SIZE);
1626 
1627 	std::string vertexShaderTemplate			("${GLSL_VERSION_DECL}\n"
1628 													 "${GLSL_PER_VERTEX_OUT}\n"
1629 													 "\n"
1630 													 "in highp vec2 in_v_position;\n"
1631 													 "in highp float in_v_tessParam;\n"
1632 													 "\n"
1633 													 "out highp vec2 in_tc_position;\n"
1634 													 "out highp float in_tc_tessParam;\n"
1635 													 "\n"
1636 													 "void main (void)\n"
1637 													 "{\n"
1638 													 "	in_tc_position = in_v_position;\n"
1639 													 "	in_tc_tessParam = in_v_tessParam;\n"
1640 												 "}\n");
1641 
1642 	std::string tessellationControlTemplate		("${GLSL_VERSION_DECL}\n"
1643 												 "${TESSELLATION_SHADER_REQUIRE}\n"
1644 												 + string(m_caseType == CASETYPE_PRECISE ? "${GPU_SHADER5_REQUIRE}\n" : "") +
1645 													 "${GLSL_PER_VERTEX_IN_ARR}\n"
1646 													 "${GLSL_PER_VERTEX_OUT_ARR}\n"
1647 													 "\n"
1648 													 "layout (vertices = " + string(m_primitiveType == TESSPRIMITIVETYPE_TRIANGLES ? "3" : m_primitiveType == TESSPRIMITIVETYPE_QUADS ? "4" : DE_NULL) + ") out;\n"
1649 													 "\n"
1650 													 "in highp vec2 in_tc_position[];\n"
1651 													 "in highp float in_tc_tessParam[];\n"
1652 													 "\n"
1653 													 "out highp vec2 in_te_position[];\n"
1654 													 "\n"
1655 													 + (m_caseType == CASETYPE_PRECISE ? "precise gl_TessLevelOuter;\n\n" : "") +
1656 													 "void main (void)\n"
1657 													 "{\n"
1658 													 "	in_te_position[gl_InvocationID] = in_tc_position[gl_InvocationID];\n"
1659 													 "\n"
1660 													 "	gl_TessLevelInner[0] = 5.0;\n"
1661 													 "	gl_TessLevelInner[1] = 5.0;\n"
1662 													 "\n"
1663 													 + (m_primitiveType == TESSPRIMITIVETYPE_TRIANGLES ?
1664 														"	gl_TessLevelOuter[0] = 1.0 + 59.0 * 0.5 * (in_tc_tessParam[1] + in_tc_tessParam[2]);\n"
1665 														"	gl_TessLevelOuter[1] = 1.0 + 59.0 * 0.5 * (in_tc_tessParam[2] + in_tc_tessParam[0]);\n"
1666 														"	gl_TessLevelOuter[2] = 1.0 + 59.0 * 0.5 * (in_tc_tessParam[0] + in_tc_tessParam[1]);\n"
1667 													  : m_primitiveType == TESSPRIMITIVETYPE_QUADS ?
1668 														"	gl_TessLevelOuter[0] = 1.0 + 59.0 * 0.5 * (in_tc_tessParam[0] + in_tc_tessParam[2]);\n"
1669 														"	gl_TessLevelOuter[1] = 1.0 + 59.0 * 0.5 * (in_tc_tessParam[1] + in_tc_tessParam[0]);\n"
1670 														"	gl_TessLevelOuter[2] = 1.0 + 59.0 * 0.5 * (in_tc_tessParam[3] + in_tc_tessParam[1]);\n"
1671 														"	gl_TessLevelOuter[3] = 1.0 + 59.0 * 0.5 * (in_tc_tessParam[2] + in_tc_tessParam[3]);\n"
1672 													  : DE_NULL) +
1673 												 "}\n");
1674 
1675 	std::string tessellationEvaluationTemplate	("${GLSL_VERSION_DECL}\n"
1676 												 "${TESSELLATION_SHADER_REQUIRE}\n"
1677 												 + string(m_caseType == CASETYPE_PRECISE ? "${GPU_SHADER5_REQUIRE}\n" : "") +
1678 													 "${GLSL_PRECISE_PER_VERTEX_IN_ARR}\n"
1679 													 "${GLSL_PRECISE_PER_VERTEX_OUT}\n"
1680 													 "\n"
1681 													 + getTessellationEvaluationInLayoutString(m_primitiveType, m_spacing) +
1682 													 "\n"
1683 													 "in highp vec2 in_te_position[];\n"
1684 													 "\n"
1685 													 "out mediump vec4 in_f_color;\n"
1686 													 "\n"
1687 													 + ((m_caseType == CASETYPE_PRECISE && !isGL45) ? "precise gl_Position;\n\n" : "") +
1688 													 "void main (void)\n"
1689 													 "{\n"
1690 													 + (m_primitiveType == TESSPRIMITIVETYPE_TRIANGLES ?
1691 														"	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"
1692 														"\n"
1693 														"	highp float f = sqrt(3.0 * min(gl_TessCoord.x, min(gl_TessCoord.y, gl_TessCoord.z))) * 0.5 + 0.5;\n"
1694 														"	in_f_color = vec4(gl_TessCoord*f, 1.0);\n"
1695 													  : m_primitiveType == TESSPRIMITIVETYPE_QUADS ?
1696 													    string()
1697 														+ (m_caseType == CASETYPE_BASIC ?
1698 															"	highp vec2 pos = (1.0-gl_TessCoord.x)*(1.0-gl_TessCoord.y)*in_te_position[0]\n"
1699 															"	               + (    gl_TessCoord.x)*(1.0-gl_TessCoord.y)*in_te_position[1]\n"
1700 															"	               + (1.0-gl_TessCoord.x)*(    gl_TessCoord.y)*in_te_position[2]\n"
1701 															"	               + (    gl_TessCoord.x)*(    gl_TessCoord.y)*in_te_position[3];\n"
1702 														 : m_caseType == CASETYPE_PRECISE ?
1703 															"	highp vec2 a = (1.0-gl_TessCoord.x)*(1.0-gl_TessCoord.y)*in_te_position[0];\n"
1704 															"	highp vec2 b = (    gl_TessCoord.x)*(1.0-gl_TessCoord.y)*in_te_position[1];\n"
1705 															"	highp vec2 c = (1.0-gl_TessCoord.x)*(    gl_TessCoord.y)*in_te_position[2];\n"
1706 															"	highp vec2 d = (    gl_TessCoord.x)*(    gl_TessCoord.y)*in_te_position[3];\n"
1707 															"	highp vec2 pos = a+b+c+d;\n"
1708 														 : DE_NULL) +
1709 														"\n"
1710 														"	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"
1711 														"	in_f_color = vec4(0.1, gl_TessCoord.xy*f, 1.0);\n"
1712 													  : DE_NULL) +
1713 													 "\n"
1714 													 "	// Offset the position slightly, based on the parity of the bits in the float representation.\n"
1715 													 "	// This is done to detect possible small differences in edge vertex positions between patches.\n"
1716 													 "	uvec2 bits = floatBitsToUint(pos);\n"
1717 													 "	uint numBits = 0u;\n"
1718 													 "	for (uint i = 0u; i < 32u; i++)\n"
1719 													 "		numBits += ((bits[0] >> i) & 1u) + ((bits[1] >> i) & 1u);\n"
1720 													 "	pos += float(numBits&1u)*0.04;\n"
1721 													 "\n"
1722 													 "	gl_Position = vec4(pos, 0.0, 1.0);\n"
1723 												 "}\n");
1724 
1725 	std::string fragmentShaderTemplate			("${GLSL_VERSION_DECL}\n"
1726 													 "\n"
1727 													 "layout (location = 0) out mediump vec4 o_color;\n"
1728 													 "\n"
1729 													 "in mediump vec4 in_f_color;\n"
1730 													 "\n"
1731 													 "void main (void)\n"
1732 													 "{\n"
1733 													 "	o_color = in_f_color;\n"
1734 												 "}\n");
1735 
1736 	m_program = SharedPtr<const ShaderProgram>(new ShaderProgram(m_context.getRenderContext(), glu::ProgramSources()
1737 			<< glu::VertexSource					(specializeShader(m_context, vertexShaderTemplate.c_str()))
1738 			<< glu::TessellationControlSource		(specializeShader(m_context, tessellationControlTemplate.c_str()))
1739 			<< glu::TessellationEvaluationSource	(specializeShader(m_context, tessellationEvaluationTemplate.c_str()))
1740 			<< glu::FragmentSource					(specializeShader(m_context, fragmentShaderTemplate.c_str()))));
1741 
1742 	m_testCtx.getLog() << *m_program;
1743 	if (!m_program->isOk())
1744 		TCU_FAIL("Program compilation failed");
1745 }
1746 
deinit(void)1747 void CommonEdgeCase::deinit (void)
1748 {
1749 	m_program.clear();
1750 }
1751 
iterate(void)1752 CommonEdgeCase::IterateResult CommonEdgeCase::iterate (void)
1753 {
1754 	TestLog&					log						= m_testCtx.getLog();
1755 	const RenderContext&		renderCtx				= m_context.getRenderContext();
1756 	const RandomViewport		viewport				(renderCtx.getRenderTarget(), RENDER_SIZE, RENDER_SIZE, deStringHash(getName()));
1757 	const deUint32				programGL				= m_program->getProgram();
1758 	const glw::Functions&		gl						= renderCtx.getFunctions();
1759 
1760 	const int					gridWidth				= 4;
1761 	const int					gridHeight				= 4;
1762 	const int					numVertices				= (gridWidth+1)*(gridHeight+1);
1763 	const int					numIndices				= gridWidth*gridHeight * (m_primitiveType == TESSPRIMITIVETYPE_TRIANGLES ? 3*2 : m_primitiveType == TESSPRIMITIVETYPE_QUADS ? 4 : -1);
1764 	const int					numPosCompsPerVertex	= 2;
1765 	const int					totalNumPosComps		= numPosCompsPerVertex*numVertices;
1766 	vector<float>				gridPosComps;
1767 	vector<float>				gridTessParams;
1768 	vector<deUint16>			gridIndices;
1769 
1770 	gridPosComps.reserve(totalNumPosComps);
1771 	gridTessParams.reserve(numVertices);
1772 	gridIndices.reserve(numIndices);
1773 
1774 	{
1775 		for (int i = 0; i < gridHeight+1; i++)
1776 		for (int j = 0; j < gridWidth+1; j++)
1777 		{
1778 			gridPosComps.push_back(-1.0f + 2.0f * ((float)j + 0.5f) / (float)(gridWidth+1));
1779 			gridPosComps.push_back(-1.0f + 2.0f * ((float)i + 0.5f) / (float)(gridHeight+1));
1780 			gridTessParams.push_back((float)(i*(gridWidth+1) + j) / (float)(numVertices-1));
1781 		}
1782 	}
1783 
1784 	// Generate patch vertex indices.
1785 	// \note If CASETYPE_BASIC, the vertices are ordered such that when multiple
1786 	//		 triangles/quads share a vertex, it's at the same index for everyone.
1787 
1788 	if (m_primitiveType == TESSPRIMITIVETYPE_TRIANGLES)
1789 	{
1790 		for (int i = 0; i < gridHeight; i++)
1791 		for (int j = 0; j < gridWidth; j++)
1792 		{
1793 			const deUint16 corners[4] =
1794 			{
1795 				(deUint16)((i+0)*(gridWidth+1) + j+0),
1796 				(deUint16)((i+0)*(gridWidth+1) + j+1),
1797 				(deUint16)((i+1)*(gridWidth+1) + j+0),
1798 				(deUint16)((i+1)*(gridWidth+1) + j+1)
1799 			};
1800 
1801 			const int secondTriangleVertexIndexOffset = m_caseType == CASETYPE_BASIC	? 0
1802 													  : m_caseType == CASETYPE_PRECISE	? 1
1803 													  : -1;
1804 			DE_ASSERT(secondTriangleVertexIndexOffset != -1);
1805 
1806 			for (int k = 0; k < 3; k++)
1807 				gridIndices.push_back(corners[(k+0 + i + (2-j%3)) % 3]);
1808 			for (int k = 0; k < 3; k++)
1809 				gridIndices.push_back(corners[(k+2 + i + (2-j%3) + secondTriangleVertexIndexOffset) % 3 + 1]);
1810 		}
1811 	}
1812 	else if (m_primitiveType == TESSPRIMITIVETYPE_QUADS)
1813 	{
1814 		for (int i = 0; i < gridHeight; i++)
1815 		for (int j = 0; j < gridWidth; j++)
1816 		{
1817 			// \note The vertices are ordered such that when multiple quads
1818 			//		 share a vertices, it's at the same index for everyone.
1819 			for (int m = 0; m < 2; m++)
1820 			for (int n = 0; n < 2; n++)
1821 				gridIndices.push_back((deUint16)((i+(i+m)%2)*(gridWidth+1) + j+(j+n)%2));
1822 
1823 			if(m_caseType == CASETYPE_PRECISE && (i+j) % 2 == 0)
1824 				std::reverse(gridIndices.begin() + (gridIndices.size() - 4),
1825 							 gridIndices.begin() + gridIndices.size());
1826 		}
1827 	}
1828 	else
1829 		DE_ASSERT(false);
1830 
1831 	DE_ASSERT((int)gridPosComps.size() == totalNumPosComps);
1832 	DE_ASSERT((int)gridTessParams.size() == numVertices);
1833 	DE_ASSERT((int)gridIndices.size() == numIndices);
1834 
1835 	setViewport(gl, viewport);
1836 	gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
1837 	gl.useProgram(programGL);
1838 
1839 	{
1840 		gl.patchParameteri(GL_PATCH_VERTICES, m_primitiveType == TESSPRIMITIVETYPE_TRIANGLES ? 3 : m_primitiveType == TESSPRIMITIVETYPE_QUADS ? 4 : -1);
1841 		gl.clear(GL_COLOR_BUFFER_BIT);
1842 
1843 		const glu::VertexArrayBinding attrBindings[] =
1844 		{
1845 			glu::va::Float("in_v_position", numPosCompsPerVertex, numVertices, 0, &gridPosComps[0]),
1846 			glu::va::Float("in_v_tessParam", 1, numVertices, 0, &gridTessParams[0])
1847 		};
1848 
1849 		glu::draw(renderCtx, programGL, DE_LENGTH_OF_ARRAY(attrBindings), &attrBindings[0],
1850 			glu::pr::Patches((int)gridIndices.size(), &gridIndices[0]));
1851 		GLU_EXPECT_NO_ERROR(gl.getError(), "Draw failed");
1852 	}
1853 
1854 	{
1855 		const tcu::Surface rendered = getPixels(renderCtx, viewport);
1856 
1857 		log << TestLog::Image("RenderedImage", "Rendered Image", rendered)
1858 			<< TestLog::Message << "Note: coloring is done to clarify the positioning and orientation of the "
1859 								<< (m_primitiveType == TESSPRIMITIVETYPE_TRIANGLES ? "triangles" : m_primitiveType == TESSPRIMITIVETYPE_QUADS ? "quads" : DE_NULL)
1860 								<< "; the color of a vertex corresponds to the index of that vertex in the patch"
1861 								<< TestLog::EndMessage;
1862 
1863 		if (m_caseType == CASETYPE_BASIC)
1864 			log << TestLog::Message << "Note: each shared vertex has the same index among the primitives it belongs to" << TestLog::EndMessage;
1865 		else if (m_caseType == CASETYPE_PRECISE)
1866 			log << TestLog::Message << "Note: the 'precise' qualifier is used to avoid cracks between primitives" << TestLog::EndMessage;
1867 		else
1868 			DE_ASSERT(false);
1869 
1870 		// Ad-hoc result verification - check that a certain rectangle in the image contains no black pixels.
1871 
1872 		const int startX	= (int)(0.15f * (float)rendered.getWidth());
1873 		const int endX		= (int)(0.85f * (float)rendered.getWidth());
1874 		const int startY	= (int)(0.15f * (float)rendered.getHeight());
1875 		const int endY		= (int)(0.85f * (float)rendered.getHeight());
1876 
1877 		for (int y = startY; y < endY; y++)
1878 		for (int x = startX; x < endX; x++)
1879 		{
1880 			const tcu::RGBA pixel = rendered.getPixel(x, y);
1881 
1882 			if (pixel.getRed() == 0 && pixel.getGreen() == 0 && pixel.getBlue() == 0)
1883 			{
1884 				log << TestLog::Message << "Failure: there seem to be cracks in the rendered result" << TestLog::EndMessage
1885 					<< TestLog::Message << "Note: pixel with zero r, g and b channels found at " << tcu::IVec2(x, y) << TestLog::EndMessage;
1886 
1887 				m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image verification failed");
1888 				return STOP;
1889 			}
1890 		}
1891 
1892 		log << TestLog::Message << "Success: there seem to be no cracks in the rendered result" << TestLog::EndMessage;
1893 	}
1894 
1895 	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
1896 	return STOP;
1897 }
1898 
1899 // Check tessellation coordinates (read with transform feedback).
1900 class TessCoordCase : public TestCase
1901 {
1902 public:
TessCoordCase(Context & context,const char * name,const char * description,TessPrimitiveType primitiveType,SpacingMode spacing)1903 					TessCoordCase (Context& context, const char* name, const char* description, TessPrimitiveType primitiveType, SpacingMode spacing)
1904 						: TestCase			(context, name, description)
1905 						, m_primitiveType	(primitiveType)
1906 						, m_spacing			(spacing)
1907 					{
1908 					}
1909 
1910 	void			init		(void);
1911 	void			deinit		(void);
1912 	IterateResult	iterate		(void);
1913 
1914 private:
1915 	struct TessLevels
1916 	{
1917 		float inner[2];
1918 		float outer[4];
1919 	};
1920 
1921 	static const int				RENDER_SIZE = 16;
1922 
1923 	vector<TessLevels>				genTessLevelCases (void) const;
1924 
1925 	const TessPrimitiveType			m_primitiveType;
1926 	const SpacingMode				m_spacing;
1927 
1928 	SharedPtr<const ShaderProgram>	m_program;
1929 };
1930 
init(void)1931 void TessCoordCase::init (void)
1932 {
1933 	checkTessellationSupport(m_context);
1934 	checkRenderTargetSize(m_context.getRenderTarget(), RENDER_SIZE);
1935 
1936 	std::string vertexShaderTemplate			("${GLSL_VERSION_DECL}\n"
1937 													 "${GLSL_PER_VERTEX_OUT}\n"
1938 													 "\n"
1939 													 "void main (void)\n"
1940 													 "{\n"
1941 												 "}\n");
1942 
1943 	std::string tessellationControlTemplate		("${GLSL_VERSION_DECL}\n"
1944 												 "${TESSELLATION_SHADER_REQUIRE}\n"
1945 													 "${GLSL_PER_VERTEX_IN_ARR}\n"
1946 													 "${GLSL_PER_VERTEX_OUT_ARR}\n"
1947 													 "\n"
1948 													 "layout (vertices = 1) out;\n"
1949 													 "\n"
1950 													 "uniform mediump float u_tessLevelInner0;\n"
1951 													 "uniform mediump float u_tessLevelInner1;\n"
1952 													 "\n"
1953 													 "uniform mediump float u_tessLevelOuter0;\n"
1954 													 "uniform mediump float u_tessLevelOuter1;\n"
1955 													 "uniform mediump float u_tessLevelOuter2;\n"
1956 													 "uniform mediump float u_tessLevelOuter3;\n"
1957 													 "\n"
1958 													 "void main (void)\n"
1959 													 "{\n"
1960 													 "	gl_TessLevelInner[0] = u_tessLevelInner0;\n"
1961 													 "	gl_TessLevelInner[1] = u_tessLevelInner1;\n"
1962 													 "\n"
1963 													 "	gl_TessLevelOuter[0] = u_tessLevelOuter0;\n"
1964 													 "	gl_TessLevelOuter[1] = u_tessLevelOuter1;\n"
1965 													 "	gl_TessLevelOuter[2] = u_tessLevelOuter2;\n"
1966 													 "	gl_TessLevelOuter[3] = u_tessLevelOuter3;\n"
1967 												 "}\n");
1968 
1969 	std::string tessellationEvaluationTemplate	("${GLSL_VERSION_DECL}\n"
1970 												 "${TESSELLATION_SHADER_REQUIRE}\n"
1971 													 "${GLSL_PER_VERTEX_IN_ARR}\n"
1972 													 "${GLSL_PER_VERTEX_OUT}\n"
1973 													 "\n"
1974 													 + getTessellationEvaluationInLayoutString(m_primitiveType, m_spacing, true) +
1975 													 "\n"
1976 													 "out highp vec3 out_te_tessCoord;\n"
1977 													 "\n"
1978 													 "void main (void)\n"
1979 													 "{\n"
1980 													 "	out_te_tessCoord = gl_TessCoord;\n"
1981 													 "	gl_Position = vec4(gl_TessCoord.xy*1.6 - 0.8, 0.0, 1.0);\n"
1982 												 "}\n");
1983 
1984 	std::string fragmentShaderTemplate			("${GLSL_VERSION_DECL}\n"
1985 													 "\n"
1986 													 "layout (location = 0) out mediump vec4 o_color;\n"
1987 													 "\n"
1988 													 "void main (void)\n"
1989 													 "{\n"
1990 													 "	o_color = vec4(1.0);\n"
1991 												 "}\n");
1992 
1993 	m_program = SharedPtr<const ShaderProgram>(new ShaderProgram(m_context.getRenderContext(), glu::ProgramSources()
1994 			<< glu::VertexSource					(specializeShader(m_context, vertexShaderTemplate.c_str()))
1995 			<< glu::TessellationControlSource		(specializeShader(m_context, tessellationControlTemplate.c_str()))
1996 			<< glu::TessellationEvaluationSource	(specializeShader(m_context, tessellationEvaluationTemplate.c_str()))
1997 			<< glu::FragmentSource					(specializeShader(m_context, fragmentShaderTemplate.c_str()))
1998 			<< glu::TransformFeedbackVarying		("out_te_tessCoord")
1999 			<< glu::TransformFeedbackMode			(GL_INTERLEAVED_ATTRIBS)));
2000 
2001 	m_testCtx.getLog() << *m_program;
2002 	if (!m_program->isOk())
2003 		TCU_FAIL("Program compilation failed");
2004 }
2005 
deinit(void)2006 void TessCoordCase::deinit (void)
2007 {
2008 	m_program.clear();
2009 }
2010 
genTessLevelCases(void) const2011 vector<TessCoordCase::TessLevels> TessCoordCase::genTessLevelCases (void) const
2012 {
2013 	static const TessLevels rawTessLevelCases[] =
2014 	{
2015 		{ { 1.0f,	1.0f	},	{ 1.0f,		1.0f,	1.0f,	1.0f	} },
2016 		{ { 63.0f,	24.0f	},	{ 15.0f,	42.0f,	10.0f,	12.0f	} },
2017 		{ { 3.0f,	2.0f	},	{ 6.0f,		8.0f,	7.0f,	9.0f	} },
2018 		{ { 4.0f,	6.0f	},	{ 2.0f,		3.0f,	1.0f,	4.0f	} },
2019 		{ { 2.0f,	2.0f	},	{ 6.0f,		8.0f,	7.0f,	9.0f	} },
2020 		{ { 5.0f,	6.0f	},	{ 1.0f,		1.0f,	1.0f,	1.0f	} },
2021 		{ { 1.0f,	6.0f	},	{ 2.0f,		3.0f,	1.0f,	4.0f	} },
2022 		{ { 5.0f,	1.0f	},	{ 2.0f,		3.0f,	1.0f,	4.0f	} },
2023 		{ { 5.2f,	1.6f	},	{ 2.9f,		3.4f,	1.5f,	4.1f	} }
2024 	};
2025 
2026 	if (m_spacing == SPACINGMODE_EQUAL)
2027 		return vector<TessLevels>(DE_ARRAY_BEGIN(rawTessLevelCases), DE_ARRAY_END(rawTessLevelCases));
2028 	else
2029 	{
2030 		vector<TessLevels> result;
2031 		result.reserve(DE_LENGTH_OF_ARRAY(rawTessLevelCases));
2032 
2033 		for (int tessLevelCaseNdx = 0; tessLevelCaseNdx < DE_LENGTH_OF_ARRAY(rawTessLevelCases); tessLevelCaseNdx++)
2034 		{
2035 			TessLevels curTessLevelCase = rawTessLevelCases[tessLevelCaseNdx];
2036 
2037 			float* const inner = &curTessLevelCase.inner[0];
2038 			float* const outer = &curTessLevelCase.outer[0];
2039 
2040 			for (int j = 0; j < 2; j++) inner[j] = (float)getClampedRoundedTessLevel(m_spacing, inner[j]);
2041 			for (int j = 0; j < 4; j++) outer[j] = (float)getClampedRoundedTessLevel(m_spacing, outer[j]);
2042 
2043 			if (m_primitiveType == TESSPRIMITIVETYPE_TRIANGLES)
2044 			{
2045 				if (outer[0] > 1.0f || outer[1] > 1.0f || outer[2] > 1.0f)
2046 				{
2047 					if (inner[0] == 1.0f)
2048 						inner[0] = (float)getClampedRoundedTessLevel(m_spacing, inner[0] + 0.1f);
2049 				}
2050 			}
2051 			else if (m_primitiveType == TESSPRIMITIVETYPE_QUADS)
2052 			{
2053 				if (outer[0] > 1.0f || outer[1] > 1.0f || outer[2] > 1.0f || outer[3] > 1.0f)
2054 				{
2055 					if (inner[0] == 1.0f) inner[0] = (float)getClampedRoundedTessLevel(m_spacing, inner[0] + 0.1f);
2056 					if (inner[1] == 1.0f) inner[1] = (float)getClampedRoundedTessLevel(m_spacing, inner[1] + 0.1f);
2057 				}
2058 			}
2059 
2060 			result.push_back(curTessLevelCase);
2061 		}
2062 
2063 		DE_ASSERT((int)result.size() == DE_LENGTH_OF_ARRAY(rawTessLevelCases));
2064 		return result;
2065 	}
2066 }
2067 
iterate(void)2068 TessCoordCase::IterateResult TessCoordCase::iterate (void)
2069 {
2070 	typedef TransformFeedbackHandler<Vec3> TFHandler;
2071 
2072 	TestLog&						log							= m_testCtx.getLog();
2073 	const RenderContext&			renderCtx					= m_context.getRenderContext();
2074 	const RandomViewport			viewport					(renderCtx.getRenderTarget(), RENDER_SIZE, RENDER_SIZE, deStringHash(getName()));
2075 	const deUint32					programGL					= m_program->getProgram();
2076 	const glw::Functions&			gl							= renderCtx.getFunctions();
2077 
2078 	const int						tessLevelInner0Loc			= gl.getUniformLocation(programGL, "u_tessLevelInner0");
2079 	const int						tessLevelInner1Loc			= gl.getUniformLocation(programGL, "u_tessLevelInner1");
2080 	const int						tessLevelOuter0Loc			= gl.getUniformLocation(programGL, "u_tessLevelOuter0");
2081 	const int						tessLevelOuter1Loc			= gl.getUniformLocation(programGL, "u_tessLevelOuter1");
2082 	const int						tessLevelOuter2Loc			= gl.getUniformLocation(programGL, "u_tessLevelOuter2");
2083 	const int						tessLevelOuter3Loc			= gl.getUniformLocation(programGL, "u_tessLevelOuter3");
2084 
2085 	const vector<TessLevels>		tessLevelCases				= genTessLevelCases();
2086 	vector<vector<Vec3> >			caseReferences				(tessLevelCases.size());
2087 
2088 	for (int i = 0; i < (int)tessLevelCases.size(); i++)
2089 		caseReferences[i] = generateReferenceTessCoords(m_primitiveType, m_spacing, &tessLevelCases[i].inner[0], &tessLevelCases[i].outer[0]);
2090 
2091 	const int						maxNumVertices				= (int)std::max_element(caseReferences.begin(), caseReferences.end(), SizeLessThan<vector<Vec3> >())->size();
2092 	const TFHandler					tfHandler					(m_context.getRenderContext(), maxNumVertices);
2093 
2094 	bool							success						= true;
2095 
2096 	setViewport(gl, viewport);
2097 	gl.useProgram(programGL);
2098 
2099 	gl.patchParameteri(GL_PATCH_VERTICES, 1);
2100 
2101 	for (int tessLevelCaseNdx = 0; tessLevelCaseNdx < (int)tessLevelCases.size(); tessLevelCaseNdx++)
2102 	{
2103 		const float* const innerLevels = &tessLevelCases[tessLevelCaseNdx].inner[0];
2104 		const float* const outerLevels = &tessLevelCases[tessLevelCaseNdx].outer[0];
2105 
2106 		log << TestLog::Message << "Tessellation levels: " << tessellationLevelsString(innerLevels, outerLevels, m_primitiveType) << TestLog::EndMessage;
2107 
2108 		gl.uniform1f(tessLevelInner0Loc, innerLevels[0]);
2109 		gl.uniform1f(tessLevelInner1Loc, innerLevels[1]);
2110 		gl.uniform1f(tessLevelOuter0Loc, outerLevels[0]);
2111 		gl.uniform1f(tessLevelOuter1Loc, outerLevels[1]);
2112 		gl.uniform1f(tessLevelOuter2Loc, outerLevels[2]);
2113 		gl.uniform1f(tessLevelOuter3Loc, outerLevels[3]);
2114 		GLU_EXPECT_NO_ERROR(gl.getError(), "Setup failed");
2115 
2116 		{
2117 			const vector<Vec3>&			tessCoordsRef	= caseReferences[tessLevelCaseNdx];
2118 			const TFHandler::Result		tfResult		= tfHandler.renderAndGetPrimitives(programGL, GL_POINTS, 0, DE_NULL, 1);
2119 
2120 			if (tfResult.numPrimitives != (int)tessCoordsRef.size())
2121 			{
2122 				log << TestLog::Message << "Failure: GL reported GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN to be "
2123 										<< tfResult.numPrimitives << ", reference value is " << tessCoordsRef.size()
2124 										<< " (logging further info anyway)" << TestLog::EndMessage;
2125 				success = false;
2126 			}
2127 			else
2128 				log << TestLog::Message << "Note: GL reported GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN to be " << tfResult.numPrimitives << TestLog::EndMessage;
2129 
2130 			if (m_primitiveType == TESSPRIMITIVETYPE_TRIANGLES)
2131 				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;
2132 			else if (m_primitiveType == TESSPRIMITIVETYPE_QUADS || m_primitiveType == TESSPRIMITIVETYPE_ISOLINES)
2133 				log << TestLog::Message << "Note: in the following visualization(s), u and v coordinate go left-to-right and bottom-to-top, respectively" << TestLog::EndMessage;
2134 			else
2135 				DE_ASSERT(false);
2136 
2137 			success = compareTessCoords(log, m_primitiveType, tessCoordsRef, tfResult.varying) && success;
2138 		}
2139 
2140 		if (!success)
2141 			break;
2142 		else
2143 			log << TestLog::Message << "All OK" << TestLog::EndMessage;
2144 	}
2145 
2146 	m_testCtx.setTestResult(success ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, success ? "Pass" : "Invalid tessellation coordinates");
2147 	return STOP;
2148 }
2149 
2150 // Check validity of fractional spacing modes. Draws a single isoline, reads tesscoords with transform feedback.
2151 class FractionalSpacingModeCase : public TestCase
2152 {
2153 public:
FractionalSpacingModeCase(Context & context,const char * name,const char * description,SpacingMode spacing)2154 					FractionalSpacingModeCase (Context& context, const char* name, const char* description, SpacingMode spacing)
2155 						: TestCase	(context, name, description)
2156 						, m_spacing	(spacing)
2157 					{
2158 						DE_ASSERT(m_spacing == SPACINGMODE_FRACTIONAL_EVEN || m_spacing == SPACINGMODE_FRACTIONAL_ODD);
2159 					}
2160 
2161 	void			init		(void);
2162 	void			deinit		(void);
2163 	IterateResult	iterate		(void);
2164 
2165 private:
2166 	static const int				RENDER_SIZE = 16;
2167 
2168 	static vector<float>			genTessLevelCases (void);
2169 
2170 	const SpacingMode				m_spacing;
2171 
2172 	SharedPtr<const ShaderProgram>	m_program;
2173 };
2174 
init(void)2175 void FractionalSpacingModeCase::init (void)
2176 {
2177 	checkTessellationSupport(m_context);
2178 	checkRenderTargetSize(m_context.getRenderTarget(), RENDER_SIZE);
2179 
2180 	std::string vertexShaderTemplate			("${GLSL_VERSION_DECL}\n"
2181 													 "${GLSL_PER_VERTEX_OUT}\n"
2182 													 "\n"
2183 													 "void main (void)\n"
2184 													 "{\n"
2185 												 "}\n");
2186 	std::string tessellationControlTemplate		("${GLSL_VERSION_DECL}\n"
2187 												 "${TESSELLATION_SHADER_REQUIRE}\n"
2188 													 "${GLSL_PER_VERTEX_IN_ARR}\n"
2189 													 "${GLSL_PER_VERTEX_OUT_ARR}\n"
2190 													 "\n"
2191 													 "layout (vertices = 1) out;\n"
2192 													 "\n"
2193 													 "uniform mediump float u_tessLevelOuter1;\n"
2194 													 "\n"
2195 													 "void main (void)\n"
2196 													 "{\n"
2197 													 "	gl_TessLevelOuter[0] = 1.0;\n"
2198 													 "	gl_TessLevelOuter[1] = u_tessLevelOuter1;\n"
2199 												 "}\n");
2200 	std::string tessellationEvaluationTemplate	("${GLSL_VERSION_DECL}\n"
2201 												 "${TESSELLATION_SHADER_REQUIRE}\n"
2202 												 "${GLSL_PER_VERTEX_IN_ARR}\n"
2203 												 "${GLSL_PER_VERTEX_OUT}\n"
2204 													 "\n"
2205 													 + getTessellationEvaluationInLayoutString(TESSPRIMITIVETYPE_ISOLINES, m_spacing, true) +
2206 													 "\n"
2207 													 "out highp float out_te_tessCoord;\n"
2208 													 "\n"
2209 													 "void main (void)\n"
2210 													 "{\n"
2211 													 "	out_te_tessCoord = gl_TessCoord.x;\n"
2212 													 "	gl_Position = vec4(gl_TessCoord.xy*1.6 - 0.8, 0.0, 1.0);\n"
2213 												 "}\n");
2214 	std::string fragmentShaderTemplate			("${GLSL_VERSION_DECL}\n"
2215 													 "\n"
2216 													 "layout (location = 0) out mediump vec4 o_color;\n"
2217 													 "\n"
2218 													 "void main (void)\n"
2219 													 "{\n"
2220 													 "	o_color = vec4(1.0);\n"
2221 												 "}\n");
2222 
2223 	m_program = SharedPtr<const ShaderProgram>(new ShaderProgram(m_context.getRenderContext(), glu::ProgramSources()
2224 			<< glu::VertexSource					(specializeShader(m_context, vertexShaderTemplate.c_str()))
2225 			<< glu::TessellationControlSource		(specializeShader(m_context, tessellationControlTemplate.c_str()))
2226 			<< glu::TessellationEvaluationSource	(specializeShader(m_context, tessellationEvaluationTemplate.c_str()))
2227 			<< glu::FragmentSource					(specializeShader(m_context, fragmentShaderTemplate.c_str()))
2228 			<< glu::TransformFeedbackVarying		("out_te_tessCoord")
2229 			<< glu::TransformFeedbackMode			(GL_INTERLEAVED_ATTRIBS)));
2230 
2231 	m_testCtx.getLog() << *m_program;
2232 	if (!m_program->isOk())
2233 		TCU_FAIL("Program compilation failed");
2234 }
2235 
deinit(void)2236 void FractionalSpacingModeCase::deinit (void)
2237 {
2238 	m_program.clear();
2239 }
2240 
genTessLevelCases(void)2241 vector<float> FractionalSpacingModeCase::genTessLevelCases (void)
2242 {
2243 	vector<float> result;
2244 
2245 	// Ranges [7.0 .. 8.0), [8.0 .. 9.0) and [9.0 .. 10.0)
2246 	{
2247 		static const float	rangeStarts[]		= { 7.0f, 8.0f, 9.0f };
2248 		const int			numSamplesPerRange	= 10;
2249 
2250 		for (int rangeNdx = 0; rangeNdx < DE_LENGTH_OF_ARRAY(rangeStarts); rangeNdx++)
2251 			for (int i = 0; i < numSamplesPerRange; i++)
2252 				result.push_back(rangeStarts[rangeNdx] + (float)i/(float)numSamplesPerRange);
2253 	}
2254 
2255 	// 0.3, 1.3, 2.3,  ... , 62.3
2256 	for (int i = 0; i <= 62; i++)
2257 		result.push_back((float)i + 0.3f);
2258 
2259 	return result;
2260 }
2261 
iterate(void)2262 FractionalSpacingModeCase::IterateResult FractionalSpacingModeCase::iterate (void)
2263 {
2264 	typedef TransformFeedbackHandler<float> TFHandler;
2265 
2266 	TestLog&						log							= m_testCtx.getLog();
2267 	const RenderContext&			renderCtx					= m_context.getRenderContext();
2268 	const RandomViewport			viewport					(renderCtx.getRenderTarget(), RENDER_SIZE, RENDER_SIZE, deStringHash(getName()));
2269 	const deUint32					programGL					= m_program->getProgram();
2270 	const glw::Functions&			gl							= renderCtx.getFunctions();
2271 
2272 	const int						tessLevelOuter1Loc			= gl.getUniformLocation(programGL, "u_tessLevelOuter1");
2273 
2274 	// Second outer tessellation levels.
2275 	const vector<float>				tessLevelCases				= genTessLevelCases();
2276 	const int						maxNumVertices				= 1 + getClampedRoundedTessLevel(m_spacing, *std::max_element(tessLevelCases.begin(), tessLevelCases.end()));
2277 	vector<float>					additionalSegmentLengths;
2278 	vector<int>						additionalSegmentLocations;
2279 
2280 	const TFHandler					tfHandler					(m_context.getRenderContext(), maxNumVertices);
2281 
2282 	bool							success						= true;
2283 
2284 	setViewport(gl, viewport);
2285 	gl.useProgram(programGL);
2286 
2287 	gl.patchParameteri(GL_PATCH_VERTICES, 1);
2288 
2289 	for (int tessLevelCaseNdx = 0; tessLevelCaseNdx < (int)tessLevelCases.size(); tessLevelCaseNdx++)
2290 	{
2291 		const float outerLevel1 = tessLevelCases[tessLevelCaseNdx];
2292 
2293 		gl.uniform1f(tessLevelOuter1Loc, outerLevel1);
2294 		GLU_EXPECT_NO_ERROR(gl.getError(), "Setup failed");
2295 
2296 		{
2297 			const TFHandler::Result		tfResult = tfHandler.renderAndGetPrimitives(programGL, GL_POINTS, 0, DE_NULL, 1);
2298 			float						additionalSegmentLength;
2299 			int							additionalSegmentLocation;
2300 
2301 			success = verifyFractionalSpacingSingle(log, m_spacing, outerLevel1, tfResult.varying,
2302 													additionalSegmentLength, additionalSegmentLocation);
2303 
2304 			if (!success)
2305 				break;
2306 
2307 			additionalSegmentLengths.push_back(additionalSegmentLength);
2308 			additionalSegmentLocations.push_back(additionalSegmentLocation);
2309 		}
2310 	}
2311 
2312 	if (success)
2313 		success = verifyFractionalSpacingMultiple(log, m_spacing, tessLevelCases, additionalSegmentLengths, additionalSegmentLocations);
2314 
2315 	m_testCtx.setTestResult(success ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, success ? "Pass" : "Invalid tessellation coordinates");
2316 	return STOP;
2317 }
2318 
2319 // 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.
2320 class BasicVariousTessLevelsPosAttrCase : public TestCase
2321 {
2322 public:
BasicVariousTessLevelsPosAttrCase(Context & context,const char * name,const char * description,TessPrimitiveType primitiveType,SpacingMode spacing,const char * referenceImagePathPrefix)2323 					BasicVariousTessLevelsPosAttrCase (Context&				context,
2324 													   const char*			name,
2325 													   const char*			description,
2326 													   TessPrimitiveType	primitiveType,
2327 													   SpacingMode			spacing,
2328 													   const char*			referenceImagePathPrefix)
2329 						: TestCase						(context, name, description)
2330 						, m_primitiveType				(primitiveType)
2331 						, m_spacing						(spacing)
2332 						, m_referenceImagePathPrefix	(referenceImagePathPrefix)
2333 					{
2334 					}
2335 
2336 	void			init			(void);
2337 	void			deinit			(void);
2338 	IterateResult	iterate			(void);
2339 
2340 protected:
2341 	virtual const glu::ProgramSources	makeSources (TessPrimitiveType, SpacingMode, const char* vtxOutPosAttrName) const = DE_NULL;
2342 
2343 private:
2344 	static const int					RENDER_SIZE = 256;
2345 
2346 	const TessPrimitiveType				m_primitiveType;
2347 	const SpacingMode					m_spacing;
2348 	const string						m_referenceImagePathPrefix;
2349 
2350 	SharedPtr<const ShaderProgram>		m_program;
2351 };
2352 
init(void)2353 void BasicVariousTessLevelsPosAttrCase::init (void)
2354 {
2355 	checkTessellationSupport(m_context);
2356 	checkRenderTargetSize(m_context.getRenderTarget(), RENDER_SIZE);
2357 
2358 	{
2359 		glu::ProgramSources sources = makeSources(m_primitiveType, m_spacing, "in_tc_position");
2360 		DE_ASSERT(sources.sources[glu::SHADERTYPE_TESSELLATION_CONTROL].empty());
2361 
2362 		std::string tessellationControlTemplate		("${GLSL_VERSION_DECL}\n"
2363 													 "${TESSELLATION_SHADER_REQUIRE}\n"
2364 													 "${GLSL_PER_VERTEX_IN_ARR}\n"
2365 													 "${GLSL_PER_VERTEX_OUT_ARR}\n"
2366 													"\n"
2367 													"layout (vertices = " + string(m_primitiveType == TESSPRIMITIVETYPE_TRIANGLES ? "3" : "4") + ") out;\n"
2368 													"\n"
2369 													"in highp vec2 in_tc_position[];\n"
2370 													"\n"
2371 													"out highp vec2 in_te_position[];\n"
2372 													"\n"
2373 													"uniform mediump float u_tessLevelInner0;\n"
2374 													"uniform mediump float u_tessLevelInner1;\n"
2375 													"uniform mediump float u_tessLevelOuter0;\n"
2376 													"uniform mediump float u_tessLevelOuter1;\n"
2377 													"uniform mediump float u_tessLevelOuter2;\n"
2378 													"uniform mediump float u_tessLevelOuter3;\n"
2379 													"\n"
2380 													"void main (void)\n"
2381 													"{\n"
2382 													"	in_te_position[gl_InvocationID] = in_tc_position[gl_InvocationID];\n"
2383 													"\n"
2384 													"	gl_TessLevelInner[0] = u_tessLevelInner0;\n"
2385 													"	gl_TessLevelInner[1] = u_tessLevelInner1;\n"
2386 													"\n"
2387 													"	gl_TessLevelOuter[0] = u_tessLevelOuter0;\n"
2388 													"	gl_TessLevelOuter[1] = u_tessLevelOuter1;\n"
2389 													"	gl_TessLevelOuter[2] = u_tessLevelOuter2;\n"
2390 													"	gl_TessLevelOuter[3] = u_tessLevelOuter3;\n"
2391 													"}\n");
2392 
2393 		sources << glu::TessellationControlSource(specializeShader(m_context, tessellationControlTemplate.c_str()));
2394 
2395 		m_program = SharedPtr<const ShaderProgram>(new glu::ShaderProgram(m_context.getRenderContext(), sources));
2396 	}
2397 
2398 	m_testCtx.getLog() << *m_program;
2399 	if (!m_program->isOk())
2400 		TCU_FAIL("Program compilation failed");
2401 }
2402 
deinit(void)2403 void BasicVariousTessLevelsPosAttrCase::deinit (void)
2404 {
2405 	m_program.clear();
2406 }
2407 
iterate(void)2408 BasicVariousTessLevelsPosAttrCase::IterateResult BasicVariousTessLevelsPosAttrCase::iterate (void)
2409 {
2410 	static const struct
2411 	{
2412 		float inner[2];
2413 		float outer[4];
2414 	} tessLevelCases[] =
2415 	{
2416 		{ { 9.0f,	9.0f	},	{ 9.0f,		9.0f,	9.0f,	9.0f	} },
2417 		{ { 8.0f,	11.0f	},	{ 13.0f,	15.0f,	18.0f,	21.0f	} },
2418 		{ { 17.0f,	14.0f	},	{ 3.0f,		6.0f,	9.0f,	12.0f	} }
2419 	};
2420 
2421 	TestLog&				log					= m_testCtx.getLog();
2422 	const RenderContext&	renderCtx			= m_context.getRenderContext();
2423 	const RandomViewport	viewport			(renderCtx.getRenderTarget(), RENDER_SIZE, RENDER_SIZE, deStringHash(getName()));
2424 	const deUint32			programGL			= m_program->getProgram();
2425 	const glw::Functions&	gl					= renderCtx.getFunctions();
2426 	const int				patchSize			= m_primitiveType == TESSPRIMITIVETYPE_TRIANGLES	? 3
2427 												: m_primitiveType == TESSPRIMITIVETYPE_QUADS		? 4
2428 												: m_primitiveType == TESSPRIMITIVETYPE_ISOLINES		? 4
2429 												: -1;
2430 
2431 	setViewport(gl, viewport);
2432 	gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
2433 	gl.useProgram(programGL);
2434 
2435 	gl.patchParameteri(GL_PATCH_VERTICES, patchSize);
2436 
2437 	for (int tessLevelCaseNdx = 0; tessLevelCaseNdx < DE_LENGTH_OF_ARRAY(tessLevelCases); tessLevelCaseNdx++)
2438 	{
2439 		float innerLevels[2];
2440 		float outerLevels[4];
2441 
2442 		for (int i = 0; i < DE_LENGTH_OF_ARRAY(innerLevels); i++)
2443 			innerLevels[i] = (float)getClampedRoundedTessLevel(m_spacing, tessLevelCases[tessLevelCaseNdx].inner[i]);
2444 
2445 		for (int i = 0; i < DE_LENGTH_OF_ARRAY(outerLevels); i++)
2446 			outerLevels[i] = (float)getClampedRoundedTessLevel(m_spacing, tessLevelCases[tessLevelCaseNdx].outer[i]);
2447 
2448 		log << TestLog::Message << "Tessellation levels: " << tessellationLevelsString(&innerLevels[0], &outerLevels[0], m_primitiveType) << TestLog::EndMessage;
2449 
2450 		gl.uniform1f(gl.getUniformLocation(programGL, "u_tessLevelInner0"), innerLevels[0]);
2451 		gl.uniform1f(gl.getUniformLocation(programGL, "u_tessLevelInner1"), innerLevels[1]);
2452 		gl.uniform1f(gl.getUniformLocation(programGL, "u_tessLevelOuter0"), outerLevels[0]);
2453 		gl.uniform1f(gl.getUniformLocation(programGL, "u_tessLevelOuter1"), outerLevels[1]);
2454 		gl.uniform1f(gl.getUniformLocation(programGL, "u_tessLevelOuter2"), outerLevels[2]);
2455 		gl.uniform1f(gl.getUniformLocation(programGL, "u_tessLevelOuter3"), outerLevels[3]);
2456 
2457 		gl.clear(GL_COLOR_BUFFER_BIT);
2458 
2459 		{
2460 			vector<Vec2> positions;
2461 			positions.reserve(4);
2462 
2463 			if (m_primitiveType == TESSPRIMITIVETYPE_TRIANGLES)
2464 			{
2465 				positions.push_back(Vec2( 0.8f,    0.6f));
2466 				positions.push_back(Vec2( 0.0f, -0.786f));
2467 				positions.push_back(Vec2(-0.8f,    0.6f));
2468 			}
2469 			else if (m_primitiveType == TESSPRIMITIVETYPE_QUADS || m_primitiveType == TESSPRIMITIVETYPE_ISOLINES)
2470 			{
2471 				positions.push_back(Vec2(-0.8f, -0.8f));
2472 				positions.push_back(Vec2( 0.8f, -0.8f));
2473 				positions.push_back(Vec2(-0.8f,  0.8f));
2474 				positions.push_back(Vec2( 0.8f,  0.8f));
2475 			}
2476 			else
2477 				DE_ASSERT(false);
2478 
2479 			DE_ASSERT((int)positions.size() == patchSize);
2480 
2481 			const glu::VertexArrayBinding attrBindings[] =
2482 			{
2483 				glu::va::Float("in_v_position", 2, (int)positions.size(), 0, &positions[0].x())
2484 			};
2485 
2486 			glu::draw(m_context.getRenderContext(), programGL, DE_LENGTH_OF_ARRAY(attrBindings), &attrBindings[0],
2487 				glu::pr::Patches(patchSize));
2488 			GLU_EXPECT_NO_ERROR(gl.getError(), "Draw failed");
2489 		}
2490 
2491 		{
2492 			const tcu::Surface			rendered	= getPixels(renderCtx, viewport);
2493 			const tcu::TextureLevel		reference	= getPNG(m_testCtx.getArchive(), m_referenceImagePathPrefix + "_" + de::toString(tessLevelCaseNdx) + ".png");
2494 			const bool					success		= tcu::fuzzyCompare(log, "ImageComparison", "Image Comparison", reference.getAccess(), rendered.getAccess(), 0.002f, tcu::COMPARE_LOG_RESULT);
2495 
2496 			if (!success)
2497 			{
2498 				m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed");
2499 				return STOP;
2500 			}
2501 		}
2502 	}
2503 
2504 	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
2505 	return STOP;
2506 }
2507 
2508 // Test that there are no obvious gaps in the triangulation of a tessellated triangle or quad.
2509 class BasicTriangleFillCoverCase : public BasicVariousTessLevelsPosAttrCase
2510 {
2511 public:
BasicTriangleFillCoverCase(Context & context,const char * name,const char * description,TessPrimitiveType primitiveType,SpacingMode spacing,const char * referenceImagePathPrefix)2512 	BasicTriangleFillCoverCase (Context& context, const char* name, const char* description, TessPrimitiveType primitiveType, SpacingMode spacing, const char* referenceImagePathPrefix)
2513 		: BasicVariousTessLevelsPosAttrCase (context, name, description, primitiveType, spacing, referenceImagePathPrefix)
2514 	{
2515 		DE_ASSERT(primitiveType == TESSPRIMITIVETYPE_TRIANGLES || primitiveType == TESSPRIMITIVETYPE_QUADS);
2516 	}
2517 
2518 protected:
init(void)2519 	void init (void)
2520 	{
2521 		checkGPUShader5Support(m_context);
2522 		BasicVariousTessLevelsPosAttrCase::init();
2523 	}
2524 
makeSources(TessPrimitiveType primitiveType,SpacingMode spacing,const char * vtxOutPosAttrName) const2525 	const glu::ProgramSources makeSources (TessPrimitiveType primitiveType, SpacingMode spacing, const char* vtxOutPosAttrName) const
2526 	{
2527 		bool isGL45 = glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 5));
2528 		std::string vertexShaderTemplate			("${GLSL_VERSION_DECL}\n"
2529 													 "${GLSL_PER_VERTEX_OUT}\n"
2530 													 "\n"
2531 													 "in highp vec2 in_v_position;\n"
2532 													 "\n"
2533 													 "out highp vec2 " + string(vtxOutPosAttrName) + ";\n"
2534 													 "\n"
2535 													 "void main (void)\n"
2536 													 "{\n"
2537 													 "	" + vtxOutPosAttrName + " = in_v_position;\n"
2538 													 "}\n");
2539 		std::string tessellationEvaluationTemplate	("${GLSL_VERSION_DECL}\n"
2540 													 "${TESSELLATION_SHADER_REQUIRE}\n"
2541 													 "${GPU_SHADER5_REQUIRE}\n"
2542 													 "${GLSL_PER_VERTEX_IN_ARR}\n"
2543 													 "${GLSL_PRECISE_PER_VERTEX_OUT}\n"
2544 													 "\n"
2545 													 + getTessellationEvaluationInLayoutString(primitiveType, spacing) +
2546 													 "\n"
2547 													 "in highp vec2 in_te_position[];\n"
2548 													 "\n"
2549 													 + (isGL45 ? "" : "precise gl_Position;\n") +
2550 													 "void main (void)\n"
2551 													 "{\n"
2552 													 + (primitiveType == TESSPRIMITIVETYPE_TRIANGLES ?
2553 														"\n"
2554 														"	highp float d = 3.0 * min(gl_TessCoord.x, min(gl_TessCoord.y, gl_TessCoord.z));\n"
2555 														"	highp vec2 corner0 = in_te_position[0];\n"
2556 														"	highp vec2 corner1 = in_te_position[1];\n"
2557 														"	highp vec2 corner2 = in_te_position[2];\n"
2558 														"	highp vec2 pos =  corner0*gl_TessCoord.x + corner1*gl_TessCoord.y + corner2*gl_TessCoord.z;\n"
2559 														"	highp vec2 fromCenter = pos - (corner0 + corner1 + corner2) / 3.0;\n"
2560 														"	highp float f = (1.0 - length(fromCenter)) * (1.5 - d);\n"
2561 														"	pos += 0.75 * f * fromCenter / (length(fromCenter) + 0.3);\n"
2562 														"	gl_Position = vec4(pos, 0.0, 1.0);\n"
2563 													  : primitiveType == TESSPRIMITIVETYPE_QUADS ?
2564 														"	highp vec2 corner0 = in_te_position[0];\n"
2565 														"	highp vec2 corner1 = in_te_position[1];\n"
2566 														"	highp vec2 corner2 = in_te_position[2];\n"
2567 														"	highp vec2 corner3 = in_te_position[3];\n"
2568 														"	highp vec2 pos = (1.0-gl_TessCoord.x)*(1.0-gl_TessCoord.y)*corner0\n"
2569 														"	               + (    gl_TessCoord.x)*(1.0-gl_TessCoord.y)*corner1\n"
2570 														"	               + (1.0-gl_TessCoord.x)*(    gl_TessCoord.y)*corner2\n"
2571 														"	               + (    gl_TessCoord.x)*(    gl_TessCoord.y)*corner3;\n"
2572 														"	highp float d = 2.0 * min(abs(gl_TessCoord.x-0.5), abs(gl_TessCoord.y-0.5));\n"
2573 														"	highp vec2 fromCenter = pos - (corner0 + corner1 + corner2 + corner3) / 4.0;\n"
2574 														"	highp float f = (1.0 - length(fromCenter)) * sqrt(1.7 - d);\n"
2575 														"	pos += 0.75 * f * fromCenter / (length(fromCenter) + 0.3);\n"
2576 														"	gl_Position = vec4(pos, 0.0, 1.0);\n"
2577 													  : DE_NULL) +
2578 													 "}\n");
2579 		std::string fragmentShaderTemplate			("${GLSL_VERSION_DECL}\n"
2580 													 "\n"
2581 													 "layout (location = 0) out mediump vec4 o_color;\n"
2582 													 "\n"
2583 													 "void main (void)\n"
2584 													 "{\n"
2585 													 "	o_color = vec4(1.0);\n"
2586 													 "}\n");
2587 
2588 		return glu::ProgramSources()
2589 			<< glu::VertexSource					(specializeShader(m_context, vertexShaderTemplate.c_str()))
2590 			<< glu::TessellationEvaluationSource	(specializeShader(m_context, tessellationEvaluationTemplate.c_str()))
2591 			<< glu::FragmentSource					(specializeShader(m_context, fragmentShaderTemplate.c_str()));
2592 	}
2593 };
2594 
2595 // Check that there are no obvious overlaps in the triangulation of a tessellated triangle or quad.
2596 class BasicTriangleFillNonOverlapCase : public BasicVariousTessLevelsPosAttrCase
2597 {
2598 public:
BasicTriangleFillNonOverlapCase(Context & context,const char * name,const char * description,TessPrimitiveType primitiveType,SpacingMode spacing,const char * referenceImagePathPrefix)2599 	BasicTriangleFillNonOverlapCase (Context& context, const char* name, const char* description, TessPrimitiveType primitiveType, SpacingMode spacing, const char* referenceImagePathPrefix)
2600 		: BasicVariousTessLevelsPosAttrCase (context, name, description, primitiveType, spacing, referenceImagePathPrefix)
2601 	{
2602 		DE_ASSERT(primitiveType == TESSPRIMITIVETYPE_TRIANGLES || primitiveType == TESSPRIMITIVETYPE_QUADS);
2603 	}
2604 
2605 protected:
makeSources(TessPrimitiveType primitiveType,SpacingMode spacing,const char * vtxOutPosAttrName) const2606 	const glu::ProgramSources makeSources (TessPrimitiveType primitiveType, SpacingMode spacing, const char* vtxOutPosAttrName) const
2607 	{
2608 		std::string vertexShaderTemplate			("${GLSL_VERSION_DECL}\n"
2609 													 "${GLSL_PER_VERTEX_OUT}\n"
2610 													 "\n"
2611 													 "in highp vec2 in_v_position;\n"
2612 													 "\n"
2613 													 "out highp vec2 " + string(vtxOutPosAttrName) + ";\n"
2614 													 "\n"
2615 													 "void main (void)\n"
2616 													 "{\n"
2617 													 "	" + vtxOutPosAttrName + " = in_v_position;\n"
2618 													 "}\n");
2619 		std::string tessellationEvaluationTemplate	("${GLSL_VERSION_DECL}\n"
2620 													 "${TESSELLATION_SHADER_REQUIRE}\n"
2621 													 "${GLSL_PER_VERTEX_IN_ARR}\n"
2622 													 "${GLSL_PER_VERTEX_OUT}\n"
2623 													 "\n"
2624 													 + getTessellationEvaluationInLayoutString(primitiveType, spacing) +
2625 													 "\n"
2626 													 "in highp vec2 in_te_position[];\n"
2627 													 "\n"
2628 													 "out mediump vec4 in_f_color;\n"
2629 													 "\n"
2630 													 "uniform mediump float u_tessLevelInner0;\n"
2631 													 "uniform mediump float u_tessLevelInner1;\n"
2632 													 "\n"
2633 													 "void main (void)\n"
2634 													 "{\n"
2635 													 + (primitiveType == TESSPRIMITIVETYPE_TRIANGLES ?
2636 														"\n"
2637 														"	highp vec2 corner0 = in_te_position[0];\n"
2638 														"	highp vec2 corner1 = in_te_position[1];\n"
2639 														"	highp vec2 corner2 = in_te_position[2];\n"
2640 														"	highp vec2 pos =  corner0*gl_TessCoord.x + corner1*gl_TessCoord.y + corner2*gl_TessCoord.z;\n"
2641 														"	gl_Position = vec4(pos, 0.0, 1.0);\n"
2642 														"	highp int numConcentricTriangles = int(round(u_tessLevelInner0)) / 2 + 1;\n"
2643 														"	highp float d = 3.0 * min(gl_TessCoord.x, min(gl_TessCoord.y, gl_TessCoord.z));\n"
2644 														"	highp int phase = int(d*float(numConcentricTriangles)) % 3;\n"
2645 														"	in_f_color = phase == 0 ? vec4(1.0, 0.0, 0.0, 1.0)\n"
2646 														"	           : phase == 1 ? vec4(0.0, 1.0, 0.0, 1.0)\n"
2647 														"	           :              vec4(0.0, 0.0, 1.0, 1.0);\n"
2648 													  : primitiveType == TESSPRIMITIVETYPE_QUADS ?
2649 														"	highp vec2 corner0 = in_te_position[0];\n"
2650 														"	highp vec2 corner1 = in_te_position[1];\n"
2651 														"	highp vec2 corner2 = in_te_position[2];\n"
2652 														"	highp vec2 corner3 = in_te_position[3];\n"
2653 														"	highp vec2 pos = (1.0-gl_TessCoord.x)*(1.0-gl_TessCoord.y)*corner0\n"
2654 														"	               + (    gl_TessCoord.x)*(1.0-gl_TessCoord.y)*corner1\n"
2655 														"	               + (1.0-gl_TessCoord.x)*(    gl_TessCoord.y)*corner2\n"
2656 														"	               + (    gl_TessCoord.x)*(    gl_TessCoord.y)*corner3;\n"
2657 														"	gl_Position = vec4(pos, 0.0, 1.0);\n"
2658 														"	highp int phaseX = int(round((0.5 - abs(gl_TessCoord.x-0.5)) * u_tessLevelInner0));\n"
2659 														"	highp int phaseY = int(round((0.5 - abs(gl_TessCoord.y-0.5)) * u_tessLevelInner1));\n"
2660 														"	highp int phase = min(phaseX, phaseY) % 3;\n"
2661 														"	in_f_color = phase == 0 ? vec4(1.0, 0.0, 0.0, 1.0)\n"
2662 														"	           : phase == 1 ? vec4(0.0, 1.0, 0.0, 1.0)\n"
2663 														"	           :              vec4(0.0, 0.0, 1.0, 1.0);\n"
2664 													  : DE_NULL) +
2665 													 "}\n");
2666 		std::string fragmentShaderTemplate			("${GLSL_VERSION_DECL}\n"
2667 													 "\n"
2668 													 "layout (location = 0) out mediump vec4 o_color;\n"
2669 													 "\n"
2670 													 "in mediump vec4 in_f_color;\n"
2671 													 "\n"
2672 													 "void main (void)\n"
2673 													 "{\n"
2674 													 "	o_color = in_f_color;\n"
2675 													 "}\n");
2676 
2677 		return glu::ProgramSources()
2678 			<< glu::VertexSource					(specializeShader(m_context, vertexShaderTemplate.c_str()))
2679 			<< glu::TessellationEvaluationSource	(specializeShader(m_context, tessellationEvaluationTemplate.c_str()))
2680 			<< glu::FragmentSource					(specializeShader(m_context, fragmentShaderTemplate.c_str()));
2681 	}
2682 };
2683 
2684 // Basic isolines rendering case.
2685 class IsolinesRenderCase : public BasicVariousTessLevelsPosAttrCase
2686 {
2687 public:
IsolinesRenderCase(Context & context,const char * name,const char * description,SpacingMode spacing,const char * referenceImagePathPrefix)2688 	IsolinesRenderCase (Context& context, const char* name, const char* description, SpacingMode spacing, const char* referenceImagePathPrefix)
2689 		: BasicVariousTessLevelsPosAttrCase (context, name, description, TESSPRIMITIVETYPE_ISOLINES, spacing, referenceImagePathPrefix)
2690 	{
2691 	}
2692 
2693 protected:
makeSources(TessPrimitiveType primitiveType,SpacingMode spacing,const char * vtxOutPosAttrName) const2694 	const glu::ProgramSources makeSources (TessPrimitiveType primitiveType, SpacingMode spacing, const char* vtxOutPosAttrName) const
2695 	{
2696 		DE_ASSERT(primitiveType == TESSPRIMITIVETYPE_ISOLINES);
2697 		DE_UNREF(primitiveType);
2698 
2699 		std::string vertexShaderTemplate			("${GLSL_VERSION_DECL}\n"
2700 													 "${GLSL_PER_VERTEX_OUT}\n"
2701 													 "\n"
2702 													 "in highp vec2 in_v_position;\n"
2703 													 "\n"
2704 													 "out highp vec2 " + string(vtxOutPosAttrName) + ";\n"
2705 													 "\n"
2706 													 "void main (void)\n"
2707 													 "{\n"
2708 													 "	" + vtxOutPosAttrName + " = in_v_position;\n"
2709 													 "}\n");
2710 		std::string tessellationEvaluationTemplate	("${GLSL_VERSION_DECL}\n"
2711 													 "${TESSELLATION_SHADER_REQUIRE}\n"
2712 													 "${GLSL_PER_VERTEX_IN_ARR}\n"
2713 													 "${GLSL_PER_VERTEX_OUT}\n"
2714 													 "\n"
2715 													 + getTessellationEvaluationInLayoutString(TESSPRIMITIVETYPE_ISOLINES, spacing) +
2716 													 "\n"
2717 													 "in highp vec2 in_te_position[];\n"
2718 													 "\n"
2719 													 "out mediump vec4 in_f_color;\n"
2720 													 "\n"
2721 													 "uniform mediump float u_tessLevelOuter0;\n"
2722 													 "uniform mediump float u_tessLevelOuter1;\n"
2723 													 "\n"
2724 													 "void main (void)\n"
2725 													 "{\n"
2726 													 "	highp vec2 corner0 = in_te_position[0];\n"
2727 													 "	highp vec2 corner1 = in_te_position[1];\n"
2728 													 "	highp vec2 corner2 = in_te_position[2];\n"
2729 													 "	highp vec2 corner3 = in_te_position[3];\n"
2730 													 "	highp vec2 pos = (1.0-gl_TessCoord.x)*(1.0-gl_TessCoord.y)*corner0\n"
2731 													 "	               + (    gl_TessCoord.x)*(1.0-gl_TessCoord.y)*corner1\n"
2732 													 "	               + (1.0-gl_TessCoord.x)*(    gl_TessCoord.y)*corner2\n"
2733 													 "	               + (    gl_TessCoord.x)*(    gl_TessCoord.y)*corner3;\n"
2734 													 "	pos.y += 0.15*sin(gl_TessCoord.x*10.0);\n"
2735 													 "	gl_Position = vec4(pos, 0.0, 1.0);\n"
2736 													 "	highp int phaseX = int(round(gl_TessCoord.x*u_tessLevelOuter1));\n"
2737 													 "	highp int phaseY = int(round(gl_TessCoord.y*u_tessLevelOuter0));\n"
2738 													 "	highp int phase = (phaseX + phaseY) % 3;\n"
2739 													 "	in_f_color = phase == 0 ? vec4(1.0, 0.0, 0.0, 1.0)\n"
2740 													 "	           : phase == 1 ? vec4(0.0, 1.0, 0.0, 1.0)\n"
2741 													 "	           :              vec4(0.0, 0.0, 1.0, 1.0);\n"
2742 													 "}\n");
2743 		std::string fragmentShaderTemplate			("${GLSL_VERSION_DECL}\n"
2744 													 "\n"
2745 													 "layout (location = 0) out mediump vec4 o_color;\n"
2746 													 "\n"
2747 													 "in mediump vec4 in_f_color;\n"
2748 													 "\n"
2749 													 "void main (void)\n"
2750 													 "{\n"
2751 													 "	o_color = in_f_color;\n"
2752 													 "}\n");
2753 
2754 		return glu::ProgramSources()
2755 				<< glu::VertexSource					(specializeShader(m_context, vertexShaderTemplate.c_str()))
2756 				<< glu::TessellationEvaluationSource	(specializeShader(m_context, tessellationEvaluationTemplate.c_str()))
2757 				<< glu::FragmentSource					(specializeShader(m_context, fragmentShaderTemplate.c_str()));
2758 	}
2759 };
2760 
2761 // Test the "cw" and "ccw" TES input layout qualifiers.
2762 class WindingCase : public TestCase
2763 {
2764 public:
WindingCase(Context & context,const char * name,const char * description,TessPrimitiveType primitiveType,Winding winding)2765 					WindingCase (Context& context, const char* name, const char* description, TessPrimitiveType primitiveType, Winding winding)
2766 						: TestCase			(context, name, description)
2767 						, m_primitiveType	(primitiveType)
2768 						, m_winding			(winding)
2769 					{
2770 						DE_ASSERT(primitiveType == TESSPRIMITIVETYPE_TRIANGLES || primitiveType == TESSPRIMITIVETYPE_QUADS);
2771 					}
2772 
2773 	void			init		(void);
2774 	void			deinit		(void);
2775 	IterateResult	iterate		(void);
2776 
2777 private:
2778 	static const int				RENDER_SIZE = 64;
2779 
2780 	const TessPrimitiveType			m_primitiveType;
2781 	const Winding					m_winding;
2782 
2783 	SharedPtr<const ShaderProgram>	m_program;
2784 };
2785 
init(void)2786 void WindingCase::init (void)
2787 {
2788 	checkTessellationSupport(m_context);
2789 	checkRenderTargetSize(m_context.getRenderTarget(), RENDER_SIZE);
2790 
2791 	std::string vertexShaderTemplate			("${GLSL_VERSION_DECL}\n"
2792 												 "${GLSL_PER_VERTEX_OUT}\n"
2793 												 "\n"
2794 												 "void main (void)\n"
2795 												 "{\n"
2796 												 "}\n");
2797 	std::string tessellationControlTemplate		("${GLSL_VERSION_DECL}\n"
2798 												 "${TESSELLATION_SHADER_REQUIRE}\n"
2799 												 "${GLSL_PER_VERTEX_IN_ARR}\n"
2800 												 "${GLSL_PER_VERTEX_OUT_ARR}\n"
2801 												 "\n"
2802 												 "layout (vertices = 1) out;\n"
2803 												 "\n"
2804 												 "void main (void)\n"
2805 												 "{\n"
2806 												 "	gl_TessLevelInner[0] = 5.0;\n"
2807 												 "	gl_TessLevelInner[1] = 5.0;\n"
2808 												 "\n"
2809 												 "	gl_TessLevelOuter[0] = 5.0;\n"
2810 												 "	gl_TessLevelOuter[1] = 5.0;\n"
2811 												 "	gl_TessLevelOuter[2] = 5.0;\n"
2812 												 "	gl_TessLevelOuter[3] = 5.0;\n"
2813 												 "}\n");
2814 	std::string tessellationEvaluationTemplate	("${GLSL_VERSION_DECL}\n"
2815 												 "${TESSELLATION_SHADER_REQUIRE}\n"
2816 												 "${GLSL_PER_VERTEX_IN_ARR}\n"
2817 												 "${GLSL_PER_VERTEX_OUT}\n"
2818 												 "\n"
2819 												 + getTessellationEvaluationInLayoutString(m_primitiveType, m_winding) +
2820 												 "\n"
2821 												 "void main (void)\n"
2822 												 "{\n"
2823 												 "	gl_Position = vec4(gl_TessCoord.xy*2.0 - 1.0, 0.0, 1.0);\n"
2824 												 "}\n");
2825 	std::string fragmentShaderTemplate			("${GLSL_VERSION_DECL}\n"
2826 												 "\n"
2827 												 "layout (location = 0) out mediump vec4 o_color;\n"
2828 												 "\n"
2829 												 "void main (void)\n"
2830 												 "{\n"
2831 												 "	o_color = vec4(1.0);\n"
2832 												 "}\n");
2833 
2834 	m_program = SharedPtr<const ShaderProgram>(new ShaderProgram(m_context.getRenderContext(), glu::ProgramSources()
2835 			<< glu::VertexSource					(specializeShader(m_context, vertexShaderTemplate.c_str()))
2836 			<< glu::TessellationControlSource		(specializeShader(m_context, tessellationControlTemplate.c_str()))
2837 			<< glu::TessellationEvaluationSource	(specializeShader(m_context, tessellationEvaluationTemplate.c_str()))
2838 			<< glu::FragmentSource					(specializeShader(m_context, fragmentShaderTemplate.c_str()))));
2839 
2840 	m_testCtx.getLog() << *m_program;
2841 	if (!m_program->isOk())
2842 		TCU_FAIL("Program compilation failed");
2843 }
2844 
deinit(void)2845 void WindingCase::deinit (void)
2846 {
2847 	m_program.clear();
2848 }
2849 
iterate(void)2850 WindingCase::IterateResult WindingCase::iterate (void)
2851 {
2852 	TestLog&						log							= m_testCtx.getLog();
2853 	const RenderContext&			renderCtx					= m_context.getRenderContext();
2854 	const RandomViewport			viewport					(renderCtx.getRenderTarget(), RENDER_SIZE, RENDER_SIZE, deStringHash(getName()));
2855 	const deUint32					programGL					= m_program->getProgram();
2856 	const glw::Functions&			gl							= renderCtx.getFunctions();
2857 	const glu::VertexArray			vao							(renderCtx);
2858 
2859 	bool							success						= true;
2860 
2861 	setViewport(gl, viewport);
2862 	gl.clearColor(1.0f, 0.0f, 0.0f, 1.0f);
2863 	gl.useProgram(programGL);
2864 
2865 	gl.patchParameteri(GL_PATCH_VERTICES, 1);
2866 
2867 	gl.enable(GL_CULL_FACE);
2868 
2869 	gl.bindVertexArray(*vao);
2870 
2871 	log << TestLog::Message << "Face culling enabled" << TestLog::EndMessage;
2872 
2873 	for (int frontFaceWinding = 0; frontFaceWinding < WINDING_LAST; frontFaceWinding++)
2874 	{
2875 		log << TestLog::Message << "Setting glFrontFace(" << (frontFaceWinding == WINDING_CW ? "GL_CW" : "GL_CCW") << ")" << TestLog::EndMessage;
2876 
2877 		gl.frontFace(frontFaceWinding == WINDING_CW ? GL_CW : GL_CCW);
2878 
2879 		gl.clear(GL_COLOR_BUFFER_BIT);
2880 		gl.drawArrays(GL_PATCHES, 0, 1);
2881 		GLU_EXPECT_NO_ERROR(gl.getError(), "Draw failed");
2882 
2883 		{
2884 			const tcu::Surface rendered = getPixels(renderCtx, viewport);
2885 			log << TestLog::Image("RenderedImage", "Rendered Image", rendered);
2886 
2887 			{
2888 				const int totalNumPixels		= rendered.getWidth()*rendered.getHeight();
2889 				const int badPixelTolerance		= m_primitiveType == TESSPRIMITIVETYPE_TRIANGLES ? 5*de::max(rendered.getWidth(), rendered.getHeight()) : 0;
2890 
2891 				int numWhitePixels	= 0;
2892 				int numRedPixels	= 0;
2893 				for (int y = 0; y < rendered.getHeight();	y++)
2894 				for (int x = 0; x < rendered.getWidth();	x++)
2895 				{
2896 					numWhitePixels	+= rendered.getPixel(x, y) == tcu::RGBA::white()	? 1 : 0;
2897 					numRedPixels	+= rendered.getPixel(x, y) == tcu::RGBA::red()	? 1 : 0;
2898 				}
2899 
2900 				DE_ASSERT(numWhitePixels + numRedPixels <= totalNumPixels);
2901 
2902 				log << TestLog::Message << "Note: got " << numWhitePixels << " white and " << numRedPixels << " red pixels" << TestLog::EndMessage;
2903 
2904 				if (totalNumPixels - numWhitePixels - numRedPixels > badPixelTolerance)
2905 				{
2906 					log << TestLog::Message << "Failure: Got " << totalNumPixels - numWhitePixels - numRedPixels << " other than white or red pixels (maximum tolerance " << badPixelTolerance << ")" << TestLog::EndMessage;
2907 					success = false;
2908 					break;
2909 				}
2910 
2911 				if ((Winding)frontFaceWinding == m_winding)
2912 				{
2913 					if (m_primitiveType == TESSPRIMITIVETYPE_TRIANGLES)
2914 					{
2915 						if (de::abs(numWhitePixels - totalNumPixels/2) > badPixelTolerance)
2916 						{
2917 							log << TestLog::Message << "Failure: wrong number of white pixels; expected approximately " << totalNumPixels/2 << TestLog::EndMessage;
2918 							success = false;
2919 							break;
2920 						}
2921 					}
2922 					else if (m_primitiveType == TESSPRIMITIVETYPE_QUADS)
2923 					{
2924 						if (numWhitePixels != totalNumPixels)
2925 						{
2926 							log << TestLog::Message << "Failure: expected only white pixels (full-viewport quad)" << TestLog::EndMessage;
2927 							success = false;
2928 							break;
2929 						}
2930 					}
2931 					else
2932 						DE_ASSERT(false);
2933 				}
2934 				else
2935 				{
2936 					if (numWhitePixels != 0)
2937 					{
2938 						log << TestLog::Message << "Failure: expected only red pixels (everything culled)" << TestLog::EndMessage;
2939 						success = false;
2940 						break;
2941 					}
2942 				}
2943 			}
2944 		}
2945 	}
2946 
2947 	m_testCtx.setTestResult(success ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, success ? "Pass" : "Image verification failed");
2948 	return STOP;
2949 }
2950 
2951 // Test potentially differing input and output patch sizes.
2952 class PatchVertexCountCase : public TestCase
2953 {
2954 public:
PatchVertexCountCase(Context & context,const char * name,const char * description,int inputPatchSize,int outputPatchSize,const char * referenceImagePath)2955 	PatchVertexCountCase (Context& context, const char* name, const char* description, int inputPatchSize, int outputPatchSize, const char* referenceImagePath)
2956 		: TestCase				(context, name, description)
2957 		, m_inputPatchSize		(inputPatchSize)
2958 		, m_outputPatchSize		(outputPatchSize)
2959 		, m_referenceImagePath	(referenceImagePath)
2960 	{
2961 	}
2962 
2963 	void							init				(void);
2964 	void							deinit				(void);
2965 	IterateResult					iterate				(void);
2966 
2967 private:
2968 	static const int				RENDER_SIZE = 256;
2969 
2970 	const int						m_inputPatchSize;
2971 	const int						m_outputPatchSize;
2972 
2973 	const string					m_referenceImagePath;
2974 
2975 	SharedPtr<const ShaderProgram>	m_program;
2976 };
2977 
init(void)2978 void PatchVertexCountCase::init (void)
2979 {
2980 	checkTessellationSupport(m_context);
2981 	checkRenderTargetSize(m_context.getRenderTarget(), RENDER_SIZE);
2982 
2983 	const string inSizeStr		= de::toString(m_inputPatchSize);
2984 	const string outSizeStr		= de::toString(m_outputPatchSize);
2985 
2986 	std::string vertexShaderTemplate			("${GLSL_VERSION_DECL}\n"
2987 												 "${GLSL_PER_VERTEX_OUT}\n"
2988 												 "\n"
2989 												 "in highp float in_v_attr;\n"
2990 												 "\n"
2991 												 "out highp float in_tc_attr;\n"
2992 												 "\n"
2993 												 "void main (void)\n"
2994 												 "{\n"
2995 												 "	in_tc_attr = in_v_attr;\n"
2996 												 "}\n");
2997 	std::string tessellationControlTemplate		("${GLSL_VERSION_DECL}\n"
2998 												 "${TESSELLATION_SHADER_REQUIRE}\n"
2999 												 "${GLSL_PER_VERTEX_IN_ARR}\n"
3000 												 "${GLSL_PER_VERTEX_OUT_ARR}\n"
3001 												 "\n"
3002 												 "layout (vertices = " + outSizeStr + ") out;\n"
3003 												 "\n"
3004 												 "in highp float in_tc_attr[];\n"
3005 												 "\n"
3006 												 "out highp float in_te_attr[];\n"
3007 												 "\n"
3008 												 "void main (void)\n"
3009 												 "{\n"
3010 												 "	in_te_attr[gl_InvocationID] = in_tc_attr[gl_InvocationID*" + inSizeStr + "/" + outSizeStr + "];\n"
3011 												 "\n"
3012 												 "	gl_TessLevelInner[0] = 5.0;\n"
3013 												 "	gl_TessLevelInner[1] = 5.0;\n"
3014 												 "\n"
3015 												"	gl_TessLevelOuter[0] = 5.0;\n"
3016 												"	gl_TessLevelOuter[1] = 5.0;\n"
3017 												"	gl_TessLevelOuter[2] = 5.0;\n"
3018 												"	gl_TessLevelOuter[3] = 5.0;\n"
3019 												 "}\n");
3020 	std::string tessellationEvaluationTemplate	("${GLSL_VERSION_DECL}\n"
3021 												 "${TESSELLATION_SHADER_REQUIRE}\n"
3022 												 "${GLSL_PER_VERTEX_IN_ARR}\n"
3023 												 "${GLSL_PER_VERTEX_OUT}\n"
3024 												 "\n"
3025 												 + getTessellationEvaluationInLayoutString(TESSPRIMITIVETYPE_QUADS) +
3026 												 "\n"
3027 												 "in highp float in_te_attr[];\n"
3028 												 "\n"
3029 												 "out mediump vec4 in_f_color;\n"
3030 												 "\n"
3031 												 "void main (void)\n"
3032 												 "{\n"
3033 												 "	highp float x = gl_TessCoord.x*2.0 - 1.0;\n"
3034 												 "	highp float y = gl_TessCoord.y - in_te_attr[int(round(gl_TessCoord.x*float(" + outSizeStr + "-1)))];\n"
3035 												 "	gl_Position = vec4(x, y, 0.0, 1.0);\n"
3036 												 "	in_f_color = vec4(1.0);\n"
3037 												 "}\n");
3038 	std::string fragmentShaderTemplate			("${GLSL_VERSION_DECL}\n"
3039 												 "\n"
3040 												 "layout (location = 0) out mediump vec4 o_color;\n"
3041 												 "\n"
3042 												 "in mediump vec4 in_f_color;\n"
3043 												 "\n"
3044 												 "void main (void)\n"
3045 												 "{\n"
3046 												 "	o_color = in_f_color;\n"
3047 												 "}\n");
3048 
3049 	m_program = SharedPtr<const ShaderProgram>(new ShaderProgram(m_context.getRenderContext(), glu::ProgramSources()
3050 			<< glu::VertexSource					(specializeShader(m_context, vertexShaderTemplate.c_str()))
3051 			<< glu::TessellationControlSource		(specializeShader(m_context, tessellationControlTemplate.c_str()))
3052 			<< glu::TessellationEvaluationSource	(specializeShader(m_context, tessellationEvaluationTemplate.c_str()))
3053 			<< glu::FragmentSource					(specializeShader(m_context, fragmentShaderTemplate.c_str()))));
3054 
3055 	m_testCtx.getLog() << *m_program;
3056 	if (!m_program->isOk())
3057 		TCU_FAIL("Program compilation failed");
3058 }
3059 
deinit(void)3060 void PatchVertexCountCase::deinit (void)
3061 {
3062 	m_program.clear();
3063 }
3064 
iterate(void)3065 PatchVertexCountCase::IterateResult PatchVertexCountCase::iterate (void)
3066 {
3067 	TestLog&					log						= m_testCtx.getLog();
3068 	const RenderContext&		renderCtx				= m_context.getRenderContext();
3069 	const RandomViewport		viewport				(renderCtx.getRenderTarget(), RENDER_SIZE, RENDER_SIZE, deStringHash(getName()));
3070 	const deUint32				programGL				= m_program->getProgram();
3071 	const glw::Functions&		gl						= renderCtx.getFunctions();
3072 
3073 	setViewport(gl, viewport);
3074 	gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
3075 	gl.useProgram(programGL);
3076 
3077 	log << TestLog::Message << "Note: input patch size is " << m_inputPatchSize << ", output patch size is " << m_outputPatchSize << TestLog::EndMessage;
3078 
3079 	{
3080 		vector<float> attributeData;
3081 		attributeData.reserve(m_inputPatchSize);
3082 
3083 		for (int i = 0; i < m_inputPatchSize; i++)
3084 		{
3085 			const float f = (float)i / (float)(m_inputPatchSize-1);
3086 			attributeData.push_back(f*f);
3087 		}
3088 
3089 		gl.patchParameteri(GL_PATCH_VERTICES, m_inputPatchSize);
3090 		gl.clear(GL_COLOR_BUFFER_BIT);
3091 
3092 		const glu::VertexArrayBinding attrBindings[] =
3093 		{
3094 			glu::va::Float("in_v_attr", 1, (int)attributeData.size(), 0, &attributeData[0])
3095 		};
3096 
3097 		glu::draw(m_context.getRenderContext(), programGL, DE_LENGTH_OF_ARRAY(attrBindings), &attrBindings[0],
3098 			glu::pr::Patches(m_inputPatchSize));
3099 		GLU_EXPECT_NO_ERROR(gl.getError(), "Draw failed");
3100 	}
3101 
3102 	{
3103 		const tcu::Surface			rendered	= getPixels(renderCtx, viewport);
3104 		const tcu::TextureLevel		reference	= getPNG(m_testCtx.getArchive(), m_referenceImagePath);
3105 		const bool					success		= tcu::fuzzyCompare(log, "ImageComparison", "Image Comparison", reference.getAccess(), rendered.getAccess(), 0.02f, tcu::COMPARE_LOG_RESULT);
3106 
3107 		m_testCtx.setTestResult(success ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, success ? "Pass" : "Image comparison failed");
3108 		return STOP;
3109 	}
3110 }
3111 
3112 // Test per-patch inputs/outputs.
3113 class PerPatchDataCase : public TestCase
3114 {
3115 public:
3116 	enum CaseType
3117 	{
3118 		CASETYPE_PRIMITIVE_ID_TCS = 0,
3119 		CASETYPE_PRIMITIVE_ID_TES,
3120 		CASETYPE_PATCH_VERTICES_IN_TCS,
3121 		CASETYPE_PATCH_VERTICES_IN_TES,
3122 		CASETYPE_TESS_LEVEL_INNER0_TES,
3123 		CASETYPE_TESS_LEVEL_INNER1_TES,
3124 		CASETYPE_TESS_LEVEL_OUTER0_TES,
3125 		CASETYPE_TESS_LEVEL_OUTER1_TES,
3126 		CASETYPE_TESS_LEVEL_OUTER2_TES,
3127 		CASETYPE_TESS_LEVEL_OUTER3_TES,
3128 
3129 		CASETYPE_LAST
3130 	};
3131 
PerPatchDataCase(Context & context,const char * name,const char * description,CaseType caseType,const char * referenceImagePath)3132 	PerPatchDataCase (Context& context, const char* name, const char* description, CaseType caseType, const char* referenceImagePath)
3133 		: TestCase				(context, name, description)
3134 		, m_caseType			(caseType)
3135 		, m_referenceImagePath	(caseTypeUsesRefImageFromFile(caseType) ? referenceImagePath : "")
3136 	{
3137 		DE_ASSERT(caseTypeUsesRefImageFromFile(caseType) == (referenceImagePath != DE_NULL));
3138 	}
3139 
3140 	void							init							(void);
3141 	void							deinit							(void);
3142 	IterateResult					iterate							(void);
3143 
3144 	static const char*				getCaseTypeName					(CaseType);
3145 	static const char*				getCaseTypeDescription			(CaseType);
3146 	static bool						caseTypeUsesRefImageFromFile	(CaseType);
3147 
3148 private:
3149 	static const int				RENDER_SIZE = 256;
3150 	static const int				INPUT_PATCH_SIZE;
3151 	static const int				OUTPUT_PATCH_SIZE;
3152 
3153 	const CaseType					m_caseType;
3154 	const string					m_referenceImagePath;
3155 
3156 	SharedPtr<const ShaderProgram>	m_program;
3157 };
3158 
3159 const int PerPatchDataCase::INPUT_PATCH_SIZE	= 10;
3160 const int PerPatchDataCase::OUTPUT_PATCH_SIZE	= 5;
3161 
getCaseTypeName(CaseType type)3162 const char* PerPatchDataCase::getCaseTypeName (CaseType type)
3163 {
3164 	switch (type)
3165 	{
3166 		case CASETYPE_PRIMITIVE_ID_TCS:			return "primitive_id_tcs";
3167 		case CASETYPE_PRIMITIVE_ID_TES:			return "primitive_id_tes";
3168 		case CASETYPE_PATCH_VERTICES_IN_TCS:	return "patch_vertices_in_tcs";
3169 		case CASETYPE_PATCH_VERTICES_IN_TES:	return "patch_vertices_in_tes";
3170 		case CASETYPE_TESS_LEVEL_INNER0_TES:	return "tess_level_inner_0_tes";
3171 		case CASETYPE_TESS_LEVEL_INNER1_TES:	return "tess_level_inner_1_tes";
3172 		case CASETYPE_TESS_LEVEL_OUTER0_TES:	return "tess_level_outer_0_tes";
3173 		case CASETYPE_TESS_LEVEL_OUTER1_TES:	return "tess_level_outer_1_tes";
3174 		case CASETYPE_TESS_LEVEL_OUTER2_TES:	return "tess_level_outer_2_tes";
3175 		case CASETYPE_TESS_LEVEL_OUTER3_TES:	return "tess_level_outer_3_tes";
3176 		default:
3177 			DE_ASSERT(false);
3178 			return DE_NULL;
3179 	}
3180 }
3181 
getCaseTypeDescription(CaseType type)3182 const char* PerPatchDataCase::getCaseTypeDescription (CaseType type)
3183 {
3184 	switch (type)
3185 	{
3186 		case CASETYPE_PRIMITIVE_ID_TCS:			return "Read gl_PrimitiveID in TCS and pass it as patch output to TES";
3187 		case CASETYPE_PRIMITIVE_ID_TES:			return "Read gl_PrimitiveID in TES";
3188 		case CASETYPE_PATCH_VERTICES_IN_TCS:	return "Read gl_PatchVerticesIn in TCS and pass it as patch output to TES";
3189 		case CASETYPE_PATCH_VERTICES_IN_TES:	return "Read gl_PatchVerticesIn in TES";
3190 		case CASETYPE_TESS_LEVEL_INNER0_TES:	return "Read gl_TessLevelInner[0] in TES";
3191 		case CASETYPE_TESS_LEVEL_INNER1_TES:	return "Read gl_TessLevelInner[1] in TES";
3192 		case CASETYPE_TESS_LEVEL_OUTER0_TES:	return "Read gl_TessLevelOuter[0] in TES";
3193 		case CASETYPE_TESS_LEVEL_OUTER1_TES:	return "Read gl_TessLevelOuter[1] in TES";
3194 		case CASETYPE_TESS_LEVEL_OUTER2_TES:	return "Read gl_TessLevelOuter[2] in TES";
3195 		case CASETYPE_TESS_LEVEL_OUTER3_TES:	return "Read gl_TessLevelOuter[3] in TES";
3196 		default:
3197 			DE_ASSERT(false);
3198 			return DE_NULL;
3199 	}
3200 }
3201 
caseTypeUsesRefImageFromFile(CaseType type)3202 bool PerPatchDataCase::caseTypeUsesRefImageFromFile (CaseType type)
3203 {
3204 	switch (type)
3205 	{
3206 		case CASETYPE_PRIMITIVE_ID_TCS:
3207 		case CASETYPE_PRIMITIVE_ID_TES:
3208 			return true;
3209 
3210 		default:
3211 			return false;
3212 	}
3213 }
3214 
init(void)3215 void PerPatchDataCase::init (void)
3216 {
3217 	checkTessellationSupport(m_context);
3218 	checkRenderTargetSize(m_context.getRenderTarget(), RENDER_SIZE);
3219 
3220 	DE_ASSERT(OUTPUT_PATCH_SIZE < INPUT_PATCH_SIZE);
3221 
3222 	const string inSizeStr		= de::toString(INPUT_PATCH_SIZE);
3223 	const string outSizeStr		= de::toString(OUTPUT_PATCH_SIZE);
3224 
3225 	std::string vertexShaderTemplate			("${GLSL_VERSION_DECL}\n"
3226 													 "${GLSL_PER_VERTEX_OUT}\n"
3227 													 "\n"
3228 													 "in highp float in_v_attr;\n"
3229 													 "\n"
3230 													 "out highp float in_tc_attr;\n"
3231 													 "\n"
3232 													 "void main (void)\n"
3233 													 "{\n"
3234 													 "	in_tc_attr = in_v_attr;\n"
3235 													 "}\n");
3236 	std::string tessellationControlTemplate		("${GLSL_VERSION_DECL}\n"
3237 												 "${TESSELLATION_SHADER_REQUIRE}\n"
3238 												 "${GLSL_PER_VERTEX_IN_ARR}\n"
3239 												 "${GLSL_PER_VERTEX_OUT_ARR}\n"
3240 													 "\n"
3241 													 "layout (vertices = " + outSizeStr + ") out;\n"
3242 													 "\n"
3243 													 "in highp float in_tc_attr[];\n"
3244 													 "\n"
3245 													 "out highp float in_te_attr[];\n"
3246 													 + (m_caseType == CASETYPE_PRIMITIVE_ID_TCS			? "patch out mediump int in_te_primitiveIDFromTCS;\n"
3247 													  : m_caseType == CASETYPE_PATCH_VERTICES_IN_TCS	? "patch out mediump int in_te_patchVerticesInFromTCS;\n"
3248 													  : "") +
3249 													 "\n"
3250 													 "void main (void)\n"
3251 													 "{\n"
3252 													 "	in_te_attr[gl_InvocationID] = in_tc_attr[gl_InvocationID];\n"
3253 													 + (m_caseType == CASETYPE_PRIMITIVE_ID_TCS			? "\tin_te_primitiveIDFromTCS = gl_PrimitiveID;\n"
3254 													  : m_caseType == CASETYPE_PATCH_VERTICES_IN_TCS	? "\tin_te_patchVerticesInFromTCS = gl_PatchVerticesIn;\n"
3255 													  : "") +
3256 													 "\n"
3257 													 "	gl_TessLevelInner[0] = 9.0;\n"
3258 													 "	gl_TessLevelInner[1] = 8.0;\n"
3259 													 "\n"
3260 													"	gl_TessLevelOuter[0] = 7.0;\n"
3261 													"	gl_TessLevelOuter[1] = 6.0;\n"
3262 													"	gl_TessLevelOuter[2] = 5.0;\n"
3263 													"	gl_TessLevelOuter[3] = 4.0;\n"
3264 												 "}\n");
3265 	std::string tessellationEvaluationTemplate	("${GLSL_VERSION_DECL}\n"
3266 												 "${TESSELLATION_SHADER_REQUIRE}\n"
3267 												 "${GLSL_PER_VERTEX_IN_ARR}\n"
3268 												 "${GLSL_PER_VERTEX_OUT}\n"
3269 													 "\n"
3270 													 + getTessellationEvaluationInLayoutString(TESSPRIMITIVETYPE_QUADS) +
3271 													 "\n"
3272 													 "in highp float in_te_attr[];\n"
3273 													 + (m_caseType == CASETYPE_PRIMITIVE_ID_TCS			? "patch in mediump int in_te_primitiveIDFromTCS;\n"
3274 													  : m_caseType == CASETYPE_PATCH_VERTICES_IN_TCS	? "patch in mediump int in_te_patchVerticesInFromTCS;\n"
3275 													  : string()) +
3276 													 "\n"
3277 													 "out mediump vec4 in_f_color;\n"
3278 													 "\n"
3279 													 "uniform highp float u_xScale;\n"
3280 													 "\n"
3281 													 "void main (void)\n"
3282 													 "{\n"
3283 													 "	highp float x = (gl_TessCoord.x*u_xScale + in_te_attr[0]) * 2.0 - 1.0;\n"
3284 													 "	highp float y = gl_TessCoord.y*2.0 - 1.0;\n"
3285 													 "	gl_Position = vec4(x, y, 0.0, 1.0);\n"
3286 													 + (m_caseType == CASETYPE_PRIMITIVE_ID_TCS			? "\tbool ok = in_te_primitiveIDFromTCS == 3;\n"
3287 													  : m_caseType == CASETYPE_PRIMITIVE_ID_TES			? "\tbool ok = gl_PrimitiveID == 3;\n"
3288 													  : m_caseType == CASETYPE_PATCH_VERTICES_IN_TCS	? "\tbool ok = in_te_patchVerticesInFromTCS == " + inSizeStr + ";\n"
3289 													  : m_caseType == CASETYPE_PATCH_VERTICES_IN_TES	? "\tbool ok = gl_PatchVerticesIn == " + outSizeStr + ";\n"
3290 													  : m_caseType == CASETYPE_TESS_LEVEL_INNER0_TES	? "\tbool ok = abs(gl_TessLevelInner[0] - 9.0) < 0.1f;\n"
3291 													  : m_caseType == CASETYPE_TESS_LEVEL_INNER1_TES	? "\tbool ok = abs(gl_TessLevelInner[1] - 8.0) < 0.1f;\n"
3292 													  : m_caseType == CASETYPE_TESS_LEVEL_OUTER0_TES	? "\tbool ok = abs(gl_TessLevelOuter[0] - 7.0) < 0.1f;\n"
3293 													  : m_caseType == CASETYPE_TESS_LEVEL_OUTER1_TES	? "\tbool ok = abs(gl_TessLevelOuter[1] - 6.0) < 0.1f;\n"
3294 													  : m_caseType == CASETYPE_TESS_LEVEL_OUTER2_TES	? "\tbool ok = abs(gl_TessLevelOuter[2] - 5.0) < 0.1f;\n"
3295 													  : m_caseType == CASETYPE_TESS_LEVEL_OUTER3_TES	? "\tbool ok = abs(gl_TessLevelOuter[3] - 4.0) < 0.1f;\n"
3296 													  : DE_NULL) +
3297 													  "	in_f_color = ok ? vec4(1.0) : vec4(vec3(0.0), 1.0);\n"
3298 												 "}\n");
3299 	std::string fragmentShaderTemplate			("${GLSL_VERSION_DECL}\n"
3300 													 "\n"
3301 													 "layout (location = 0) out mediump vec4 o_color;\n"
3302 													 "\n"
3303 													 "in mediump vec4 in_f_color;\n"
3304 													 "\n"
3305 													 "void main (void)\n"
3306 													 "{\n"
3307 													 "	o_color = in_f_color;\n"
3308 												 "}\n");
3309 
3310 	m_program = SharedPtr<const ShaderProgram>(new ShaderProgram(m_context.getRenderContext(), glu::ProgramSources()
3311 			<< glu::VertexSource					(specializeShader(m_context, vertexShaderTemplate.c_str()))
3312 			<< glu::TessellationControlSource		(specializeShader(m_context, tessellationControlTemplate.c_str()))
3313 			<< glu::TessellationEvaluationSource	(specializeShader(m_context, tessellationEvaluationTemplate.c_str()))
3314 			<< glu::FragmentSource					(specializeShader(m_context, fragmentShaderTemplate.c_str()))));
3315 
3316 	m_testCtx.getLog() << *m_program;
3317 	if (!m_program->isOk())
3318 		TCU_FAIL("Program compilation failed");
3319 }
3320 
deinit(void)3321 void PerPatchDataCase::deinit (void)
3322 {
3323 	m_program.clear();
3324 }
3325 
iterate(void)3326 PerPatchDataCase::IterateResult PerPatchDataCase::iterate (void)
3327 {
3328 	TestLog&					log						= m_testCtx.getLog();
3329 	const RenderContext&		renderCtx				= m_context.getRenderContext();
3330 	const RandomViewport		viewport				(renderCtx.getRenderTarget(), RENDER_SIZE, RENDER_SIZE, deStringHash(getName()));
3331 	const deUint32				programGL				= m_program->getProgram();
3332 	const glw::Functions&		gl						= renderCtx.getFunctions();
3333 
3334 	setViewport(gl, viewport);
3335 	gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
3336 	gl.useProgram(programGL);
3337 
3338 	log << TestLog::Message << "Note: input patch size is " << INPUT_PATCH_SIZE << ", output patch size is " << OUTPUT_PATCH_SIZE << TestLog::EndMessage;
3339 
3340 	{
3341 		const int numPrimitives = m_caseType == CASETYPE_PRIMITIVE_ID_TCS || m_caseType == CASETYPE_PRIMITIVE_ID_TES ? 8 : 1;
3342 
3343 		vector<float> attributeData;
3344 		attributeData.reserve(numPrimitives*INPUT_PATCH_SIZE);
3345 
3346 		for (int i = 0; i < numPrimitives; i++)
3347 		{
3348 			attributeData.push_back((float)i / (float)numPrimitives);
3349 			for (int j = 0; j < INPUT_PATCH_SIZE-1; j++)
3350 				attributeData.push_back(0.0f);
3351 		}
3352 
3353 		gl.patchParameteri(GL_PATCH_VERTICES, INPUT_PATCH_SIZE);
3354 		gl.clear(GL_COLOR_BUFFER_BIT);
3355 
3356 		gl.uniform1f(gl.getUniformLocation(programGL, "u_xScale"), 1.0f / (float)numPrimitives);
3357 
3358 		const glu::VertexArrayBinding attrBindings[] =
3359 		{
3360 			glu::va::Float("in_v_attr", 1, (int)attributeData.size(), 0, &attributeData[0])
3361 		};
3362 
3363 		glu::draw(m_context.getRenderContext(), programGL, DE_LENGTH_OF_ARRAY(attrBindings), &attrBindings[0],
3364 			glu::pr::Patches(numPrimitives*INPUT_PATCH_SIZE));
3365 		GLU_EXPECT_NO_ERROR(gl.getError(), "Draw failed");
3366 	}
3367 
3368 	{
3369 		const tcu::Surface rendered = getPixels(renderCtx, viewport);
3370 
3371 		if (m_caseType == CASETYPE_PRIMITIVE_ID_TCS || m_caseType == CASETYPE_PRIMITIVE_ID_TES)
3372 		{
3373 			DE_ASSERT(caseTypeUsesRefImageFromFile(m_caseType));
3374 
3375 			const tcu::TextureLevel		reference	= getPNG(m_testCtx.getArchive(), m_referenceImagePath);
3376 			const bool					success		= tcu::fuzzyCompare(log, "ImageComparison", "Image Comparison", reference.getAccess(), rendered.getAccess(), 0.02f, tcu::COMPARE_LOG_RESULT);
3377 
3378 			m_testCtx.setTestResult(success ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, success ? "Pass" : "Image comparison failed");
3379 			return STOP;
3380 		}
3381 		else
3382 		{
3383 			DE_ASSERT(!caseTypeUsesRefImageFromFile(m_caseType));
3384 
3385 			log << TestLog::Image("RenderedImage", "Rendered Image", rendered);
3386 
3387 			for (int y = 0; y < rendered.getHeight();	y++)
3388 			for (int x = 0; x < rendered.getWidth();	x++)
3389 			{
3390 				if (rendered.getPixel(x, y) != tcu::RGBA::white())
3391 				{
3392 					log << TestLog::Message << "Failure: expected all white pixels" << TestLog::EndMessage;
3393 					m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image verification failed");
3394 					return STOP;
3395 				}
3396 			}
3397 
3398 			m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
3399 			return STOP;
3400 		}
3401 	}
3402 }
3403 
3404 // Basic barrier() usage in TCS.
3405 class BarrierCase : public TestCase
3406 {
3407 public:
BarrierCase(Context & context,const char * name,const char * description,const char * referenceImagePath)3408 	BarrierCase (Context& context, const char* name, const char* description, const char* referenceImagePath)
3409 		: TestCase				(context, name, description)
3410 		, m_referenceImagePath	(referenceImagePath)
3411 	{
3412 	}
3413 
3414 	void							init		(void);
3415 	void							deinit		(void);
3416 	IterateResult					iterate		(void);
3417 
3418 private:
3419 	static const int				RENDER_SIZE = 256;
3420 	static const int				NUM_VERTICES;
3421 
3422 	const string					m_referenceImagePath;
3423 
3424 	SharedPtr<const ShaderProgram>	m_program;
3425 };
3426 
3427 const int BarrierCase::NUM_VERTICES = 32;
3428 
init(void)3429 void BarrierCase::init (void)
3430 {
3431 	checkTessellationSupport(m_context);
3432 	checkRenderTargetSize(m_context.getRenderTarget(), RENDER_SIZE);
3433 
3434 	const string numVertsStr = de::toString(NUM_VERTICES);
3435 
3436 	std::string vertexShaderTemplate			("${GLSL_VERSION_DECL}\n"
3437 													 "${GLSL_PER_VERTEX_OUT}\n"
3438 													 "\n"
3439 													 "in highp float in_v_attr;\n"
3440 													 "\n"
3441 													 "out highp float in_tc_attr;\n"
3442 													 "\n"
3443 													 "void main (void)\n"
3444 													 "{\n"
3445 													 "	in_tc_attr = in_v_attr;\n"
3446 												 "}\n");
3447 	std::string tessellationControlTemplate		("${GLSL_VERSION_DECL}\n"
3448 												 "${TESSELLATION_SHADER_REQUIRE}\n"
3449 													 "${GLSL_PER_VERTEX_IN_ARR}\n"
3450 													 "${GLSL_PER_VERTEX_OUT_ARR}\n"
3451 													 "\n"
3452 													 "layout (vertices = " + numVertsStr + ") out;\n"
3453 													 "\n"
3454 													 "in highp float in_tc_attr[];\n"
3455 													 "\n"
3456 													 "out highp float in_te_attr[];\n"
3457 													 "patch out highp float in_te_patchAttr;\n"
3458 													 "\n"
3459 													 "void main (void)\n"
3460 													 "{\n"
3461 													 "	in_te_attr[gl_InvocationID] = in_tc_attr[gl_InvocationID];\n"
3462 													 "	in_te_patchAttr = 0.0f;\n"
3463 													 "	barrier();\n"
3464 													 "	if (gl_InvocationID == 5)\n"
3465 													 "		in_te_patchAttr = float(gl_InvocationID)*0.1;\n"
3466 													 "	barrier();\n"
3467 													 "	highp float temp = in_te_patchAttr + in_te_attr[gl_InvocationID];\n"
3468 													 "	barrier();\n"
3469 													 "	if (gl_InvocationID == " + numVertsStr + "-1)\n"
3470 													 "		in_te_patchAttr = float(gl_InvocationID);\n"
3471 													 "	barrier();\n"
3472 													 "	in_te_attr[gl_InvocationID] = temp;\n"
3473 													 "	barrier();\n"
3474 													 "	temp = temp + in_te_attr[(gl_InvocationID+1) % " + numVertsStr + "];\n"
3475 													 "	barrier();\n"
3476 													 "	in_te_attr[gl_InvocationID] = 0.25*temp;\n"
3477 													 "\n"
3478 													 "	gl_TessLevelInner[0] = 32.0;\n"
3479 													 "	gl_TessLevelInner[1] = 32.0;\n"
3480 													 "\n"
3481 													 "	gl_TessLevelOuter[0] = 32.0;\n"
3482 													 "	gl_TessLevelOuter[1] = 32.0;\n"
3483 													 "	gl_TessLevelOuter[2] = 32.0;\n"
3484 													 "	gl_TessLevelOuter[3] = 32.0;\n"
3485 												 "}\n");
3486 	std::string tessellationEvaluationTemplate	("${GLSL_VERSION_DECL}\n"
3487 												 "${TESSELLATION_SHADER_REQUIRE}\n"
3488 													 "${GLSL_PER_VERTEX_IN_ARR}\n"
3489 													 "${GLSL_PER_VERTEX_OUT}\n"
3490 													 "\n"
3491 													 + getTessellationEvaluationInLayoutString(TESSPRIMITIVETYPE_QUADS) +
3492 													 "\n"
3493 													 "in highp float in_te_attr[];\n"
3494 													 "patch in highp float in_te_patchAttr;\n"
3495 													 "\n"
3496 													 "out highp float in_f_blue;\n"
3497 													 "\n"
3498 													 "void main (void)\n"
3499 													 "{\n"
3500 													 "	highp float x = gl_TessCoord.x*2.0 - 1.0;\n"
3501 													 "	highp float y = gl_TessCoord.y - in_te_attr[int(round(gl_TessCoord.x*float(" + numVertsStr + "-1)))];\n"
3502 													 "	gl_Position = vec4(x, y, 0.0, 1.0);\n"
3503 													 "	in_f_blue = abs(in_te_patchAttr - float(" + numVertsStr + "-1));\n"
3504 												 "}\n");
3505 	std::string fragmentShaderTemplate			("${GLSL_VERSION_DECL}\n"
3506 													 "\n"
3507 													 "layout (location = 0) out mediump vec4 o_color;\n"
3508 													 "\n"
3509 													 "in highp float in_f_blue;\n"
3510 													 "\n"
3511 													 "void main (void)\n"
3512 													 "{\n"
3513 													 "	o_color = vec4(1.0, 0.0, in_f_blue, 1.0);\n"
3514 												 "}\n");
3515 
3516 	m_program = SharedPtr<const ShaderProgram>(new ShaderProgram(m_context.getRenderContext(), glu::ProgramSources()
3517 			<< glu::VertexSource					(specializeShader(m_context, vertexShaderTemplate.c_str()))
3518 			<< glu::TessellationControlSource		(specializeShader(m_context, tessellationControlTemplate.c_str()))
3519 			<< glu::TessellationEvaluationSource	(specializeShader(m_context, tessellationEvaluationTemplate.c_str()))
3520 			<< glu::FragmentSource					(specializeShader(m_context, fragmentShaderTemplate.c_str()))));
3521 
3522 	m_testCtx.getLog() << *m_program;
3523 	if (!m_program->isOk())
3524 		TCU_FAIL("Program compilation failed");
3525 }
3526 
deinit(void)3527 void BarrierCase::deinit (void)
3528 {
3529 	m_program.clear();
3530 }
3531 
iterate(void)3532 BarrierCase::IterateResult BarrierCase::iterate (void)
3533 {
3534 	TestLog&					log						= m_testCtx.getLog();
3535 	const RenderContext&		renderCtx				= m_context.getRenderContext();
3536 	const RandomViewport		viewport				(renderCtx.getRenderTarget(), RENDER_SIZE, RENDER_SIZE, deStringHash(getName()));
3537 	const deUint32				programGL				= m_program->getProgram();
3538 	const glw::Functions&		gl						= renderCtx.getFunctions();
3539 
3540 	setViewport(gl, viewport);
3541 	gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
3542 	gl.useProgram(programGL);
3543 
3544 	{
3545 		vector<float> attributeData(NUM_VERTICES);
3546 
3547 		for (int i = 0; i < NUM_VERTICES; i++)
3548 			attributeData[i] = (float)i / (float)(NUM_VERTICES-1);
3549 
3550 		gl.patchParameteri(GL_PATCH_VERTICES, NUM_VERTICES);
3551 		gl.clear(GL_COLOR_BUFFER_BIT);
3552 
3553 		const glu::VertexArrayBinding attrBindings[] =
3554 		{
3555 			glu::va::Float("in_v_attr", 1, (int)attributeData.size(), 0, &attributeData[0])
3556 		};
3557 
3558 		glu::draw(m_context.getRenderContext(), programGL, DE_LENGTH_OF_ARRAY(attrBindings), &attrBindings[0],
3559 			glu::pr::Patches(NUM_VERTICES));
3560 		GLU_EXPECT_NO_ERROR(gl.getError(), "Draw failed");
3561 	}
3562 
3563 	{
3564 		const tcu::Surface			rendered	= getPixels(renderCtx, viewport);
3565 		const tcu::TextureLevel		reference	= getPNG(m_testCtx.getArchive(), m_referenceImagePath);
3566 		const bool					success		= tcu::fuzzyCompare(log, "ImageComparison", "Image Comparison", reference.getAccess(), rendered.getAccess(), 0.02f, tcu::COMPARE_LOG_RESULT);
3567 
3568 		m_testCtx.setTestResult(success ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, success ? "Pass" : "Image comparison failed");
3569 		return STOP;
3570 	}
3571 }
3572 
3573 /*--------------------------------------------------------------------*//*!
3574  * \brief Base class for testing invariance of entire primitive set
3575  *
3576  * Draws two patches with identical tessellation levels and compares the
3577  * results. Repeats the same with other programs that are only different
3578  * in irrelevant ways; compares the results between these two programs.
3579  * Also potentially compares to results produced by different tessellation
3580  * levels (see e.g. invariance rule #6).
3581  * Furthermore, repeats the above with multiple different tessellation
3582  * value sets.
3583  *
3584  * The manner of primitive set comparison is defined by subclass. E.g.
3585  * case for invariance rule #1 tests that same vertices come out, in same
3586  * order; rule #5 only requires that the same triangles are output, but
3587  * not necessarily in the same order.
3588  *//*--------------------------------------------------------------------*/
3589 class PrimitiveSetInvarianceCase : public TestCase
3590 {
3591 public:
3592 	enum WindingUsage
3593 	{
3594 		WINDINGUSAGE_CCW = 0,
3595 		WINDINGUSAGE_CW,
3596 		WINDINGUSAGE_VARY,
3597 
3598 		WINDINGUSAGE_LAST
3599 	};
3600 
PrimitiveSetInvarianceCase(Context & context,const char * name,const char * description,TessPrimitiveType primType,SpacingMode spacing,bool usePointMode,WindingUsage windingUsage)3601 	PrimitiveSetInvarianceCase (Context& context, const char* name, const char* description, TessPrimitiveType primType, SpacingMode spacing, bool usePointMode, WindingUsage windingUsage)
3602 		: TestCase			(context, name, description)
3603 		, m_primitiveType	(primType)
3604 		, m_spacing			(spacing)
3605 		, m_usePointMode	(usePointMode)
3606 		, m_windingUsage	(windingUsage)
3607 	{
3608 	}
3609 
3610 	void									init				(void);
3611 	void									deinit				(void);
3612 	IterateResult							iterate				(void);
3613 
3614 protected:
3615 	struct TessLevels
3616 	{
3617 		float inner[2];
3618 		float outer[4];
descriptiondeqp::gles31::Functional::__anon755cd4500211::PrimitiveSetInvarianceCase::TessLevels3619 		string description (void) const { return tessellationLevelsString(&inner[0], &outer[0]); }
3620 	};
3621 	struct LevelCase
3622 	{
3623 		vector<TessLevels>	levels;
3624 		int					mem; //!< Subclass-defined arbitrary piece of data, for type of the levelcase, if needed. Passed to compare().
LevelCasedeqp::gles31::Functional::__anon755cd4500211::PrimitiveSetInvarianceCase::LevelCase3625 		LevelCase (const TessLevels& lev) : levels(vector<TessLevels>(1, lev)), mem(0) {}
LevelCasedeqp::gles31::Functional::__anon755cd4500211::PrimitiveSetInvarianceCase::LevelCase3626 		LevelCase (void) : mem(0) {}
3627 	};
3628 
3629 	virtual vector<LevelCase>	genTessLevelCases	(void) const;
3630 	virtual bool				compare				(const vector<Vec3>& coordsA, const vector<Vec3>& coordsB, int levelCaseMem) const = 0;
3631 
3632 	const TessPrimitiveType		m_primitiveType;
3633 
3634 private:
3635 	struct Program
3636 	{
3637 		Winding							winding;
3638 		SharedPtr<const ShaderProgram>	program;
3639 
Programdeqp::gles31::Functional::__anon755cd4500211::PrimitiveSetInvarianceCase::Program3640 				Program			(Winding w, const SharedPtr<const ShaderProgram>& prog) : winding(w), program(prog) {}
3641 
descriptiondeqp::gles31::Functional::__anon755cd4500211::PrimitiveSetInvarianceCase::Program3642 		string	description		(void) const { return string() + "winding mode " + getWindingShaderName(winding); }
3643 	};
3644 
3645 	static const int			RENDER_SIZE = 16;
3646 
3647 	const SpacingMode			m_spacing;
3648 	const bool					m_usePointMode;
3649 	const WindingUsage			m_windingUsage;
3650 
3651 	vector<Program>				m_programs;
3652 };
3653 
genTessLevelCases(void) const3654 vector<PrimitiveSetInvarianceCase::LevelCase> PrimitiveSetInvarianceCase::genTessLevelCases (void) const
3655 {
3656 	static const TessLevels basicTessLevelCases[] =
3657 	{
3658 		{ { 1.0f,	1.0f	},	{ 1.0f,		1.0f,	1.0f,	1.0f	} },
3659 		{ { 63.0f,	24.0f	},	{ 15.0f,	42.0f,	10.0f,	12.0f	} },
3660 		{ { 3.0f,	2.0f	},	{ 6.0f,		8.0f,	7.0f,	9.0f	} },
3661 		{ { 4.0f,	6.0f	},	{ 2.0f,		3.0f,	1.0f,	4.0f	} },
3662 		{ { 2.0f,	2.0f	},	{ 6.0f,		8.0f,	7.0f,	9.0f	} },
3663 		{ { 5.0f,	6.0f	},	{ 1.0f,		1.0f,	1.0f,	1.0f	} },
3664 		{ { 1.0f,	6.0f	},	{ 2.0f,		3.0f,	1.0f,	4.0f	} },
3665 		{ { 5.0f,	1.0f	},	{ 2.0f,		3.0f,	1.0f,	4.0f	} },
3666 		{ { 5.2f,	1.6f	},	{ 2.9f,		3.4f,	1.5f,	4.1f	} }
3667 	};
3668 
3669 	vector<LevelCase> result;
3670 	for (int i = 0; i < DE_LENGTH_OF_ARRAY(basicTessLevelCases); i++)
3671 		result.push_back(LevelCase(basicTessLevelCases[i]));
3672 
3673 	{
3674 		de::Random rnd(123);
3675 		for (int i = 0; i < 10; i++)
3676 		{
3677 			TessLevels levels;
3678 			for (int j = 0; j < DE_LENGTH_OF_ARRAY(levels.inner); j++)
3679 				levels.inner[j] = rnd.getFloat(1.0f, 16.0f);
3680 			for (int j = 0; j < DE_LENGTH_OF_ARRAY(levels.outer); j++)
3681 				levels.outer[j] = rnd.getFloat(1.0f, 16.0f);
3682 			result.push_back(LevelCase(levels));
3683 		}
3684 	}
3685 
3686 	return result;
3687 }
3688 
init(void)3689 void PrimitiveSetInvarianceCase::init (void)
3690 {
3691 	const int			numDifferentConstantExprCases = 2;
3692 	vector<Winding>		windings;
3693 	switch (m_windingUsage)
3694 	{
3695 		case WINDINGUSAGE_CCW:		windings.push_back(WINDING_CCW); break;
3696 		case WINDINGUSAGE_CW:		windings.push_back(WINDING_CW); break;
3697 		case WINDINGUSAGE_VARY:		windings.push_back(WINDING_CCW);
3698 									windings.push_back(WINDING_CW); break;
3699 		default: DE_ASSERT(false);
3700 	}
3701 
3702 	checkTessellationSupport(m_context);
3703 	checkRenderTargetSize(m_context.getRenderTarget(), RENDER_SIZE);
3704 
3705 	for (int constantExprCaseNdx = 0; constantExprCaseNdx < numDifferentConstantExprCases; constantExprCaseNdx++)
3706 	{
3707 		for (int windingCaseNdx = 0; windingCaseNdx < (int)windings.size(); windingCaseNdx++)
3708 		{
3709 			const string	floatLit01 = de::floatToString(10.0f / (float)(constantExprCaseNdx + 10), 2);
3710 			const int		programNdx = (int)m_programs.size();
3711 
3712 			std::string vertexShaderTemplate			("${GLSL_VERSION_DECL}\n"
3713 															 "${GLSL_PER_VERTEX_OUT}\n"
3714 															 "\n"
3715 															 "in highp float in_v_attr;\n"
3716 															 "out highp float in_tc_attr;\n"
3717 															 "\n"
3718 															 "void main (void)\n"
3719 															 "{\n"
3720 															 "	in_tc_attr = in_v_attr;\n"
3721 														 "}\n");
3722 			std::string tessellationControlTemplate		("${GLSL_VERSION_DECL}\n"
3723 														 "${TESSELLATION_SHADER_REQUIRE}\n"
3724 															 "${GLSL_PER_VERTEX_IN_ARR}\n"
3725 															 "${GLSL_PER_VERTEX_OUT_ARR}\n"
3726 															 "\n"
3727 															 "layout (vertices = " + de::toString(constantExprCaseNdx+1) + ") out;\n"
3728 															 "\n"
3729 															 "in highp float in_tc_attr[];\n"
3730 															 "\n"
3731 															 "patch out highp float in_te_positionOffset;\n"
3732 															 "\n"
3733 															 "void main (void)\n"
3734 															 "{\n"
3735 															 "	in_te_positionOffset = in_tc_attr[6];\n"
3736 															 "\n"
3737 															 "	gl_TessLevelInner[0] = in_tc_attr[0];\n"
3738 															 "	gl_TessLevelInner[1] = in_tc_attr[1];\n"
3739 															 "\n"
3740 															 "	gl_TessLevelOuter[0] = in_tc_attr[2];\n"
3741 															 "	gl_TessLevelOuter[1] = in_tc_attr[3];\n"
3742 															 "	gl_TessLevelOuter[2] = in_tc_attr[4];\n"
3743 															 "	gl_TessLevelOuter[3] = in_tc_attr[5];\n"
3744 														 "}\n");
3745 			std::string tessellationEvaluationTemplate	("${GLSL_VERSION_DECL}\n"
3746 														 "${TESSELLATION_SHADER_REQUIRE}\n"
3747 															 "${GLSL_PER_VERTEX_IN_ARR}\n"
3748 															 "${GLSL_PER_VERTEX_OUT}\n"
3749 															 "\n"
3750 															 + getTessellationEvaluationInLayoutString(m_primitiveType, m_spacing, windings[windingCaseNdx], m_usePointMode) +
3751 															 "\n"
3752 															 "patch in highp float in_te_positionOffset;\n"
3753 															 "\n"
3754 															 "out highp vec4 in_f_color;\n"
3755 															 "invariant out highp vec3 out_te_tessCoord;\n"
3756 															 "\n"
3757 															 "void main (void)\n"
3758 															 "{\n"
3759 															 "	gl_Position = vec4(gl_TessCoord.xy*" + floatLit01 + " - in_te_positionOffset + float(gl_PrimitiveID)*0.1, 0.0, 1.0);\n"
3760 															 "	in_f_color = vec4(" + floatLit01 + ");\n"
3761 															 "	out_te_tessCoord = gl_TessCoord;\n"
3762 														 "}\n");
3763 			std::string fragmentShaderTemplate			("${GLSL_VERSION_DECL}\n"
3764 															 "\n"
3765 															 "layout (location = 0) out mediump vec4 o_color;\n"
3766 															 "\n"
3767 															 "in highp vec4 in_f_color;\n"
3768 															 "\n"
3769 															 "void main (void)\n"
3770 															 "{\n"
3771 															 "	o_color = in_f_color;\n"
3772 														 "}\n");
3773 
3774 			m_programs.push_back(Program(windings[windingCaseNdx],
3775 										 SharedPtr<const ShaderProgram>(new ShaderProgram(m_context.getRenderContext(), glu::ProgramSources()
3776 					<< glu::VertexSource					(specializeShader(m_context, vertexShaderTemplate.c_str()))
3777 					<< glu::TessellationControlSource		(specializeShader(m_context, tessellationControlTemplate.c_str()))
3778 					<< glu::TessellationEvaluationSource	(specializeShader(m_context, tessellationEvaluationTemplate.c_str()))
3779 					<< glu::FragmentSource					(specializeShader(m_context, fragmentShaderTemplate.c_str()))
3780 					<< glu::TransformFeedbackVarying		("out_te_tessCoord")
3781 					<< glu::TransformFeedbackMode			(GL_INTERLEAVED_ATTRIBS)))));
3782 
3783 			{
3784 				const tcu::ScopedLogSection section(m_testCtx.getLog(), "Program" + de::toString(programNdx), "Program " + de::toString(programNdx));
3785 
3786 				if (programNdx == 0 || !m_programs.back().program->isOk())
3787 					m_testCtx.getLog() << *m_programs.back().program;
3788 
3789 				if (!m_programs.back().program->isOk())
3790 					TCU_FAIL("Program compilation failed");
3791 
3792 				if (programNdx > 0)
3793 					m_testCtx.getLog() << TestLog::Message << "Note: program " << programNdx << " is similar to above, except some constants are different, and: " << m_programs.back().description() << TestLog::EndMessage;
3794 			}
3795 		}
3796 	}
3797 }
3798 
deinit(void)3799 void PrimitiveSetInvarianceCase::deinit (void)
3800 {
3801 	m_programs.clear();
3802 }
3803 
iterate(void)3804 PrimitiveSetInvarianceCase::IterateResult PrimitiveSetInvarianceCase::iterate (void)
3805 {
3806 	typedef TransformFeedbackHandler<Vec3> TFHandler;
3807 
3808 	TestLog&					log					= m_testCtx.getLog();
3809 	const RenderContext&		renderCtx			= m_context.getRenderContext();
3810 	const RandomViewport		viewport			(renderCtx.getRenderTarget(), RENDER_SIZE, RENDER_SIZE, deStringHash(getName()));
3811 	const glw::Functions&		gl					= renderCtx.getFunctions();
3812 	const vector<LevelCase>		tessLevelCases		= genTessLevelCases();
3813 	vector<vector<int> >		primitiveCounts;
3814 	int							maxNumPrimitives	= -1;
3815 
3816 	for (int caseNdx = 0; caseNdx < (int)tessLevelCases.size(); caseNdx++)
3817 	{
3818 		primitiveCounts.push_back(vector<int>());
3819 		for (int i = 0; i < (int)tessLevelCases[caseNdx].levels.size(); i++)
3820 		{
3821 			const int primCount = referencePrimitiveCount(m_primitiveType, m_spacing, m_usePointMode,
3822 														  &tessLevelCases[caseNdx].levels[i].inner[0], &tessLevelCases[caseNdx].levels[i].outer[0]);
3823 			primitiveCounts.back().push_back(primCount);
3824 			maxNumPrimitives = de::max(maxNumPrimitives, primCount);
3825 		}
3826 	}
3827 
3828 	const deUint32				primitiveTypeGL		= outputPrimitiveTypeGL(m_primitiveType, m_usePointMode);
3829 	const TFHandler				transformFeedback	(m_context.getRenderContext(), 2*maxNumPrimitives*numVerticesPerPrimitive(primitiveTypeGL));
3830 
3831 	setViewport(gl, viewport);
3832 	gl.patchParameteri(GL_PATCH_VERTICES, 7);
3833 
3834 	for (int tessLevelCaseNdx = 0; tessLevelCaseNdx < (int)tessLevelCases.size(); tessLevelCaseNdx++)
3835 	{
3836 		const LevelCase&	levelCase = tessLevelCases[tessLevelCaseNdx];
3837 		vector<Vec3>		firstPrimVertices;
3838 
3839 		{
3840 			string tessLevelsStr;
3841 			for (int i = 0; i < (int)levelCase.levels.size(); i++)
3842 				tessLevelsStr += (levelCase.levels.size() > 1 ? "\n" : "") + levelCase.levels[i].description();
3843 			log << TestLog::Message << "Tessellation level sets: " << tessLevelsStr << TestLog::EndMessage;
3844 		}
3845 
3846 		for (int subTessLevelCaseNdx = 0; subTessLevelCaseNdx < (int)levelCase.levels.size(); subTessLevelCaseNdx++)
3847 		{
3848 			const TessLevels&				tessLevels		= levelCase.levels[subTessLevelCaseNdx];
3849 			const float						(&inner)[2]		= tessLevels.inner;
3850 			const float						(&outer)[4]		= tessLevels.outer;
3851 			const float						attribute[2*7]	= { inner[0], inner[1], outer[0], outer[1], outer[2], outer[3], 0.0f,
3852 																inner[0], inner[1], outer[0], outer[1], outer[2], outer[3], 0.5f };
3853 			const glu::VertexArrayBinding	bindings[]		= { glu::va::Float("in_v_attr", 1, DE_LENGTH_OF_ARRAY(attribute), 0, &attribute[0]) };
3854 
3855 			for (int programNdx = 0; programNdx < (int)m_programs.size(); programNdx++)
3856 			{
3857 				const deUint32				programGL	= m_programs[programNdx].program->getProgram();
3858 				gl.useProgram(programGL);
3859 				const TFHandler::Result		tfResult	= transformFeedback.renderAndGetPrimitives(programGL, primitiveTypeGL, DE_LENGTH_OF_ARRAY(bindings), &bindings[0], DE_LENGTH_OF_ARRAY(attribute));
3860 
3861 				if (tfResult.numPrimitives != 2*primitiveCounts[tessLevelCaseNdx][subTessLevelCaseNdx])
3862 				{
3863 					log << TestLog::Message << "Failure: GL reported GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN to be "
3864 											<< tfResult.numPrimitives << ", reference value is " << 2*primitiveCounts[tessLevelCaseNdx][subTessLevelCaseNdx]
3865 											<< TestLog::EndMessage;
3866 
3867 					m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid set of primitives");
3868 					return STOP;
3869 				}
3870 
3871 				{
3872 					const int			half			= (int)tfResult.varying.size()/2;
3873 					const vector<Vec3>	prim0Vertices	= vector<Vec3>(tfResult.varying.begin(), tfResult.varying.begin() + half);
3874 					const Vec3* const	prim1Vertices	= &tfResult.varying[half];
3875 
3876 					for (int vtxNdx = 0; vtxNdx < (int)prim0Vertices.size(); vtxNdx++)
3877 					{
3878 						if (prim0Vertices[vtxNdx] != prim1Vertices[vtxNdx])
3879 						{
3880 							log << TestLog::Message << "Failure: tessellation coordinate at index " << vtxNdx << " differs between two primitives drawn in one draw call" << TestLog::EndMessage
3881 								<< TestLog::Message << "Note: the coordinate is " << prim0Vertices[vtxNdx] << " for the first primitive and " << prim1Vertices[vtxNdx] << " for the second" << TestLog::EndMessage
3882 								<< TestLog::Message << "Note: tessellation levels for both primitives were: " << tessellationLevelsString(&inner[0], &outer[0]) << TestLog::EndMessage;
3883 							m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid set of primitives");
3884 							return STOP;
3885 						}
3886 					}
3887 
3888 					if (programNdx == 0 && subTessLevelCaseNdx == 0)
3889 						firstPrimVertices = prim0Vertices;
3890 					else
3891 					{
3892 						const bool compareOk = compare(firstPrimVertices, prim0Vertices, levelCase.mem);
3893 						if (!compareOk)
3894 						{
3895 							log << TestLog::Message << "Note: comparison of tessellation coordinates failed; comparison was made between following cases:\n"
3896 													<< "  - case A: program 0, tessellation levels: " << tessLevelCases[tessLevelCaseNdx].levels[0].description() << "\n"
3897 													<< "  - case B: program " << programNdx << ", tessellation levels: " << tessLevels.description() << TestLog::EndMessage;
3898 							m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid set of primitives");
3899 							return STOP;
3900 						}
3901 					}
3902 				}
3903 			}
3904 		}
3905 	}
3906 
3907 	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
3908 	return STOP;
3909 }
3910 
3911 /*--------------------------------------------------------------------*//*!
3912  * \brief Test invariance rule #1
3913  *
3914  * Test that the sequence of primitives input to the TES only depends on
3915  * the tessellation levels, tessellation mode, spacing mode, winding, and
3916  * point mode.
3917  *//*--------------------------------------------------------------------*/
3918 class InvariantPrimitiveSetCase : public PrimitiveSetInvarianceCase
3919 {
3920 public:
InvariantPrimitiveSetCase(Context & context,const char * name,const char * description,TessPrimitiveType primType,SpacingMode spacing,Winding winding,bool usePointMode)3921 	InvariantPrimitiveSetCase (Context& context, const char* name, const char* description, TessPrimitiveType primType, SpacingMode spacing, Winding winding, bool usePointMode)
3922 		: PrimitiveSetInvarianceCase(context, name, description, primType, spacing, usePointMode, winding == WINDING_CCW	? WINDINGUSAGE_CCW
3923 																								: winding == WINDING_CW		? WINDINGUSAGE_CW
3924 																								: WINDINGUSAGE_LAST)
3925 	{
3926 	}
3927 
3928 protected:
compare(const vector<Vec3> & coordsA,const vector<Vec3> & coordsB,int) const3929 	virtual bool compare (const vector<Vec3>& coordsA, const vector<Vec3>& coordsB, int) const
3930 	{
3931 		for (int vtxNdx = 0; vtxNdx < (int)coordsA.size(); vtxNdx++)
3932 		{
3933 			if (coordsA[vtxNdx] != coordsB[vtxNdx])
3934 			{
3935 				m_testCtx.getLog() << TestLog::Message << "Failure: tessellation coordinate at index " << vtxNdx << " differs between two programs" << TestLog::EndMessage
3936 								   << TestLog::Message << "Note: the coordinate is " << coordsA[vtxNdx] << " for the first program and " << coordsB[vtxNdx] << " for the other" << TestLog::EndMessage;
3937 				return false;
3938 			}
3939 		}
3940 		return true;
3941 	}
3942 };
3943 
3944 /*--------------------------------------------------------------------*//*!
3945  * \brief Test invariance rule #2
3946  *
3947  * Test that the set of vertices along an outer edge of a quad or triangle
3948  * only depends on that edge's tessellation level, and spacing.
3949  *
3950  * For each (outer) edge in the quad or triangle, draw multiple patches
3951  * with identical tessellation levels for that outer edge but with
3952  * different values for the other outer edges; compare, among the
3953  * primitives, the vertices generated for that outer edge. Repeat with
3954  * different programs, using different winding etc. settings. Compare
3955  * the edge's vertices between different programs.
3956  *//*--------------------------------------------------------------------*/
3957 class InvariantOuterEdgeCase : public TestCase
3958 {
3959 public:
InvariantOuterEdgeCase(Context & context,const char * name,const char * description,TessPrimitiveType primType,SpacingMode spacing)3960 	InvariantOuterEdgeCase (Context& context, const char* name, const char* description, TessPrimitiveType primType, SpacingMode spacing)
3961 		: TestCase			(context, name, description)
3962 		, m_primitiveType	(primType)
3963 		, m_spacing			(spacing)
3964 	{
3965 		DE_ASSERT(primType == TESSPRIMITIVETYPE_TRIANGLES || primType == TESSPRIMITIVETYPE_QUADS);
3966 	}
3967 
3968 	void						init		(void);
3969 	void						deinit		(void);
3970 	IterateResult				iterate		(void);
3971 
3972 private:
3973 	struct Program
3974 	{
3975 		Winding							winding;
3976 		bool							usePointMode;
3977 		SharedPtr<const ShaderProgram>	program;
3978 
Programdeqp::gles31::Functional::__anon755cd4500211::InvariantOuterEdgeCase::Program3979 				Program			(Winding w, bool point, const SharedPtr<const ShaderProgram>& prog) : winding(w), usePointMode(point), program(prog) {}
3980 
descriptiondeqp::gles31::Functional::__anon755cd4500211::InvariantOuterEdgeCase::Program3981 		string	description		(void) const { return string() + "winding mode " + getWindingShaderName(winding) + ", " + (usePointMode ? "" : "don't ") + "use point mode"; }
3982 	};
3983 
3984 	static vector<float>		generatePatchTessLevels (int numPatches, int constantOuterLevelIndex, float constantOuterLevel);
3985 
3986 	static const int			RENDER_SIZE = 16;
3987 
3988 	const TessPrimitiveType		m_primitiveType;
3989 	const SpacingMode			m_spacing;
3990 
3991 	vector<Program>				m_programs;
3992 };
3993 
generatePatchTessLevels(int numPatches,int constantOuterLevelIndex,float constantOuterLevel)3994 vector<float> InvariantOuterEdgeCase::generatePatchTessLevels (int numPatches, int constantOuterLevelIndex, float constantOuterLevel)
3995 {
3996 	de::Random rnd(123);
3997 	return generateRandomPatchTessLevels(numPatches, constantOuterLevelIndex, constantOuterLevel, rnd);
3998 }
3999 
init(void)4000 void InvariantOuterEdgeCase::init (void)
4001 {
4002 	checkTessellationSupport(m_context);
4003 	checkRenderTargetSize(m_context.getRenderTarget(), RENDER_SIZE);
4004 
4005 	for (int windingI = 0; windingI < WINDING_LAST; windingI++)
4006 	{
4007 		const Winding winding = (Winding)windingI;
4008 
4009 		for (int usePointModeI = 0; usePointModeI <= 1; usePointModeI++)
4010 		{
4011 			const bool		usePointMode	= usePointModeI != 0;
4012 			const int		programNdx		= (int)m_programs.size();
4013 			const string	floatLit01		= de::floatToString(10.0f / (float)(programNdx + 10), 2);
4014 
4015 			std::string vertexShaderTemplate			("${GLSL_VERSION_DECL}\n"
4016 														 "${GLSL_PER_VERTEX_OUT}\n"
4017 														 "\n"
4018 														 "in highp float in_v_attr;\n"
4019 														 "out highp float in_tc_attr;\n"
4020 														 "\n"
4021 														 "void main (void)\n"
4022 														 "{\n"
4023 														 "	in_tc_attr = in_v_attr;\n"
4024 														 "}\n");
4025 			std::string tessellationControlTemplate		("${GLSL_VERSION_DECL}\n"
4026 														 "${TESSELLATION_SHADER_REQUIRE}\n"
4027 														 "${GLSL_PER_VERTEX_IN_ARR}\n"
4028 														 "${GLSL_PER_VERTEX_OUT_ARR}\n"
4029 														 "\n"
4030 														 "layout (vertices = " + de::toString(programNdx+1) + ") out;\n"
4031 														 "\n"
4032 														 "in highp float in_tc_attr[];\n"
4033 														 "\n"
4034 														 "void main (void)\n"
4035 														 "{\n"
4036 														 "	gl_TessLevelInner[0] = in_tc_attr[0];\n"
4037 														 "	gl_TessLevelInner[1] = in_tc_attr[1];\n"
4038 														 "\n"
4039 														 "	gl_TessLevelOuter[0] = in_tc_attr[2];\n"
4040 														 "	gl_TessLevelOuter[1] = in_tc_attr[3];\n"
4041 														 "	gl_TessLevelOuter[2] = in_tc_attr[4];\n"
4042 														 "	gl_TessLevelOuter[3] = in_tc_attr[5];\n"
4043 														 "}\n");
4044 			std::string tessellationEvaluationTemplate	("${GLSL_VERSION_DECL}\n"
4045 														 "${TESSELLATION_SHADER_REQUIRE}\n"
4046 														 "${GLSL_PER_VERTEX_IN_ARR}\n"
4047 														 "${GLSL_PER_VERTEX_OUT}\n"
4048 														 "\n"
4049 														 + getTessellationEvaluationInLayoutString(m_primitiveType, m_spacing, winding, usePointMode) +
4050 														 "\n"
4051 														 "out highp vec4 in_f_color;\n"
4052 														 "invariant out highp vec3 out_te_tessCoord;\n"
4053 														 "\n"
4054 														 "void main (void)\n"
4055 														 "{\n"
4056 														 "	gl_Position = vec4(gl_TessCoord.xy*" + floatLit01 + " - float(gl_PrimitiveID)*0.05, 0.0, 1.0);\n"
4057 														 "	in_f_color = vec4(" + floatLit01 + ");\n"
4058 														 "	out_te_tessCoord = gl_TessCoord;\n"
4059 														 "}\n");
4060 			std::string fragmentShaderTemplate			("${GLSL_VERSION_DECL}\n"
4061 														 "\n"
4062 														 "layout (location = 0) out mediump vec4 o_color;\n"
4063 														 "\n"
4064 														 "in highp vec4 in_f_color;\n"
4065 														 "\n"
4066 														 "void main (void)\n"
4067 														 "{\n"
4068 														 "	o_color = in_f_color;\n"
4069 														 "}\n");
4070 
4071 			m_programs.push_back(Program(winding, usePointMode,
4072 										 SharedPtr<const ShaderProgram>(new ShaderProgram(m_context.getRenderContext(), glu::ProgramSources()
4073 				<< glu::VertexSource					(specializeShader(m_context, vertexShaderTemplate.c_str()))
4074 				<< glu::TessellationControlSource		(specializeShader(m_context, tessellationControlTemplate.c_str()))
4075 				<< glu::TessellationEvaluationSource	(specializeShader(m_context, tessellationEvaluationTemplate.c_str()))
4076 				<< glu::FragmentSource					(specializeShader(m_context, fragmentShaderTemplate.c_str()))
4077 				<< glu::TransformFeedbackVarying		("out_te_tessCoord")
4078 				<< glu::TransformFeedbackMode			(GL_INTERLEAVED_ATTRIBS)))));
4079 
4080 			{
4081 				const tcu::ScopedLogSection section(m_testCtx.getLog(), "Program" + de::toString(programNdx), "Program " + de::toString(programNdx));
4082 
4083 				if (programNdx == 0 || !m_programs.back().program->isOk())
4084 					m_testCtx.getLog() << *m_programs.back().program;
4085 
4086 				if (!m_programs.back().program->isOk())
4087 					TCU_FAIL("Program compilation failed");
4088 
4089 				if (programNdx > 0)
4090 					m_testCtx.getLog() << TestLog::Message << "Note: program " << programNdx << " is similar to above, except some constants are different, and: " << m_programs.back().description() << TestLog::EndMessage;
4091 			}
4092 		}
4093 	}
4094 }
4095 
deinit(void)4096 void InvariantOuterEdgeCase::deinit (void)
4097 {
4098 	m_programs.clear();
4099 }
4100 
iterate(void)4101 InvariantOuterEdgeCase::IterateResult InvariantOuterEdgeCase::iterate (void)
4102 {
4103 	typedef TransformFeedbackHandler<Vec3> TFHandler;
4104 
4105 	TestLog&							log							= m_testCtx.getLog();
4106 	const RenderContext&				renderCtx					= m_context.getRenderContext();
4107 	const RandomViewport				viewport					(renderCtx.getRenderTarget(), RENDER_SIZE, RENDER_SIZE, deStringHash(getName()));
4108 	const glw::Functions&				gl							= renderCtx.getFunctions();
4109 
4110 	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 };
4111 	const int							numPatchesPerDrawCall		= 10;
4112 	const vector<OuterEdgeDescription>	edgeDescriptions			= outerEdgeDescriptions(m_primitiveType);
4113 
4114 	{
4115 		// Compute the number vertices in the largest draw call, so we can allocate the TF buffer just once.
4116 		int maxNumVerticesInDrawCall = 0;
4117 		{
4118 			const vector<float> patchTessLevels = generatePatchTessLevels(numPatchesPerDrawCall, 0 /* outer-edge index doesn't affect vertex count */, arrayMax(singleOuterEdgeLevels));
4119 
4120 			for (int usePointModeI = 0; usePointModeI <= 1; usePointModeI++)
4121 				maxNumVerticesInDrawCall = de::max(maxNumVerticesInDrawCall,
4122 												   multiplePatchReferenceVertexCount(m_primitiveType, m_spacing, usePointModeI != 0, &patchTessLevels[0], numPatchesPerDrawCall));
4123 		}
4124 
4125 		{
4126 			const TFHandler tfHandler(m_context.getRenderContext(), maxNumVerticesInDrawCall);
4127 
4128 			setViewport(gl, viewport);
4129 			gl.patchParameteri(GL_PATCH_VERTICES, 6);
4130 
4131 			for (int outerEdgeIndex = 0; outerEdgeIndex < (int)edgeDescriptions.size(); outerEdgeIndex++)
4132 			{
4133 				const OuterEdgeDescription& edgeDesc = edgeDescriptions[outerEdgeIndex];
4134 
4135 				for (int outerEdgeLevelCaseNdx = 0; outerEdgeLevelCaseNdx < DE_LENGTH_OF_ARRAY(singleOuterEdgeLevels); outerEdgeLevelCaseNdx++)
4136 				{
4137 					typedef std::set<Vec3, VecLexLessThan<3> > Vec3Set;
4138 
4139 					const vector<float>				patchTessLevels		= generatePatchTessLevels(numPatchesPerDrawCall, outerEdgeIndex, singleOuterEdgeLevels[outerEdgeLevelCaseNdx]);
4140 					const glu::VertexArrayBinding	bindings[]			= { glu::va::Float("in_v_attr", 1, (int)patchTessLevels.size(), 0, &patchTessLevels[0]) };
4141 					Vec3Set							firstOuterEdgeVertices; // Vertices of the outer edge of the first patch of the first program's draw call; used for comparison with other patches.
4142 
4143 					log << TestLog::Message << "Testing with outer tessellation level " << singleOuterEdgeLevels[outerEdgeLevelCaseNdx]
4144 											<< " for the " << edgeDesc.description() << " edge, and with various levels for other edges, and with all programs" << TestLog::EndMessage;
4145 
4146 					for (int programNdx = 0; programNdx < (int)m_programs.size(); programNdx++)
4147 					{
4148 						const Program& program		= m_programs[programNdx];
4149 						const deUint32 programGL	= program.program->getProgram();
4150 
4151 						gl.useProgram(programGL);
4152 
4153 						{
4154 							const TFHandler::Result		tfResult			= tfHandler.renderAndGetPrimitives(programGL, outputPrimitiveTypeGL(m_primitiveType, program.usePointMode),
4155 																											   DE_LENGTH_OF_ARRAY(bindings), &bindings[0], (int)patchTessLevels.size());
4156 							const int					refNumVertices		= multiplePatchReferenceVertexCount(m_primitiveType, m_spacing, program.usePointMode, &patchTessLevels[0], numPatchesPerDrawCall);
4157 							int							numVerticesRead		= 0;
4158 
4159 							if ((int)tfResult.varying.size() != refNumVertices)
4160 							{
4161 								log << TestLog::Message << "Failure: the number of vertices returned by transform feedback is "
4162 														<< tfResult.varying.size() << ", expected " << refNumVertices << TestLog::EndMessage
4163 									<< TestLog::Message << "Note: rendered " << numPatchesPerDrawCall
4164 														<< " patches in one draw call; tessellation levels for each patch are (in order [inner0, inner1, outer0, outer1, outer2, outer3]):\n"
4165 														<< containerStr(patchTessLevels, 6) << TestLog::EndMessage;
4166 
4167 								m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid set of vertices");
4168 								return STOP;
4169 							}
4170 
4171 							// Check the vertices of each patch.
4172 
4173 							for (int patchNdx = 0; patchNdx < numPatchesPerDrawCall; patchNdx++)
4174 							{
4175 								const float* const	innerLevels			= &patchTessLevels[6*patchNdx + 0];
4176 								const float* const	outerLevels			= &patchTessLevels[6*patchNdx + 2];
4177 								const int			patchNumVertices	= referenceVertexCount(m_primitiveType, m_spacing, program.usePointMode, innerLevels, outerLevels);
4178 								Vec3Set				outerEdgeVertices;
4179 
4180 								// We're interested in just the vertices on the current outer edge.
4181 								for(int vtxNdx = numVerticesRead; vtxNdx < numVerticesRead + patchNumVertices; vtxNdx++)
4182 								{
4183 									const Vec3& vtx = tfResult.varying[vtxNdx];
4184 									if (edgeDesc.contains(vtx))
4185 										outerEdgeVertices.insert(tfResult.varying[vtxNdx]);
4186 								}
4187 
4188 								// Check that the outer edge contains an appropriate number of vertices.
4189 								{
4190 									const int refNumVerticesOnOuterEdge = 1 + getClampedRoundedTessLevel(m_spacing, singleOuterEdgeLevels[outerEdgeLevelCaseNdx]);
4191 
4192 									if ((int)outerEdgeVertices.size() != refNumVerticesOnOuterEdge)
4193 									{
4194 										log << TestLog::Message << "Failure: the number of vertices on outer edge is " << outerEdgeVertices.size()
4195 																<< ", expected " << refNumVerticesOnOuterEdge << TestLog::EndMessage
4196 											<< TestLog::Message << "Note: vertices on the outer edge are:\n" << containerStr(outerEdgeVertices, 5, 0) << TestLog::EndMessage
4197 											<< TestLog::Message << "Note: the following parameters were used: " << program.description()
4198 																<< ", tessellation levels: " << tessellationLevelsString(innerLevels, outerLevels) << TestLog::EndMessage;
4199 										m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid set of vertices");
4200 										return STOP;
4201 									}
4202 								}
4203 
4204 								// Compare the vertices to those of the first patch (unless this is the first patch).
4205 
4206 								if (programNdx == 0 && patchNdx == 0)
4207 									firstOuterEdgeVertices = outerEdgeVertices;
4208 								else
4209 								{
4210 									if (firstOuterEdgeVertices != outerEdgeVertices)
4211 									{
4212 										log << TestLog::Message << "Failure: vertices generated for the edge differ between the following cases:\n"
4213 																<< "  - case A: " << m_programs[0].description() << ", tessellation levels: "
4214 																				  << tessellationLevelsString(&patchTessLevels[0], &patchTessLevels[2]) << "\n"
4215 																<< "  - case B: " << program.description() << ", tessellation levels: "
4216 																				  << tessellationLevelsString(innerLevels, outerLevels) << TestLog::EndMessage;
4217 
4218 										log << TestLog::Message << "Note: resulting vertices for the edge for the cases were:\n"
4219 																<< "  - case A: " << containerStr(firstOuterEdgeVertices, 5, 14) << "\n"
4220 																<< "  - case B: " << containerStr(outerEdgeVertices, 5, 14) << TestLog::EndMessage;
4221 
4222 										m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid set of vertices");
4223 										return STOP;
4224 									}
4225 								}
4226 
4227 								numVerticesRead += patchNumVertices;
4228 							}
4229 
4230 							DE_ASSERT(numVerticesRead == (int)tfResult.varying.size());
4231 						}
4232 					}
4233 				}
4234 			}
4235 		}
4236 	}
4237 
4238 	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
4239 	return STOP;
4240 }
4241 
4242 /*--------------------------------------------------------------------*//*!
4243  * \brief Test invariance rule #3
4244  *
4245  * Test that the vertices along an outer edge are placed symmetrically.
4246  *
4247  * Draw multiple patches with different tessellation levels and different
4248  * point_mode, winding etc. Before outputting tesscoords with TF, mirror
4249  * the vertices in the TES such that every vertex on an outer edge -
4250  * except the possible middle vertex - should be duplicated in the output.
4251  * Check that appropriate duplicates exist.
4252  *//*--------------------------------------------------------------------*/
4253 class SymmetricOuterEdgeCase : public TestCase
4254 {
4255 public:
SymmetricOuterEdgeCase(Context & context,const char * name,const char * description,TessPrimitiveType primType,SpacingMode spacing,Winding winding,bool usePointMode)4256 	SymmetricOuterEdgeCase (Context& context, const char* name, const char* description, TessPrimitiveType primType, SpacingMode spacing, Winding winding, bool usePointMode)
4257 		: TestCase			(context, name, description)
4258 		, m_primitiveType	(primType)
4259 		, m_spacing			(spacing)
4260 		, m_winding			(winding)
4261 		, m_usePointMode	(usePointMode)
4262 	{
4263 	}
4264 
4265 	void									init		(void);
4266 	void									deinit		(void);
4267 	IterateResult							iterate		(void);
4268 
4269 private:
4270 	static vector<float>					generatePatchTessLevels (int numPatches, int constantOuterLevelIndex, float constantOuterLevel);
4271 
4272 	static const int						RENDER_SIZE = 16;
4273 
4274 	const TessPrimitiveType					m_primitiveType;
4275 	const SpacingMode						m_spacing;
4276 	const Winding							m_winding;
4277 	const bool								m_usePointMode;
4278 
4279 	SharedPtr<const glu::ShaderProgram>		m_program;
4280 };
4281 
generatePatchTessLevels(int numPatches,int constantOuterLevelIndex,float constantOuterLevel)4282 vector<float> SymmetricOuterEdgeCase::generatePatchTessLevels (int numPatches, int constantOuterLevelIndex, float constantOuterLevel)
4283 {
4284 	de::Random rnd(123);
4285 	return generateRandomPatchTessLevels(numPatches, constantOuterLevelIndex, constantOuterLevel, rnd);
4286 }
4287 
init(void)4288 void SymmetricOuterEdgeCase::init (void)
4289 {
4290 	checkTessellationSupport(m_context);
4291 	checkRenderTargetSize(m_context.getRenderTarget(), RENDER_SIZE);
4292 
4293 	std::string vertexShaderTemplate			("${GLSL_VERSION_DECL}\n"
4294 												 "\n"
4295 												 "${GLSL_PER_VERTEX_OUT}\n"
4296 												 "in highp float in_v_attr;\n"
4297 												 "out highp float in_tc_attr;\n"
4298 												 "\n"
4299 												 "void main (void)\n"
4300 												 "{\n"
4301 												 "	in_tc_attr = in_v_attr;\n"
4302 												 "}\n");
4303 	std::string tessellationControlTemplate		("${GLSL_VERSION_DECL}\n"
4304 												 "${TESSELLATION_SHADER_REQUIRE}\n"
4305 												 "${GLSL_PER_VERTEX_IN_ARR}\n"
4306 												 "${GLSL_PER_VERTEX_OUT_ARR}\n"
4307 												 "\n"
4308 												 "layout (vertices = 1) out;\n"
4309 												 "\n"
4310 												 "in highp float in_tc_attr[];\n"
4311 												 "\n"
4312 												 "void main (void)\n"
4313 												 "{\n"
4314 												 "	gl_TessLevelInner[0] = in_tc_attr[0];\n"
4315 												 "	gl_TessLevelInner[1] = in_tc_attr[1];\n"
4316 												 "\n"
4317 												 "	gl_TessLevelOuter[0] = in_tc_attr[2];\n"
4318 												 "	gl_TessLevelOuter[1] = in_tc_attr[3];\n"
4319 												 "	gl_TessLevelOuter[2] = in_tc_attr[4];\n"
4320 												 "	gl_TessLevelOuter[3] = in_tc_attr[5];\n"
4321 												 "}\n");
4322 	std::string tessellationEvaluationTemplate	("${GLSL_VERSION_DECL}\n"
4323 												 "${TESSELLATION_SHADER_REQUIRE}\n"
4324 												 "${GLSL_PER_VERTEX_IN_ARR}\n"
4325 												 "${GLSL_PER_VERTEX_OUT}\n"
4326 												 "\n"
4327 												 + getTessellationEvaluationInLayoutString(m_primitiveType, m_spacing, m_winding, m_usePointMode) +
4328 												 "\n"
4329 												 "out highp vec4 in_f_color;\n"
4330 												 "out highp vec4 out_te_tessCoord_isMirrored;\n"
4331 												 "\n"
4332 												 "void main (void)\n"
4333 												 "{\n"
4334 												 + (m_primitiveType == TESSPRIMITIVETYPE_TRIANGLES ?
4335 													"	float x = gl_TessCoord.x;\n"
4336 													"	float y = gl_TessCoord.y;\n"
4337 													"	float z = gl_TessCoord.z;\n"
4338 													"	// Mirror one half of each outer edge onto the other half, except the endpoints (because they belong to two edges)\n"
4339 													"	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"
4340 													"	                            : y == 0.0 && z > 0.5 && z != 1.0 ? vec4(1.0-x,    0.0,  1.0-z, 1.0)\n"
4341 													"	                            : x == 0.0 && y > 0.5 && y != 1.0 ? vec4(  0.0,  1.0-y,  1.0-z, 1.0)\n"
4342 													"	                            : vec4(x, y, z, 0.0);\n"
4343 												  : m_primitiveType == TESSPRIMITIVETYPE_QUADS ?
4344 													"	float x = gl_TessCoord.x;\n"
4345 													"	float y = gl_TessCoord.y;\n"
4346 													"	// Mirror one half of each outer edge onto the other half, except the endpoints (because they belong to two edges)\n"
4347 													"	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"
4348 													"	                            : (y == 0.0 || y == 1.0) && x > 0.5 && x != 1.0 ? vec4(1.0-x,     y, 0.0, 1.0)\n"
4349 													"	                            : vec4(x, y, 0.0, 0.0);\n"
4350 												  : m_primitiveType == TESSPRIMITIVETYPE_ISOLINES ?
4351 													"	float x = gl_TessCoord.x;\n"
4352 													"	float y = gl_TessCoord.y;\n"
4353 													"	// Mirror one half of each outer edge onto the other half\n"
4354 													"	out_te_tessCoord_isMirrored = (x == 0.0 || x == 1.0) && y > 0.5 ? vec4(x, 1.0-y, 0.0, 1.0)\n"
4355 													"	                            : vec4(x, y, 0.0, 0.0f);\n"
4356 												  : DE_NULL) +
4357 												 "\n"
4358 												 "	gl_Position = vec4(gl_TessCoord.xy, 0.0, 1.0);\n"
4359 												 "	in_f_color = vec4(1.0);\n"
4360 												 "}\n");
4361 	std::string fragmentShaderTemplate			("${GLSL_VERSION_DECL}\n"
4362 												 "\n"
4363 												 "layout (location = 0) out mediump vec4 o_color;\n"
4364 												 "\n"
4365 												 "in highp vec4 in_f_color;\n"
4366 												 "\n"
4367 												 "void main (void)\n"
4368 												 "{\n"
4369 												 "	o_color = in_f_color;\n"
4370 												 "}\n");
4371 
4372 	m_program = SharedPtr<const ShaderProgram>(new ShaderProgram(m_context.getRenderContext(), glu::ProgramSources()
4373 		<< glu::VertexSource					(specializeShader(m_context, vertexShaderTemplate.c_str()))
4374 		<< glu::TessellationControlSource		(specializeShader(m_context, tessellationControlTemplate.c_str()))
4375 		<< glu::TessellationEvaluationSource	(specializeShader(m_context, tessellationEvaluationTemplate.c_str()))
4376 		<< glu::FragmentSource					(specializeShader(m_context, fragmentShaderTemplate.c_str()))
4377 		<< glu::TransformFeedbackVarying		("out_te_tessCoord_isMirrored")
4378 		<< glu::TransformFeedbackMode			(GL_INTERLEAVED_ATTRIBS)));
4379 
4380 	m_testCtx.getLog() << *m_program;
4381 	if (!m_program->isOk())
4382 		TCU_FAIL("Program compilation failed");
4383 }
4384 
deinit(void)4385 void SymmetricOuterEdgeCase::deinit (void)
4386 {
4387 	m_program.clear();
4388 }
4389 
iterate(void)4390 SymmetricOuterEdgeCase::IterateResult SymmetricOuterEdgeCase::iterate (void)
4391 {
4392 	typedef TransformFeedbackHandler<Vec4> TFHandler;
4393 
4394 	TestLog&							log							= m_testCtx.getLog();
4395 	const RenderContext&				renderCtx					= m_context.getRenderContext();
4396 	const RandomViewport				viewport					(renderCtx.getRenderTarget(), RENDER_SIZE, RENDER_SIZE, deStringHash(getName()));
4397 	const glw::Functions&				gl							= renderCtx.getFunctions();
4398 
4399 	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 };
4400 	const vector<OuterEdgeDescription>	edgeDescriptions			= outerEdgeDescriptions(m_primitiveType);
4401 
4402 	{
4403 		// Compute the number vertices in the largest draw call, so we can allocate the TF buffer just once.
4404 		int maxNumVerticesInDrawCall;
4405 		{
4406 			const vector<float> patchTessLevels = generatePatchTessLevels(1, 0 /* outer-edge index doesn't affect vertex count */, arrayMax(singleOuterEdgeLevels));
4407 			maxNumVerticesInDrawCall = referenceVertexCount(m_primitiveType, m_spacing, m_usePointMode, &patchTessLevels[0], &patchTessLevels[2]);
4408 		}
4409 
4410 		{
4411 			const TFHandler tfHandler(m_context.getRenderContext(), maxNumVerticesInDrawCall);
4412 
4413 			setViewport(gl, viewport);
4414 			gl.patchParameteri(GL_PATCH_VERTICES, 6);
4415 
4416 			for (int outerEdgeIndex = 0; outerEdgeIndex < (int)edgeDescriptions.size(); outerEdgeIndex++)
4417 			{
4418 				const OuterEdgeDescription& edgeDesc = edgeDescriptions[outerEdgeIndex];
4419 
4420 				for (int outerEdgeLevelCaseNdx = 0; outerEdgeLevelCaseNdx < DE_LENGTH_OF_ARRAY(singleOuterEdgeLevels); outerEdgeLevelCaseNdx++)
4421 				{
4422 					typedef std::set<Vec3, VecLexLessThan<3> > Vec3Set;
4423 
4424 					const vector<float>				patchTessLevels		= generatePatchTessLevels(1, outerEdgeIndex, singleOuterEdgeLevels[outerEdgeLevelCaseNdx]);
4425 					const glu::VertexArrayBinding	bindings[]			= { glu::va::Float("in_v_attr", 1, (int)patchTessLevels.size(), 0, &patchTessLevels[0]) };
4426 
4427 					log << TestLog::Message << "Testing with outer tessellation level " << singleOuterEdgeLevels[outerEdgeLevelCaseNdx]
4428 											<< " for the " << edgeDesc.description() << " edge, and with various levels for other edges" << TestLog::EndMessage;
4429 
4430 					{
4431 						const deUint32 programGL = m_program->getProgram();
4432 
4433 						gl.useProgram(programGL);
4434 
4435 						{
4436 							const TFHandler::Result		tfResult		= tfHandler.renderAndGetPrimitives(programGL, outputPrimitiveTypeGL(m_primitiveType, m_usePointMode),
4437 																										   DE_LENGTH_OF_ARRAY(bindings), &bindings[0], (int)patchTessLevels.size());
4438 							const int					refNumVertices	= referenceVertexCount(m_primitiveType, m_spacing, m_usePointMode, &patchTessLevels[0], &patchTessLevels[2]);
4439 
4440 							if ((int)tfResult.varying.size() != refNumVertices)
4441 							{
4442 								log << TestLog::Message << "Failure: the number of vertices returned by transform feedback is "
4443 														<< tfResult.varying.size() << ", expected " << refNumVertices << TestLog::EndMessage
4444 									<< TestLog::Message << "Note: rendered 1 patch, tessellation levels are (in order [inner0, inner1, outer0, outer1, outer2, outer3]):\n"
4445 														<< containerStr(patchTessLevels, 6) << TestLog::EndMessage;
4446 
4447 								m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid set of vertices");
4448 								return STOP;
4449 							}
4450 
4451 							// Check the vertices.
4452 
4453 							{
4454 								Vec3Set nonMirroredEdgeVertices;
4455 								Vec3Set mirroredEdgeVertices;
4456 
4457 								// We're interested in just the vertices on the current outer edge.
4458 								for(int vtxNdx = 0; vtxNdx < refNumVertices; vtxNdx++)
4459 								{
4460 									const Vec3& vtx = tfResult.varying[vtxNdx].swizzle(0,1,2);
4461 									if (edgeDesc.contains(vtx))
4462 									{
4463 										// Ignore the middle vertex of the outer edge, as it's exactly at the mirroring point;
4464 										// for isolines, also ignore (0, 0) and (1, 0) because there's no mirrored counterpart for them.
4465 										if (m_primitiveType == TESSPRIMITIVETYPE_TRIANGLES && vtx == tcu::select(Vec3(0.0f), Vec3(0.5f), singleTrueMask<3>(edgeDesc.constantCoordinateIndex)))
4466 											continue;
4467 										if (m_primitiveType == TESSPRIMITIVETYPE_QUADS && vtx.swizzle(0,1) == tcu::select(Vec2(edgeDesc.constantCoordinateValueChoices[0]),
4468 																															   Vec2(0.5f),
4469 																															   singleTrueMask<2>(edgeDesc.constantCoordinateIndex)))
4470 											continue;
4471 										if (m_primitiveType == TESSPRIMITIVETYPE_ISOLINES && (vtx == Vec3(0.0f, 0.5f, 0.0f) || vtx == Vec3(1.0f, 0.5f, 0.0f) ||
4472 																							  vtx == Vec3(0.0f, 0.0f, 0.0f) || vtx == Vec3(1.0f, 0.0f, 0.0f)))
4473 											continue;
4474 
4475 										const bool isMirrored = tfResult.varying[vtxNdx].w() > 0.5f;
4476 										if (isMirrored)
4477 											mirroredEdgeVertices.insert(vtx);
4478 										else
4479 											nonMirroredEdgeVertices.insert(vtx);
4480 									}
4481 								}
4482 
4483 								if (m_primitiveType != TESSPRIMITIVETYPE_ISOLINES)
4484 								{
4485 									// Check that both endpoints are present. Note that endpoints aren't mirrored by the shader, since they belong to more than one edge.
4486 
4487 									Vec3 endpointA;
4488 									Vec3 endpointB;
4489 
4490 									if (m_primitiveType == TESSPRIMITIVETYPE_TRIANGLES)
4491 									{
4492 										endpointA = tcu::select(Vec3(1.0f), Vec3(0.0f), singleTrueMask<3>((edgeDesc.constantCoordinateIndex + 1) % 3));
4493 										endpointB = tcu::select(Vec3(1.0f), Vec3(0.0f), singleTrueMask<3>((edgeDesc.constantCoordinateIndex + 2) % 3));
4494 									}
4495 									else if (m_primitiveType == TESSPRIMITIVETYPE_QUADS)
4496 									{
4497 										endpointA.xy() = tcu::select(Vec2(edgeDesc.constantCoordinateValueChoices[0]), Vec2(0.0f), singleTrueMask<2>(edgeDesc.constantCoordinateIndex));
4498 										endpointB.xy() = tcu::select(Vec2(edgeDesc.constantCoordinateValueChoices[0]), Vec2(1.0f), singleTrueMask<2>(edgeDesc.constantCoordinateIndex));
4499 									}
4500 									else
4501 										DE_ASSERT(false);
4502 
4503 									if (!contains(nonMirroredEdgeVertices, endpointA) ||
4504 										!contains(nonMirroredEdgeVertices, endpointB))
4505 									{
4506 										log << TestLog::Message << "Failure: edge doesn't contain both endpoints, " << endpointA << " and " << endpointB << TestLog::EndMessage
4507 											<< TestLog::Message << "Note: non-mirrored vertices:\n" << containerStr(nonMirroredEdgeVertices, 5)
4508 																<< "\nmirrored vertices:\n" << containerStr(mirroredEdgeVertices, 5) << TestLog::EndMessage;
4509 										m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid set of vertices");
4510 										return STOP;
4511 									}
4512 									nonMirroredEdgeVertices.erase(endpointA);
4513 									nonMirroredEdgeVertices.erase(endpointB);
4514 								}
4515 
4516 								if (nonMirroredEdgeVertices != mirroredEdgeVertices)
4517 								{
4518 									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
4519 										<< TestLog::Message << "Note: non-mirrored vertices:\n" << containerStr(nonMirroredEdgeVertices, 5)
4520 																<< "\nmirrored vertices:\n" << containerStr(mirroredEdgeVertices, 5) << TestLog::EndMessage;
4521 									m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid set of vertices");
4522 									return STOP;
4523 								}
4524 							}
4525 						}
4526 					}
4527 				}
4528 			}
4529 		}
4530 	}
4531 
4532 	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
4533 	return STOP;
4534 }
4535 
4536 /*--------------------------------------------------------------------*//*!
4537  * \brief Test invariance rule #4
4538  *
4539  * Test that the vertices on an outer edge don't depend on which of the
4540  * edges it is, other than with respect to component order.
4541  *//*--------------------------------------------------------------------*/
4542 class OuterEdgeVertexSetIndexIndependenceCase : public TestCase
4543 {
4544 public:
OuterEdgeVertexSetIndexIndependenceCase(Context & context,const char * name,const char * description,TessPrimitiveType primType,SpacingMode spacing,Winding winding,bool usePointMode)4545 	OuterEdgeVertexSetIndexIndependenceCase (Context& context, const char* name, const char* description, TessPrimitiveType primType, SpacingMode spacing, Winding winding, bool usePointMode)
4546 		: TestCase			(context, name, description)
4547 		, m_primitiveType	(primType)
4548 		, m_spacing			(spacing)
4549 		, m_winding			(winding)
4550 		, m_usePointMode	(usePointMode)
4551 	{
4552 		DE_ASSERT(primType == TESSPRIMITIVETYPE_TRIANGLES || primType == TESSPRIMITIVETYPE_QUADS);
4553 	}
4554 
4555 	void									init		(void);
4556 	void									deinit		(void);
4557 	IterateResult							iterate		(void);
4558 
4559 private:
4560 	static vector<float>					generatePatchTessLevels (int numPatches, int constantOuterLevelIndex, float constantOuterLevel);
4561 
4562 	static const int						RENDER_SIZE = 16;
4563 
4564 	const TessPrimitiveType					m_primitiveType;
4565 	const SpacingMode						m_spacing;
4566 	const Winding							m_winding;
4567 	const bool								m_usePointMode;
4568 
4569 	SharedPtr<const glu::ShaderProgram>		m_program;
4570 };
4571 
generatePatchTessLevels(int numPatches,int constantOuterLevelIndex,float constantOuterLevel)4572 vector<float> OuterEdgeVertexSetIndexIndependenceCase::generatePatchTessLevels (int numPatches, int constantOuterLevelIndex, float constantOuterLevel)
4573 {
4574 	de::Random rnd(123);
4575 	return generateRandomPatchTessLevels(numPatches, constantOuterLevelIndex, constantOuterLevel, rnd);
4576 }
4577 
init(void)4578 void OuterEdgeVertexSetIndexIndependenceCase::init (void)
4579 {
4580 	checkTessellationSupport(m_context);
4581 	checkRenderTargetSize(m_context.getRenderTarget(), RENDER_SIZE);
4582 
4583 	std::string vertexShaderTemplate			("${GLSL_VERSION_DECL}\n"
4584 												 "${GLSL_PER_VERTEX_OUT}\n"
4585 												 "\n"
4586 												 "in highp float in_v_attr;\n"
4587 												 "out highp float in_tc_attr;\n"
4588 												 "\n"
4589 												 "void main (void)\n"
4590 												 "{\n"
4591 												 "	in_tc_attr = in_v_attr;\n"
4592 												 "}\n");
4593 	std::string tessellationControlTemplate		("${GLSL_VERSION_DECL}\n"
4594 												 "${TESSELLATION_SHADER_REQUIRE}\n"
4595 												 "${GLSL_PER_VERTEX_IN_ARR}\n"
4596 												 "${GLSL_PER_VERTEX_OUT_ARR}\n"
4597 												 "\n"
4598 												 "layout (vertices = 1) out;\n"
4599 												 "\n"
4600 												 "in highp float in_tc_attr[];\n"
4601 												 "\n"
4602 												 "void main (void)\n"
4603 												 "{\n"
4604 												 "	gl_TessLevelInner[0] = in_tc_attr[0];\n"
4605 												 "	gl_TessLevelInner[1] = in_tc_attr[1];\n"
4606 												 "\n"
4607 												 "	gl_TessLevelOuter[0] = in_tc_attr[2];\n"
4608 												 "	gl_TessLevelOuter[1] = in_tc_attr[3];\n"
4609 												 "	gl_TessLevelOuter[2] = in_tc_attr[4];\n"
4610 												 "	gl_TessLevelOuter[3] = in_tc_attr[5];\n"
4611 												 "}\n");
4612 	std::string tessellationEvaluationTemplate	("${GLSL_VERSION_DECL}\n"
4613 												 "${TESSELLATION_SHADER_REQUIRE}\n"
4614 												 "${GLSL_PER_VERTEX_IN_ARR}\n"
4615 												 "${GLSL_PER_VERTEX_OUT}\n"
4616 												 "\n"
4617 												 + getTessellationEvaluationInLayoutString(m_primitiveType, m_spacing, m_winding, m_usePointMode) +
4618 												 "\n"
4619 												 "out highp vec4 in_f_color;\n"
4620 												 "out highp vec3 out_te_tessCoord;\n"
4621 												 "\n"
4622 												 "void main (void)\n"
4623 												 "{\n"
4624 												 "	out_te_tessCoord = gl_TessCoord;"
4625 												 "	gl_Position = vec4(gl_TessCoord.xy, 0.0, 1.0);\n"
4626 												 "	in_f_color = vec4(1.0);\n"
4627 												 "}\n");
4628 	std::string fragmentShaderTemplate			("${GLSL_VERSION_DECL}\n"
4629 												 "\n"
4630 												 "layout (location = 0) out mediump vec4 o_color;\n"
4631 												 "\n"
4632 												 "in highp vec4 in_f_color;\n"
4633 												 "\n"
4634 												 "void main (void)\n"
4635 												 "{\n"
4636 												 "	o_color = in_f_color;\n"
4637 												 "}\n");
4638 
4639 	m_program = SharedPtr<const ShaderProgram>(new ShaderProgram(m_context.getRenderContext(), glu::ProgramSources()
4640 		<< glu::VertexSource					(specializeShader(m_context, vertexShaderTemplate.c_str()))
4641 		<< glu::TessellationControlSource		(specializeShader(m_context, tessellationControlTemplate.c_str()))
4642 		<< glu::TessellationEvaluationSource	(specializeShader(m_context, tessellationEvaluationTemplate.c_str()))
4643 		<< glu::FragmentSource					(specializeShader(m_context, fragmentShaderTemplate.c_str()))
4644 		<< glu::TransformFeedbackVarying		("out_te_tessCoord")
4645 		<< glu::TransformFeedbackMode			(GL_INTERLEAVED_ATTRIBS)));
4646 
4647 	m_testCtx.getLog() << *m_program;
4648 	if (!m_program->isOk())
4649 		TCU_FAIL("Program compilation failed");
4650 }
4651 
deinit(void)4652 void OuterEdgeVertexSetIndexIndependenceCase::deinit (void)
4653 {
4654 	m_program.clear();
4655 }
4656 
iterate(void)4657 OuterEdgeVertexSetIndexIndependenceCase::IterateResult OuterEdgeVertexSetIndexIndependenceCase::iterate (void)
4658 {
4659 	typedef TransformFeedbackHandler<Vec3> TFHandler;
4660 
4661 	TestLog&							log							= m_testCtx.getLog();
4662 	const RenderContext&				renderCtx					= m_context.getRenderContext();
4663 	const RandomViewport				viewport					(renderCtx.getRenderTarget(), RENDER_SIZE, RENDER_SIZE, deStringHash(getName()));
4664 	const glw::Functions&				gl							= renderCtx.getFunctions();
4665 	const deUint32						programGL					= m_program->getProgram();
4666 
4667 	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 };
4668 	const vector<OuterEdgeDescription>	edgeDescriptions			= outerEdgeDescriptions(m_primitiveType);
4669 
4670 	gl.useProgram(programGL);
4671 	setViewport(gl, viewport);
4672 	gl.patchParameteri(GL_PATCH_VERTICES, 6);
4673 
4674 	{
4675 		// Compute the number vertices in the largest draw call, so we can allocate the TF buffer just once.
4676 		int maxNumVerticesInDrawCall = 0;
4677 		{
4678 			const vector<float> patchTessLevels = generatePatchTessLevels(1, 0 /* outer-edge index doesn't affect vertex count */, arrayMax(singleOuterEdgeLevels));
4679 			maxNumVerticesInDrawCall = referenceVertexCount(m_primitiveType, m_spacing, m_usePointMode, &patchTessLevels[0], &patchTessLevels[2]);
4680 		}
4681 
4682 		{
4683 			const TFHandler tfHandler(m_context.getRenderContext(), maxNumVerticesInDrawCall);
4684 
4685 			for (int outerEdgeLevelCaseNdx = 0; outerEdgeLevelCaseNdx < DE_LENGTH_OF_ARRAY(singleOuterEdgeLevels); outerEdgeLevelCaseNdx++)
4686 			{
4687 				typedef std::set<Vec3, VecLexLessThan<3> > Vec3Set;
4688 
4689 				Vec3Set firstEdgeVertices;
4690 
4691 				for (int outerEdgeIndex = 0; outerEdgeIndex < (int)edgeDescriptions.size(); outerEdgeIndex++)
4692 				{
4693 					const OuterEdgeDescription&		edgeDesc			= edgeDescriptions[outerEdgeIndex];
4694 					const vector<float>				patchTessLevels		= generatePatchTessLevels(1, outerEdgeIndex, singleOuterEdgeLevels[outerEdgeLevelCaseNdx]);
4695 					const glu::VertexArrayBinding	bindings[]			= { glu::va::Float("in_v_attr", 1, (int)patchTessLevels.size(), 0, &patchTessLevels[0]) };
4696 
4697 					log << TestLog::Message << "Testing with outer tessellation level " << singleOuterEdgeLevels[outerEdgeLevelCaseNdx]
4698 											<< " for the " << edgeDesc.description() << " edge, and with various levels for other edges" << TestLog::EndMessage;
4699 
4700 					{
4701 						const TFHandler::Result		tfResult		= tfHandler.renderAndGetPrimitives(programGL, outputPrimitiveTypeGL(m_primitiveType, m_usePointMode),
4702 																										DE_LENGTH_OF_ARRAY(bindings), &bindings[0], (int)patchTessLevels.size());
4703 						const int					refNumVertices	= referenceVertexCount(m_primitiveType, m_spacing, m_usePointMode, &patchTessLevels[0], &patchTessLevels[2]);
4704 
4705 						if ((int)tfResult.varying.size() != refNumVertices)
4706 						{
4707 							log << TestLog::Message << "Failure: the number of vertices returned by transform feedback is "
4708 													<< tfResult.varying.size() << ", expected " << refNumVertices << TestLog::EndMessage
4709 								<< TestLog::Message << "Note: rendered 1 patch, tessellation levels are (in order [inner0, inner1, outer0, outer1, outer2, outer3]):\n"
4710 													<< containerStr(patchTessLevels, 6) << TestLog::EndMessage;
4711 
4712 							m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid set of vertices");
4713 							return STOP;
4714 						}
4715 
4716 						{
4717 							Vec3Set currentEdgeVertices;
4718 
4719 							// Get the vertices on the current outer edge.
4720 							for(int vtxNdx = 0; vtxNdx < refNumVertices; vtxNdx++)
4721 							{
4722 								const Vec3& vtx = tfResult.varying[vtxNdx];
4723 								if (edgeDesc.contains(vtx))
4724 								{
4725 									// Swizzle components to match the order of the first edge.
4726 									if (m_primitiveType == TESSPRIMITIVETYPE_TRIANGLES)
4727 									{
4728 										currentEdgeVertices.insert(outerEdgeIndex == 0 ? vtx
4729 																	: outerEdgeIndex == 1 ? vtx.swizzle(1, 0, 2)
4730 																	: outerEdgeIndex == 2 ? vtx.swizzle(2, 1, 0)
4731 																	: Vec3(-1.0f));
4732 									}
4733 									else if (m_primitiveType == TESSPRIMITIVETYPE_QUADS)
4734 									{
4735 										currentEdgeVertices.insert(Vec3(outerEdgeIndex == 0 ? vtx.y()
4736 																		: outerEdgeIndex == 1 ? vtx.x()
4737 																		: outerEdgeIndex == 2 ? vtx.y()
4738 																		: outerEdgeIndex == 3 ? vtx.x()
4739 																		: -1.0f,
4740 																		0.0f, 0.0f));
4741 									}
4742 									else
4743 										DE_ASSERT(false);
4744 								}
4745 							}
4746 
4747 							if (outerEdgeIndex == 0)
4748 								firstEdgeVertices = currentEdgeVertices;
4749 							else
4750 							{
4751 								// Compare vertices of this edge to those of the first edge.
4752 
4753 								if (currentEdgeVertices != firstEdgeVertices)
4754 								{
4755 									const char* const swizzleDesc = m_primitiveType == TESSPRIMITIVETYPE_TRIANGLES ? (outerEdgeIndex == 1 ? "(y, x, z)"
4756 																													: outerEdgeIndex == 2 ? "(z, y, x)"
4757 																													: DE_NULL)
4758 																	: m_primitiveType == TESSPRIMITIVETYPE_QUADS ? (outerEdgeIndex == 1 ? "(x, 0)"
4759 																												: outerEdgeIndex == 2 ? "(y, 0)"
4760 																												: outerEdgeIndex == 3 ? "(x, 0)"
4761 																												: DE_NULL)
4762 																	: DE_NULL;
4763 
4764 									log << TestLog::Message << "Failure: the set of vertices on the " << edgeDesc.description() << " edge"
4765 															<< " doesn't match the set of vertices on the " << edgeDescriptions[0].description() << " edge" << TestLog::EndMessage
4766 										<< TestLog::Message << "Note: set of vertices on " << edgeDesc.description() << " edge, components swizzled like " << swizzleDesc
4767 															<< " to match component order on first edge:\n" << containerStr(currentEdgeVertices, 5)
4768 															<< "\non " << edgeDescriptions[0].description() << " edge:\n" << containerStr(firstEdgeVertices, 5) << TestLog::EndMessage;
4769 									m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid set of vertices");
4770 									return STOP;
4771 								}
4772 							}
4773 						}
4774 					}
4775 				}
4776 			}
4777 		}
4778 	}
4779 
4780 	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
4781 	return STOP;
4782 }
4783 
4784 /*--------------------------------------------------------------------*//*!
4785  * \brief Test invariance rule #5
4786  *
4787  * Test that the set of triangles input to the TES only depends on the
4788  * tessellation levels, tessellation mode and spacing mode. Specifically,
4789  * winding doesn't change the set of triangles, though it can change the
4790  * order in which they are input to TES, and can (and will) change the
4791  * vertex order within a triangle.
4792  *//*--------------------------------------------------------------------*/
4793 class InvariantTriangleSetCase : public PrimitiveSetInvarianceCase
4794 {
4795 public:
InvariantTriangleSetCase(Context & context,const char * name,const char * description,TessPrimitiveType primType,SpacingMode spacing)4796 	InvariantTriangleSetCase (Context& context, const char* name, const char* description, TessPrimitiveType primType, SpacingMode spacing)
4797 		: PrimitiveSetInvarianceCase(context, name, description, primType, spacing, false, WINDINGUSAGE_VARY)
4798 	{
4799 		DE_ASSERT(primType == TESSPRIMITIVETYPE_TRIANGLES || primType == TESSPRIMITIVETYPE_QUADS);
4800 	}
4801 
4802 protected:
compare(const vector<Vec3> & coordsA,const vector<Vec3> & coordsB,int) const4803 	virtual bool compare (const vector<Vec3>& coordsA, const vector<Vec3>& coordsB, int) const
4804 	{
4805 		return compareTriangleSets(coordsA, coordsB, m_testCtx.getLog());
4806 	}
4807 };
4808 
4809 /*--------------------------------------------------------------------*//*!
4810  * \brief Test invariance rule #6
4811  *
4812  * Test that the set of inner triangles input to the TES only depends on
4813  * the inner tessellation levels, tessellation mode and spacing mode.
4814  *//*--------------------------------------------------------------------*/
4815 class InvariantInnerTriangleSetCase : public PrimitiveSetInvarianceCase
4816 {
4817 public:
InvariantInnerTriangleSetCase(Context & context,const char * name,const char * description,TessPrimitiveType primType,SpacingMode spacing)4818 	InvariantInnerTriangleSetCase (Context& context, const char* name, const char* description, TessPrimitiveType primType, SpacingMode spacing)
4819 		: PrimitiveSetInvarianceCase(context, name, description, primType, spacing, false, WINDINGUSAGE_VARY)
4820 	{
4821 		DE_ASSERT(primType == TESSPRIMITIVETYPE_TRIANGLES || primType == TESSPRIMITIVETYPE_QUADS);
4822 	}
4823 
4824 protected:
genTessLevelCases(void) const4825 	virtual vector<LevelCase> genTessLevelCases (void) const
4826 	{
4827 		const int					numSubCases		= 4;
4828 		const vector<LevelCase>		baseResults		= PrimitiveSetInvarianceCase::genTessLevelCases();
4829 		vector<LevelCase>			result;
4830 		de::Random					rnd				(123);
4831 
4832 		// Generate variants with different values for irrelevant levels.
4833 		for (int baseNdx = 0; baseNdx < (int)baseResults.size(); baseNdx++)
4834 		{
4835 			const TessLevels&	base	= baseResults[baseNdx].levels[0];
4836 			TessLevels			levels	= base;
4837 			LevelCase			levelCase;
4838 
4839 			for (int subNdx = 0; subNdx < numSubCases; subNdx++)
4840 			{
4841 				levelCase.levels.push_back(levels);
4842 
4843 				for (int i = 0; i < DE_LENGTH_OF_ARRAY(levels.outer); i++)
4844 					levels.outer[i] = rnd.getFloat(2.0f, 16.0f);
4845 				if (m_primitiveType == TESSPRIMITIVETYPE_TRIANGLES)
4846 					levels.inner[1] = rnd.getFloat(2.0f, 16.0f);
4847 			}
4848 
4849 			result.push_back(levelCase);
4850 		}
4851 
4852 		return result;
4853 	}
4854 
4855 	struct IsInnerTriangleTriangle
4856 	{
operator ()deqp::gles31::Functional::__anon755cd4500211::InvariantInnerTriangleSetCase::IsInnerTriangleTriangle4857 		bool operator() (const Vec3* vertices) const
4858 		{
4859 			for (int v = 0; v < 3; v++)
4860 				for (int c = 0; c < 3; c++)
4861 					if (vertices[v][c] == 0.0f)
4862 						return false;
4863 			return true;
4864 		}
4865 	};
4866 
4867 	struct IsInnerQuadTriangle
4868 	{
operator ()deqp::gles31::Functional::__anon755cd4500211::InvariantInnerTriangleSetCase::IsInnerQuadTriangle4869 		bool operator() (const Vec3* vertices) const
4870 		{
4871 			for (int v = 0; v < 3; v++)
4872 				for (int c = 0; c < 2; c++)
4873 					if (vertices[v][c] == 0.0f || vertices[v][c] == 1.0f)
4874 						return false;
4875 			return true;
4876 		}
4877 	};
4878 
compare(const vector<Vec3> & coordsA,const vector<Vec3> & coordsB,int) const4879 	virtual bool compare (const vector<Vec3>& coordsA, const vector<Vec3>& coordsB, int) const
4880 	{
4881 		if (m_primitiveType == TESSPRIMITIVETYPE_TRIANGLES)
4882 			return compareTriangleSets(coordsA, coordsB, m_testCtx.getLog(), IsInnerTriangleTriangle(), "outer triangles");
4883 		else if (m_primitiveType == TESSPRIMITIVETYPE_QUADS)
4884 			return compareTriangleSets(coordsA, coordsB, m_testCtx.getLog(), IsInnerQuadTriangle(), "outer triangles");
4885 		else
4886 		{
4887 			DE_ASSERT(false);
4888 			return false;
4889 		}
4890 	}
4891 };
4892 
4893 /*--------------------------------------------------------------------*//*!
4894  * \brief Test invariance rule #7
4895  *
4896  * Test that the set of outer triangles input to the TES only depends on
4897  * tessellation mode, spacing mode and the inner and outer tessellation
4898  * levels corresponding to the inner and outer edges relevant to that
4899  * triangle.
4900  *//*--------------------------------------------------------------------*/
4901 class InvariantOuterTriangleSetCase : public PrimitiveSetInvarianceCase
4902 {
4903 public:
InvariantOuterTriangleSetCase(Context & context,const char * name,const char * description,TessPrimitiveType primType,SpacingMode spacing)4904 	InvariantOuterTriangleSetCase (Context& context, const char* name, const char* description, TessPrimitiveType primType, SpacingMode spacing)
4905 		: PrimitiveSetInvarianceCase(context, name, description, primType, spacing, false, WINDINGUSAGE_VARY)
4906 	{
4907 		DE_ASSERT(primType == TESSPRIMITIVETYPE_TRIANGLES || primType == TESSPRIMITIVETYPE_QUADS);
4908 	}
4909 
4910 protected:
genTessLevelCases(void) const4911 	virtual vector<LevelCase> genTessLevelCases (void) const
4912 	{
4913 		const int					numSubCasesPerEdge	= 4;
4914 		const int					numEdges			= m_primitiveType == TESSPRIMITIVETYPE_TRIANGLES	? 3
4915 														: m_primitiveType == TESSPRIMITIVETYPE_QUADS		? 4
4916 														: -1;
4917 		const vector<LevelCase>		baseResult			= PrimitiveSetInvarianceCase::genTessLevelCases();
4918 		vector<LevelCase>			result;
4919 		de::Random					rnd					(123);
4920 
4921 		// Generate variants with different values for irrelevant levels.
4922 		for (int baseNdx = 0; baseNdx < (int)baseResult.size(); baseNdx++)
4923 		{
4924 			const TessLevels& base = baseResult[baseNdx].levels[0];
4925 			if (base.inner[0] == 1.0f || (m_primitiveType == TESSPRIMITIVETYPE_QUADS && base.inner[1] == 1.0f))
4926 				continue;
4927 
4928 			for (int edgeNdx = 0; edgeNdx < numEdges; edgeNdx++)
4929 			{
4930 				TessLevels	levels = base;
4931 				LevelCase	levelCase;
4932 				levelCase.mem = edgeNdx;
4933 
4934 				for (int subCaseNdx = 0; subCaseNdx < numSubCasesPerEdge; subCaseNdx++)
4935 				{
4936 					levelCase.levels.push_back(levels);
4937 
4938 					for (int i = 0; i < DE_LENGTH_OF_ARRAY(levels.outer); i++)
4939 					{
4940 						if (i != edgeNdx)
4941 							levels.outer[i] = rnd.getFloat(2.0f, 16.0f);
4942 					}
4943 
4944 					if (m_primitiveType == TESSPRIMITIVETYPE_TRIANGLES)
4945 						levels.inner[1] = rnd.getFloat(2.0f, 16.0f);
4946 				}
4947 
4948 				result.push_back(levelCase);
4949 			}
4950 		}
4951 
4952 		return result;
4953 	}
4954 
4955 	class IsTriangleTriangleOnOuterEdge
4956 	{
4957 	public:
IsTriangleTriangleOnOuterEdge(int edgeNdx)4958 		IsTriangleTriangleOnOuterEdge (int edgeNdx) : m_edgeNdx(edgeNdx) {}
operator ()(const Vec3 * vertices) const4959 		bool operator() (const Vec3* vertices) const
4960 		{
4961 			bool touchesAppropriateEdge = false;
4962 			for (int v = 0; v < 3; v++)
4963 				if (vertices[v][m_edgeNdx] == 0.0f)
4964 					touchesAppropriateEdge = true;
4965 
4966 			if (touchesAppropriateEdge)
4967 			{
4968 				const Vec3 avg = (vertices[0] + vertices[1] + vertices[2]) / 3.0f;
4969 				return avg[m_edgeNdx] < avg[(m_edgeNdx+1)%3] &&
4970 					   avg[m_edgeNdx] < avg[(m_edgeNdx+2)%3];
4971 			}
4972 			return false;
4973 		}
4974 
4975 	private:
4976 		int m_edgeNdx;
4977 	};
4978 
4979 	class IsQuadTriangleOnOuterEdge
4980 	{
4981 	public:
IsQuadTriangleOnOuterEdge(int edgeNdx)4982 		IsQuadTriangleOnOuterEdge (int edgeNdx) : m_edgeNdx(edgeNdx) {}
4983 
onEdge(const Vec3 & v) const4984 		bool onEdge (const Vec3& v) const
4985 		{
4986 			return v[m_edgeNdx%2] == (m_edgeNdx <= 1 ? 0.0f : 1.0f);
4987 		}
4988 
onAnyEdge(const Vec3 & v)4989 		static inline bool onAnyEdge (const Vec3& v)
4990 		{
4991 			return v[0] == 0.0f || v[0] == 1.0f || v[1] == 0.0f || v[1] == 1.0f;
4992 		}
4993 
operator ()(const Vec3 * vertices) const4994 		bool operator() (const Vec3* vertices) const
4995 		{
4996 			for (int v = 0; v < 3; v++)
4997 			{
4998 				const Vec3& a = vertices[v];
4999 				const Vec3& b = vertices[(v+1)%3];
5000 				const Vec3& c = vertices[(v+2)%3];
5001 				if (onEdge(a) && onEdge(b))
5002 					return true;
5003 				if (onEdge(c) && !onAnyEdge(a) && !onAnyEdge(b) && a[m_edgeNdx%2] == b[m_edgeNdx%2])
5004 					return true;
5005 			}
5006 
5007 			return false;
5008 		}
5009 
5010 	private:
5011 		int m_edgeNdx;
5012 	};
5013 
compare(const vector<Vec3> & coordsA,const vector<Vec3> & coordsB,int outerEdgeNdx) const5014 	virtual bool compare (const vector<Vec3>& coordsA, const vector<Vec3>& coordsB, int outerEdgeNdx) const
5015 	{
5016 		if (m_primitiveType == TESSPRIMITIVETYPE_TRIANGLES)
5017 		{
5018 			return compareTriangleSets(coordsA, coordsB, m_testCtx.getLog(),
5019 									   IsTriangleTriangleOnOuterEdge(outerEdgeNdx),
5020 									   ("inner triangles, and outer triangles corresponding to other edge than edge "
5021 										+ outerEdgeDescriptions(m_primitiveType)[outerEdgeNdx].description()).c_str());
5022 		}
5023 		else if (m_primitiveType == TESSPRIMITIVETYPE_QUADS)
5024 		{
5025 			return compareTriangleSets(coordsA, coordsB, m_testCtx.getLog(),
5026 									   IsQuadTriangleOnOuterEdge(outerEdgeNdx),
5027 									   ("inner triangles, and outer triangles corresponding to other edge than edge "
5028 										+ outerEdgeDescriptions(m_primitiveType)[outerEdgeNdx].description()).c_str());
5029 		}
5030 		else
5031 			DE_ASSERT(false);
5032 
5033 		return true;
5034 	}
5035 };
5036 
5037 /*--------------------------------------------------------------------*//*!
5038  * \brief Base class for testing individual components of tess coords
5039  *
5040  * Useful for testing parts of invariance rule #8.
5041  *//*--------------------------------------------------------------------*/
5042 class TessCoordComponentInvarianceCase : public TestCase
5043 {
5044 public:
TessCoordComponentInvarianceCase(Context & context,const char * name,const char * description,TessPrimitiveType primType,SpacingMode spacing,Winding winding,bool usePointMode)5045 	TessCoordComponentInvarianceCase (Context& context, const char* name, const char* description, TessPrimitiveType primType, SpacingMode spacing, Winding winding, bool usePointMode)
5046 		: TestCase			(context, name, description)
5047 		, m_primitiveType	(primType)
5048 		, m_spacing			(spacing)
5049 		, m_winding			(winding)
5050 		, m_usePointMode	(usePointMode)
5051 	{
5052 	}
5053 
5054 	void									init		(void);
5055 	void									deinit		(void);
5056 	IterateResult							iterate		(void);
5057 
5058 protected:
5059 	virtual string							tessEvalOutputComponentStatements	(const char* tessCoordComponentName, const char* outputComponentName) const = 0;
5060 	virtual bool							checkTessCoordComponent				(float component) const = 0;
5061 
5062 private:
5063 	static vector<float>					genTessLevelCases (int numCases);
5064 
5065 	static const int						RENDER_SIZE = 16;
5066 
5067 	const TessPrimitiveType					m_primitiveType;
5068 	const SpacingMode						m_spacing;
5069 	const Winding							m_winding;
5070 	const bool								m_usePointMode;
5071 
5072 	SharedPtr<const glu::ShaderProgram>		m_program;
5073 };
5074 
init(void)5075 void TessCoordComponentInvarianceCase::init (void)
5076 {
5077 	checkTessellationSupport(m_context);
5078 	checkRenderTargetSize(m_context.getRenderTarget(), RENDER_SIZE);
5079 
5080 	std::string vertexShaderTemplate			("${GLSL_VERSION_DECL}\n"
5081 												 "${GLSL_PER_VERTEX_OUT}\n"
5082 												 "\n"
5083 												 "in highp float in_v_attr;\n"
5084 												 "out highp float in_tc_attr;\n"
5085 												 "\n"
5086 												 "void main (void)\n"
5087 												 "{\n"
5088 												 "	in_tc_attr = in_v_attr;\n"
5089 												 "}\n");
5090 	std::string tessellationControlTemplate		("${GLSL_VERSION_DECL}\n"
5091 												 "${TESSELLATION_SHADER_REQUIRE}\n"
5092 												 "${GLSL_PER_VERTEX_IN_ARR}\n"
5093 												 "${GLSL_PER_VERTEX_OUT_ARR}\n"
5094 												 "\n"
5095 												 "layout (vertices = 1) out;\n"
5096 												 "\n"
5097 												 "in highp float in_tc_attr[];\n"
5098 												 "\n"
5099 												 "void main (void)\n"
5100 												 "{\n"
5101 												 "	gl_TessLevelInner[0] = in_tc_attr[0];\n"
5102 												 "	gl_TessLevelInner[1] = in_tc_attr[1];\n"
5103 												 "\n"
5104 												 "	gl_TessLevelOuter[0] = in_tc_attr[2];\n"
5105 												 "	gl_TessLevelOuter[1] = in_tc_attr[3];\n"
5106 												 "	gl_TessLevelOuter[2] = in_tc_attr[4];\n"
5107 												 "	gl_TessLevelOuter[3] = in_tc_attr[5];\n"
5108 												 "}\n");
5109 	std::string tessellationEvaluationTemplate	("${GLSL_VERSION_DECL}\n"
5110 												 "${TESSELLATION_SHADER_REQUIRE}\n"
5111 												 "${GLSL_PER_VERTEX_IN_ARR}\n"
5112 												 "${GLSL_PER_VERTEX_OUT}\n"
5113 												 "\n"
5114 												 + getTessellationEvaluationInLayoutString(m_primitiveType, m_spacing, m_winding, m_usePointMode) +
5115 												 "\n"
5116 												 "out highp vec4 in_f_color;\n"
5117 												 "out highp vec3 out_te_output;\n"
5118 												 "\n"
5119 												 "void main (void)\n"
5120 												 "{\n"
5121 												 + tessEvalOutputComponentStatements("gl_TessCoord.x", "out_te_output.x")
5122 												 + tessEvalOutputComponentStatements("gl_TessCoord.y", "out_te_output.y")
5123 
5124 												 + (m_primitiveType == TESSPRIMITIVETYPE_TRIANGLES ?
5125 													tessEvalOutputComponentStatements("gl_TessCoord.z", "out_te_output.z") :
5126 													"	out_te_output.z = 0.0f;\n") +
5127 												 "	gl_Position = vec4(gl_TessCoord.xy, 0.0, 1.0);\n"
5128 												 "	in_f_color = vec4(1.0);\n"
5129 												 "}\n");
5130 	std::string fragmentShaderTemplate			("${GLSL_VERSION_DECL}\n"
5131 												 "\n"
5132 												 "layout (location = 0) out mediump vec4 o_color;\n"
5133 												 "\n"
5134 												 "in highp vec4 in_f_color;\n"
5135 												 "\n"
5136 												 "void main (void)\n"
5137 												 "{\n"
5138 												 "	o_color = in_f_color;\n"
5139 												 "}\n");
5140 
5141 	m_program = SharedPtr<const ShaderProgram>(new ShaderProgram(m_context.getRenderContext(), glu::ProgramSources()
5142 		<< glu::VertexSource					(specializeShader(m_context, vertexShaderTemplate.c_str()))
5143 		<< glu::TessellationControlSource		(specializeShader(m_context, tessellationControlTemplate.c_str()))
5144 		<< glu::TessellationEvaluationSource	(specializeShader(m_context, tessellationEvaluationTemplate.c_str()))
5145 		<< glu::FragmentSource					(specializeShader(m_context, fragmentShaderTemplate.c_str()))
5146 		<< glu::TransformFeedbackVarying		("out_te_output")
5147 		<< glu::TransformFeedbackMode			(GL_INTERLEAVED_ATTRIBS)));
5148 
5149 	m_testCtx.getLog() << *m_program;
5150 	if (!m_program->isOk())
5151 		TCU_FAIL("Program compilation failed");
5152 }
5153 
deinit(void)5154 void TessCoordComponentInvarianceCase::deinit (void)
5155 {
5156 	m_program.clear();
5157 }
5158 
genTessLevelCases(int numCases)5159 vector<float> TessCoordComponentInvarianceCase::genTessLevelCases (int numCases)
5160 {
5161 	de::Random		rnd(123);
5162 	vector<float>	result;
5163 
5164 	for (int i = 0; i < numCases; i++)
5165 		for (int j = 0; j < 6; j++)
5166 			result.push_back(rnd.getFloat(1.0f, 63.0f));
5167 
5168 	return result;
5169 }
5170 
iterate(void)5171 TessCoordComponentInvarianceCase::IterateResult TessCoordComponentInvarianceCase::iterate (void)
5172 {
5173 	typedef TransformFeedbackHandler<Vec3> TFHandler;
5174 
5175 	TestLog&				log					= m_testCtx.getLog();
5176 	const RenderContext&	renderCtx			= m_context.getRenderContext();
5177 	const RandomViewport	viewport			(renderCtx.getRenderTarget(), RENDER_SIZE, RENDER_SIZE, deStringHash(getName()));
5178 	const glw::Functions&	gl					= renderCtx.getFunctions();
5179 	const int				numTessLevelCases	= 32;
5180 	const vector<float>		tessLevels			= genTessLevelCases(numTessLevelCases);
5181 	const deUint32			programGL			= m_program->getProgram();
5182 
5183 	gl.useProgram(programGL);
5184 	setViewport(gl, viewport);
5185 	gl.patchParameteri(GL_PATCH_VERTICES, 6);
5186 
5187 	{
5188 		// Compute the number vertices in the largest draw call, so we can allocate the TF buffer just once.
5189 		int maxNumVerticesInDrawCall = 0;
5190 		for (int i = 0; i < numTessLevelCases; i++)
5191 			maxNumVerticesInDrawCall = de::max(maxNumVerticesInDrawCall, referenceVertexCount(m_primitiveType, m_spacing, m_usePointMode, &tessLevels[6*i+0], &tessLevels[6*i+2]));
5192 
5193 		{
5194 			const TFHandler tfHandler(m_context.getRenderContext(), maxNumVerticesInDrawCall);
5195 
5196 			for (int tessLevelCaseNdx = 0; tessLevelCaseNdx < numTessLevelCases; tessLevelCaseNdx++)
5197 			{
5198 				log << TestLog::Message << "Testing with tessellation levels: " << tessellationLevelsString(&tessLevels[6*tessLevelCaseNdx+0], &tessLevels[6*tessLevelCaseNdx+2]) << TestLog::EndMessage;
5199 
5200 				const glu::VertexArrayBinding bindings[] = { glu::va::Float("in_v_attr", 1, (int)6, 0, &tessLevels[6*tessLevelCaseNdx]) };
5201 				const TFHandler::Result tfResult = tfHandler.renderAndGetPrimitives(programGL, outputPrimitiveTypeGL(m_primitiveType, m_usePointMode),
5202 																					DE_LENGTH_OF_ARRAY(bindings), &bindings[0], 6);
5203 
5204 				for (int vtxNdx = 0; vtxNdx < (int)tfResult.varying.size(); vtxNdx++)
5205 				{
5206 					const Vec3&		vec			= tfResult.varying[vtxNdx];
5207 					const int		numComps	= m_primitiveType == TESSPRIMITIVETYPE_TRIANGLES ? 3 : 2;
5208 
5209 					for (int compNdx = 0; compNdx < numComps; compNdx++)
5210 					{
5211 						if (!checkTessCoordComponent(vec[compNdx]))
5212 						{
5213 							log << TestLog::Message << "Note: output value at index " << vtxNdx << " is "
5214 													<< (m_primitiveType == TESSPRIMITIVETYPE_TRIANGLES ? de::toString(vec) : de::toString(vec.swizzle(0,1)))
5215 													<< TestLog::EndMessage;
5216 							m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Invalid tessellation coordinate component");
5217 							return STOP;
5218 						}
5219 					}
5220 				}
5221 			}
5222 		}
5223 	}
5224 
5225 	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
5226 	return STOP;
5227 }
5228 
5229 /*--------------------------------------------------------------------*//*!
5230  * \brief Test first part of invariance rule #8
5231  *
5232  * Test that all (relevant) components of tess coord are in [0,1].
5233  *//*--------------------------------------------------------------------*/
5234 class TessCoordComponentRangeCase : public TessCoordComponentInvarianceCase
5235 {
5236 public:
TessCoordComponentRangeCase(Context & context,const char * name,const char * description,TessPrimitiveType primType,SpacingMode spacing,Winding winding,bool usePointMode)5237 	TessCoordComponentRangeCase (Context& context, const char* name, const char* description, TessPrimitiveType primType, SpacingMode spacing, Winding winding, bool usePointMode)
5238 		: TessCoordComponentInvarianceCase(context, name, description, primType, spacing, winding, usePointMode)
5239 	{
5240 	}
5241 
5242 protected:
tessEvalOutputComponentStatements(const char * tessCoordComponentName,const char * outputComponentName) const5243 	virtual string tessEvalOutputComponentStatements (const char* tessCoordComponentName, const char* outputComponentName) const
5244 	{
5245 		return string() + "\t" + outputComponentName + " = " + tessCoordComponentName + ";\n";
5246 	}
5247 
checkTessCoordComponent(float component) const5248 	virtual bool checkTessCoordComponent (float component) const
5249 	{
5250 		if (!de::inRange(component, 0.0f, 1.0f))
5251 		{
5252 			m_testCtx.getLog() << TestLog::Message << "Failure: tess coord component isn't in range [0,1]" << TestLog::EndMessage;
5253 			return false;
5254 		}
5255 		return true;
5256 	}
5257 };
5258 
5259 /*--------------------------------------------------------------------*//*!
5260  * \brief Test second part of invariance rule #8
5261  *
5262  * Test that all (relevant) components of tess coord are in [0,1] and
5263  * 1.0-c is exact for every such component c.
5264  *//*--------------------------------------------------------------------*/
5265 class OneMinusTessCoordComponentCase : public TessCoordComponentInvarianceCase
5266 {
5267 public:
OneMinusTessCoordComponentCase(Context & context,const char * name,const char * description,TessPrimitiveType primType,SpacingMode spacing,Winding winding,bool usePointMode)5268 	OneMinusTessCoordComponentCase (Context& context, const char* name, const char* description, TessPrimitiveType primType, SpacingMode spacing, Winding winding, bool usePointMode)
5269 		: TessCoordComponentInvarianceCase(context, name, description, primType, spacing, winding, usePointMode)
5270 	{
5271 	}
5272 
5273 protected:
tessEvalOutputComponentStatements(const char * tessCoordComponentName,const char * outputComponentName) const5274 	virtual string tessEvalOutputComponentStatements (const char* tessCoordComponentName, const char* outputComponentName) const
5275 	{
5276 		return string() + "	{\n"
5277 						  "		float oneMinusComp = 1.0 - " + tessCoordComponentName + ";\n"
5278 						  "		" + outputComponentName + " = " + tessCoordComponentName + " + oneMinusComp;\n"
5279 						  "	}\n";
5280 	}
5281 
checkTessCoordComponent(float component) const5282 	virtual bool checkTessCoordComponent (float component) const
5283 	{
5284 		if (component != 1.0f)
5285 		{
5286 			m_testCtx.getLog() << TestLog::Message << "Failure: comp + (1.0-comp) doesn't equal 1.0 for some component of tessellation coordinate" << TestLog::EndMessage;
5287 			return false;
5288 		}
5289 		return true;
5290 	}
5291 };
5292 
5293 /*--------------------------------------------------------------------*//*!
5294  * \brief Test that patch is discarded if relevant outer level <= 0.0
5295  *
5296  * Draws patches with different combinations of tessellation levels,
5297  * varying which levels are negative. Verifies by checking that colored
5298  * pixels exist inside the area of valid primitives, and only black pixels
5299  * exist inside the area of discarded primitives. An additional sanity
5300  * test is done, checking that the number of primitives written by TF is
5301  * correct.
5302  *//*--------------------------------------------------------------------*/
5303 class PrimitiveDiscardCase : public TestCase
5304 {
5305 public:
PrimitiveDiscardCase(Context & context,const char * name,const char * description,TessPrimitiveType primType,SpacingMode spacing,Winding winding,bool usePointMode)5306 	PrimitiveDiscardCase (Context& context, const char* name, const char* description, TessPrimitiveType primType, SpacingMode spacing, Winding winding, bool usePointMode)
5307 		: TestCase			(context, name, description)
5308 		, m_primitiveType	(primType)
5309 		, m_spacing			(spacing)
5310 		, m_winding			(winding)
5311 		, m_usePointMode	(usePointMode)
5312 	{
5313 	}
5314 
5315 	void									init		(void);
5316 	void									deinit		(void);
5317 	IterateResult							iterate		(void);
5318 
5319 private:
5320 	static vector<float>					genAttributes (void);
5321 
5322 	static const int						RENDER_SIZE = 256;
5323 
5324 	const TessPrimitiveType					m_primitiveType;
5325 	const SpacingMode						m_spacing;
5326 	const Winding							m_winding;
5327 	const bool								m_usePointMode;
5328 
5329 	SharedPtr<const glu::ShaderProgram>		m_program;
5330 };
5331 
init(void)5332 void PrimitiveDiscardCase::init (void)
5333 {
5334 	checkTessellationSupport(m_context);
5335 	checkRenderTargetSize(m_context.getRenderTarget(), RENDER_SIZE);
5336 
5337 	std::string vertexShaderTemplate			("${GLSL_VERSION_DECL}\n"
5338 												 "${GLSL_PER_VERTEX_OUT}\n"
5339 												 "\n"
5340 												 "in highp float in_v_attr;\n"
5341 												 "out highp float in_tc_attr;\n"
5342 												 "\n"
5343 												 "void main (void)\n"
5344 												 "{\n"
5345 												 "	in_tc_attr = in_v_attr;\n"
5346 												 "}\n");
5347 	std::string tessellationControlTemplate		("${GLSL_VERSION_DECL}\n"
5348 												 "${TESSELLATION_SHADER_REQUIRE}\n"
5349 												 "${GLSL_PER_VERTEX_IN_ARR}\n"
5350 												 "${GLSL_PER_VERTEX_OUT_ARR}\n"
5351 												 "\n"
5352 												 "layout (vertices = 1) out;\n"
5353 												 "\n"
5354 												 "in highp float in_tc_attr[];\n"
5355 												 "\n"
5356 												 "patch out highp vec2 in_te_positionScale;\n"
5357 												 "patch out highp vec2 in_te_positionOffset;\n"
5358 												 "\n"
5359 												 "void main (void)\n"
5360 												 "{\n"
5361 												 "	in_te_positionScale  = vec2(in_tc_attr[6], in_tc_attr[7]);\n"
5362 												 "	in_te_positionOffset = vec2(in_tc_attr[8], in_tc_attr[9]);\n"
5363 												 "\n"
5364 												 "	gl_TessLevelInner[0] = in_tc_attr[0];\n"
5365 												 "	gl_TessLevelInner[1] = in_tc_attr[1];\n"
5366 												 "\n"
5367 												 "	gl_TessLevelOuter[0] = in_tc_attr[2];\n"
5368 												 "	gl_TessLevelOuter[1] = in_tc_attr[3];\n"
5369 												 "	gl_TessLevelOuter[2] = in_tc_attr[4];\n"
5370 												 "	gl_TessLevelOuter[3] = in_tc_attr[5];\n"
5371 												 "}\n");
5372 	std::string tessellationEvaluationTemplate	("${GLSL_VERSION_DECL}\n"
5373 												 "${TESSELLATION_SHADER_REQUIRE}\n"
5374 												 "${GLSL_PER_VERTEX_IN_ARR}\n"
5375 												 "${GLSL_PER_VERTEX_OUT}\n"
5376 												 "\n"
5377 												 + getTessellationEvaluationInLayoutString(m_primitiveType, m_spacing, m_winding, m_usePointMode) +
5378 												 "\n"
5379 												 "patch in highp vec2 in_te_positionScale;\n"
5380 												 "patch in highp vec2 in_te_positionOffset;\n"
5381 												 "\n"
5382 												 "out highp vec3 out_te_tessCoord;\n"
5383 												 "\n"
5384 												 "void main (void)\n"
5385 												 "{\n"
5386 												 "	out_te_tessCoord = gl_TessCoord;\n"
5387 												 "	gl_Position = vec4(gl_TessCoord.xy*in_te_positionScale + in_te_positionOffset, 0.0, 1.0);\n"
5388 												 "}\n");
5389 	std::string fragmentShaderTemplate			("${GLSL_VERSION_DECL}\n"
5390 												 "\n"
5391 												 "layout (location = 0) out mediump vec4 o_color;\n"
5392 												 "\n"
5393 												 "void main (void)\n"
5394 												 "{\n"
5395 												 "	o_color = vec4(1.0);\n"
5396 												 "}\n");
5397 
5398 	m_program = SharedPtr<const ShaderProgram>(new ShaderProgram(m_context.getRenderContext(), glu::ProgramSources()
5399 		<< glu::VertexSource					(specializeShader(m_context, vertexShaderTemplate.c_str()))
5400 		<< glu::TessellationControlSource		(specializeShader(m_context, tessellationControlTemplate.c_str()))
5401 		<< glu::TessellationEvaluationSource	(specializeShader(m_context, tessellationEvaluationTemplate.c_str()))
5402 		<< glu::FragmentSource					(specializeShader(m_context, fragmentShaderTemplate.c_str()))
5403 		<< glu::TransformFeedbackVarying		("out_te_tessCoord")
5404 		<< glu::TransformFeedbackMode			(GL_INTERLEAVED_ATTRIBS)));
5405 
5406 	m_testCtx.getLog() << *m_program;
5407 	if (!m_program->isOk())
5408 		TCU_FAIL("Program compilation failed");
5409 }
5410 
deinit(void)5411 void PrimitiveDiscardCase::deinit (void)
5412 {
5413 	m_program.clear();
5414 }
5415 
genAttributes(void)5416 vector<float> PrimitiveDiscardCase::genAttributes (void)
5417 {
5418 	// Generate input attributes (tessellation levels, and position scale and
5419 	// offset) for a number of primitives. Each primitive has a different
5420 	// combination of tessellatio levels; each level is either a valid
5421 	// value or an "invalid" value (negative or zero, chosen from
5422 	// invalidTessLevelChoices).
5423 
5424 	// \note The attributes are generated in such an order that all of the
5425 	//		 valid attribute tuples come before the first invalid one both
5426 	//		 in the result vector, and when scanning the resulting 2d grid
5427 	//		 of primitives is scanned in y-major order. This makes
5428 	//		 verification somewhat simpler.
5429 
5430 	static const float	baseTessLevels[6]			= { 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f };
5431 	static const float	invalidTessLevelChoices[]	= { -0.42f, 0.0f };
5432 	const int			numChoices					= 1 + DE_LENGTH_OF_ARRAY(invalidTessLevelChoices);
5433 	float				choices[6][numChoices];
5434 	vector<float>		result;
5435 
5436 	for (int levelNdx = 0; levelNdx < 6; levelNdx++)
5437 		for (int choiceNdx = 0; choiceNdx < numChoices; choiceNdx++)
5438 			choices[levelNdx][choiceNdx] = choiceNdx == 0 ? baseTessLevels[levelNdx] : invalidTessLevelChoices[choiceNdx-1];
5439 
5440 	{
5441 		const int	numCols			= intPow(numChoices, 6/2); // sqrt(numChoices**6) == sqrt(number of primitives)
5442 		const int	numRows			= numCols;
5443 		int			index			= 0;
5444 		int			i[6];
5445 		// We could do this with some generic combination-generation function, but meh, it's not that bad.
5446 		for (i[2] = 0; i[2] < numChoices; i[2]++) // First  outer
5447 		for (i[3] = 0; i[3] < numChoices; i[3]++) // Second outer
5448 		for (i[4] = 0; i[4] < numChoices; i[4]++) // Third  outer
5449 		for (i[5] = 0; i[5] < numChoices; i[5]++) // Fourth outer
5450 		for (i[0] = 0; i[0] < numChoices; i[0]++) // First  inner
5451 		for (i[1] = 0; i[1] < numChoices; i[1]++) // Second inner
5452 		{
5453 			for (int j = 0; j < 6; j++)
5454 				result.push_back(choices[j][i[j]]);
5455 
5456 			{
5457 				const int col = index % numCols;
5458 				const int row = index / numCols;
5459 				// Position scale.
5460 				result.push_back((float)2.0f / (float)numCols);
5461 				result.push_back((float)2.0f / (float)numRows);
5462 				// Position offset.
5463 				result.push_back((float)col / (float)numCols * 2.0f - 1.0f);
5464 				result.push_back((float)row / (float)numRows * 2.0f - 1.0f);
5465 			}
5466 
5467 			index++;
5468 		}
5469 	}
5470 
5471 	return result;
5472 }
5473 
iterate(void)5474 PrimitiveDiscardCase::IterateResult PrimitiveDiscardCase::iterate (void)
5475 {
5476 	typedef TransformFeedbackHandler<Vec3> TFHandler;
5477 
5478 	TestLog&				log						= m_testCtx.getLog();
5479 	const RenderContext&	renderCtx				= m_context.getRenderContext();
5480 	const RandomViewport	viewport				(renderCtx.getRenderTarget(), RENDER_SIZE, RENDER_SIZE, deStringHash(getName()));
5481 	const glw::Functions&	gl						= renderCtx.getFunctions();
5482 	const vector<float>		attributes				= genAttributes();
5483 	const int				numAttribsPerPrimitive	= 6+2+2; // Tess levels, scale, offset.
5484 	const int				numPrimitives			= (int)attributes.size() / numAttribsPerPrimitive;
5485 	const deUint32			programGL				= m_program->getProgram();
5486 
5487 	gl.useProgram(programGL);
5488 	setViewport(gl, viewport);
5489 	gl.patchParameteri(GL_PATCH_VERTICES, numAttribsPerPrimitive);
5490 
5491 	gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
5492 	gl.clear(GL_COLOR_BUFFER_BIT);
5493 
5494 	// Check the convenience assertion that all discarded patches come after the last non-discarded patch.
5495 	{
5496 		bool discardedPatchEncountered = false;
5497 		for (int patchNdx = 0; patchNdx < numPrimitives; patchNdx++)
5498 		{
5499 			const bool discard = isPatchDiscarded(m_primitiveType, &attributes[numAttribsPerPrimitive*patchNdx + 2]);
5500 			DE_ASSERT(discard || !discardedPatchEncountered);
5501 			discardedPatchEncountered = discard;
5502 		}
5503 		DE_UNREF(discardedPatchEncountered);
5504 	}
5505 
5506 	{
5507 		int numVerticesInDrawCall = 0;
5508 		for (int patchNdx = 0; patchNdx < numPrimitives; patchNdx++)
5509 			numVerticesInDrawCall += referenceVertexCount(m_primitiveType, m_spacing, m_usePointMode, &attributes[numAttribsPerPrimitive*patchNdx+0], &attributes[numAttribsPerPrimitive*patchNdx+2]);
5510 
5511 		log << TestLog::Message << "Note: rendering " << numPrimitives << " patches; first patches have valid relevant outer levels, "
5512 								<< "but later patches have one or more invalid (i.e. less than or equal to 0.0) relevant outer levels" << TestLog::EndMessage;
5513 
5514 		{
5515 			const TFHandler					tfHandler	(m_context.getRenderContext(), numVerticesInDrawCall);
5516 			const glu::VertexArrayBinding	bindings[]	= { glu::va::Float("in_v_attr", 1, (int)attributes.size(), 0, &attributes[0]) };
5517 			const TFHandler::Result			tfResult	= tfHandler.renderAndGetPrimitives(programGL, outputPrimitiveTypeGL(m_primitiveType, m_usePointMode),
5518 																						   DE_LENGTH_OF_ARRAY(bindings), &bindings[0], (int)attributes.size());
5519 			const tcu::Surface				pixels		= getPixels(renderCtx, viewport);
5520 
5521 			log << TestLog::Image("RenderedImage", "Rendered image", pixels);
5522 
5523 			if ((int)tfResult.varying.size() != numVerticesInDrawCall)
5524 			{
5525 				log << TestLog::Message << "Failure: expected " << numVerticesInDrawCall << " vertices from transform feedback, got " << tfResult.varying.size() << TestLog::EndMessage;
5526 				m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Wrong number of tessellation coordinates");
5527 				return STOP;
5528 			}
5529 
5530 			// Check that white pixels are found around every non-discarded
5531 			// patch, and that only black pixels are found after the last
5532 			// non-discarded patch.
5533 			{
5534 				int lastWhitePixelRow									= 0;
5535 				int secondToLastWhitePixelRow							= 0;
5536 				int	lastWhitePixelColumnOnSecondToLastWhitePixelRow		= 0;
5537 
5538 				for (int patchNdx = 0; patchNdx < numPrimitives; patchNdx++)
5539 				{
5540 					const float* const	attr			= &attributes[numAttribsPerPrimitive*patchNdx];
5541 					const bool			validLevels		= !isPatchDiscarded(m_primitiveType, &attr[2]);
5542 
5543 					if (validLevels)
5544 					{
5545 						// Not a discarded patch; check that at least one white pixel is found in its area.
5546 
5547 						const float* const	scale		= &attr[6];
5548 						const float* const	offset		= &attr[8];
5549 						const int			x0			= (int)((			offset[0] + 1.0f)*0.5f*(float)pixels.getWidth()) - 1;
5550 						const int			x1			= (int)((scale[0] + offset[0] + 1.0f)*0.5f*(float)pixels.getWidth()) + 1;
5551 						const int			y0			= (int)((			offset[1] + 1.0f)*0.5f*(float)pixels.getHeight()) - 1;
5552 						const int			y1			= (int)((scale[1] + offset[1] + 1.0f)*0.5f*(float)pixels.getHeight()) + 1;
5553 						const bool			isMSAA		= renderCtx.getRenderTarget().getNumSamples() > 1;
5554 						bool				pixelOk		= false;
5555 
5556 						if (y1 > lastWhitePixelRow)
5557 						{
5558 							secondToLastWhitePixelRow	= lastWhitePixelRow;
5559 							lastWhitePixelRow			= y1;
5560 						}
5561 						lastWhitePixelColumnOnSecondToLastWhitePixelRow = x1;
5562 
5563 						for (int y = y0; y <= y1 && !pixelOk; y++)
5564 						for (int x = x0; x <= x1 && !pixelOk; x++)
5565 						{
5566 							if (!de::inBounds(x, 0, pixels.getWidth()) || !de::inBounds(y, 0, pixels.getHeight()))
5567 								continue;
5568 
5569 							if (isMSAA)
5570 							{
5571 								if (pixels.getPixel(x, y) != tcu::RGBA::black())
5572 									pixelOk = true;
5573 							}
5574 							else
5575 							{
5576 								if (pixels.getPixel(x, y) == tcu::RGBA::white())
5577 									pixelOk = true;
5578 							}
5579 						}
5580 
5581 						if (!pixelOk)
5582 						{
5583 							log << TestLog::Message << "Failure: expected at least one " << (isMSAA ? "non-black" : "white") << " pixel in the rectangle "
5584 													<< "[x0=" << x0 << ", y0=" << y0 << ", x1=" << x1 << ", y1=" << y1 << "]" << TestLog::EndMessage
5585 								<< TestLog::Message << "Note: the rectangle approximately corresponds to the patch with these tessellation levels: "
5586 													<< tessellationLevelsString(&attr[0], &attr[1]) << TestLog::EndMessage;
5587 							m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image verification failed");
5588 							return STOP;
5589 						}
5590 					}
5591 					else
5592 					{
5593 						// First discarded primitive patch; the remaining are guaranteed to be discarded ones as well.
5594 
5595 						for (int y = 0; y < pixels.getHeight(); y++)
5596 						for (int x = 0; x < pixels.getWidth(); x++)
5597 						{
5598 							if (y > lastWhitePixelRow || (y > secondToLastWhitePixelRow && x > lastWhitePixelColumnOnSecondToLastWhitePixelRow))
5599 							{
5600 								if (pixels.getPixel(x, y) != tcu::RGBA::black())
5601 								{
5602 									log << TestLog::Message << "Failure: expected all pixels to be black in the area "
5603 															<< (lastWhitePixelColumnOnSecondToLastWhitePixelRow < pixels.getWidth()-1
5604 																	? string() + "y > " + de::toString(lastWhitePixelRow) + " || (y > " + de::toString(secondToLastWhitePixelRow)
5605 																			   + " && x > " + de::toString(lastWhitePixelColumnOnSecondToLastWhitePixelRow) + ")"
5606 																	: string() + "y > " + de::toString(lastWhitePixelRow))
5607 															<< " (they all correspond to patches that should be discarded)" << TestLog::EndMessage
5608 										<< TestLog::Message << "Note: pixel " << tcu::IVec2(x, y) << " isn't black" << TestLog::EndMessage;
5609 									m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image verification failed");
5610 									return STOP;
5611 								}
5612 							}
5613 						}
5614 
5615 						break;
5616 					}
5617 				}
5618 			}
5619 		}
5620 	}
5621 
5622 	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
5623 	return STOP;
5624 }
5625 
5626 /*--------------------------------------------------------------------*//*!
5627  * \brief Case testing user-defined IO between TCS and TES
5628  *
5629  * TCS outputs various values to TES, including aggregates. The outputs
5630  * can be per-patch or per-vertex, and if per-vertex, they can also be in
5631  * an IO block. Per-vertex input array size can be left implicit (i.e.
5632  * inputArray[]) or explicit either by gl_MaxPatchVertices or an integer
5633  * literal whose value is queried from GL.
5634  *
5635  * The values output are generated in TCS and verified in TES against
5636  * similarly generated values. In case a verification of a value fails, the
5637  * index of the invalid value is output with TF.
5638  * As a sanity check, also the rendering result is verified (against pre-
5639  * rendered reference).
5640  *//*--------------------------------------------------------------------*/
5641 class UserDefinedIOCase : public TestCase
5642 {
5643 public:
5644 	enum IOType
5645 	{
5646 		IO_TYPE_PER_PATCH = 0,
5647 		IO_TYPE_PER_PATCH_ARRAY,
5648 		IO_TYPE_PER_PATCH_BLOCK,
5649 		IO_TYPE_PER_PATCH_BLOCK_ARRAY,
5650 		IO_TYPE_PER_VERTEX,
5651 		IO_TYPE_PER_VERTEX_BLOCK,
5652 
5653 		IO_TYPE_LAST
5654 	};
5655 
5656 	enum VertexIOArraySize
5657 	{
5658 		VERTEX_IO_ARRAY_SIZE_IMPLICIT = 0,
5659 		VERTEX_IO_ARRAY_SIZE_EXPLICIT_SHADER_BUILTIN,		//!< Use gl_MaxPatchVertices as size for per-vertex input array.
5660 		VERTEX_IO_ARRAY_SIZE_EXPLICIT_QUERY,				//!< Query GL_MAX_PATCH_VERTICES, and use that as size for per-vertex input array.
5661 
5662 		VERTEX_IO_ARRAY_SIZE_LAST
5663 	};
5664 
5665 	enum TessControlOutArraySize
5666 	{
5667 		TESS_CONTROL_OUT_ARRAY_SIZE_IMPLICIT = 0,
5668 		TESS_CONTROL_OUT_ARRAY_SIZE_LAYOUT,
5669 		TESS_CONTROL_OUT_ARRAY_SIZE_QUERY,
5670 		TESS_CONTROL_OUT_ARRAY_SIZE_SHADER_BUILTIN
5671 	};
5672 
UserDefinedIOCase(Context & context,const char * name,const char * description,TessPrimitiveType primType,IOType ioType,VertexIOArraySize vertexIOArraySize,TessControlOutArraySize tessControlOutArraySize,const char * referenceImagePath)5673 	UserDefinedIOCase (Context& context, const char* name, const char* description, TessPrimitiveType primType, IOType ioType, VertexIOArraySize vertexIOArraySize, TessControlOutArraySize tessControlOutArraySize, const char* referenceImagePath)
5674 		: TestCase					(context, name, description)
5675 		, m_primitiveType			(primType)
5676 		, m_ioType					(ioType)
5677 		, m_vertexIOArraySize		(vertexIOArraySize)
5678 		, m_tessControlOutArraySize	(tessControlOutArraySize)
5679 		, m_referenceImagePath		(referenceImagePath)
5680 	{
5681 	}
5682 
5683 	void									init		(void);
5684 	void									deinit		(void);
5685 	IterateResult							iterate		(void);
5686 
5687 private:
5688 	typedef string (*BasicTypeVisitFunc)(const string& name, glu::DataType type, int indentationDepth); //!< See glslTraverseBasicTypes below.
5689 
5690 	class TopLevelObject
5691 	{
5692 	public:
~TopLevelObject(void)5693 		virtual			~TopLevelObject					(void) {}
5694 
5695 		virtual string	name							(void) const = 0;
5696 		virtual string	declare							(void) const = 0;
5697 		virtual string	declareArray					(const string& arraySizeExpr) const = 0;
5698 		virtual string	glslTraverseBasicTypeArray		(int numArrayElements, //!< If negative, traverse just array[gl_InvocationID], not all indices.
5699 														 int indentationDepth,
5700 														 BasicTypeVisitFunc) const = 0;
5701 		virtual string	glslTraverseBasicType			(int indentationDepth,
5702 														 BasicTypeVisitFunc) const = 0;
5703 		virtual int		numBasicSubobjectsInElementType	(void) const = 0;
5704 		virtual string	basicSubobjectAtIndex			(int index, int arraySize) const = 0;
5705 	};
5706 
5707 	class Variable : public TopLevelObject
5708 	{
5709 	public:
Variable(const string & name_,const glu::VarType & type,bool isArray)5710 		Variable (const string& name_, const glu::VarType& type, bool isArray)
5711 			: m_name		(name_)
5712 			, m_type		(type)
5713 			, m_isArray		(isArray)
5714 		{
5715 			DE_ASSERT(!type.isArrayType());
5716 		}
5717 
name(void) const5718 		string	name								(void) const { return m_name; }
5719 		string	declare								(void) const;
5720 		string	declareArray						(const string& arraySizeExpr) const;
5721 		string	glslTraverseBasicTypeArray			(int numArrayElements, int indentationDepth, BasicTypeVisitFunc) const;
5722 		string	glslTraverseBasicType				(int indentationDepth, BasicTypeVisitFunc) const;
5723 		int		numBasicSubobjectsInElementType		(void) const;
5724 		string	basicSubobjectAtIndex				(int index, int arraySize) const;
5725 
5726 	private:
5727 		string			m_name;
5728 		glu::VarType	m_type; //!< If this Variable is an array element, m_type is the element type; otherwise just the variable type.
5729 		const bool		m_isArray;
5730 	};
5731 
5732 	class IOBlock : public TopLevelObject
5733 	{
5734 	public:
5735 		struct Member
5736 		{
5737 			string			name;
5738 			glu::VarType	type;
Memberdeqp::gles31::Functional::__anon755cd4500211::UserDefinedIOCase::IOBlock::Member5739 			Member (const string& n, const glu::VarType& t) : name(n), type(t) {}
5740 		};
5741 
IOBlock(const string & blockName,const string & interfaceName,const vector<Member> & members)5742 		IOBlock (const string& blockName, const string& interfaceName, const vector<Member>& members)
5743 			: m_blockName		(blockName)
5744 			, m_interfaceName	(interfaceName)
5745 			, m_members			(members)
5746 		{
5747 		}
5748 
name(void) const5749 		string	name								(void) const { return m_interfaceName; }
5750 		string	declare								(void) const;
5751 		string	declareArray						(const string& arraySizeExpr) const;
5752 		string	glslTraverseBasicTypeArray			(int numArrayElements, int indentationDepth, BasicTypeVisitFunc) const;
5753 		string	glslTraverseBasicType				(int indentationDepth, BasicTypeVisitFunc) const;
5754 		int		numBasicSubobjectsInElementType		(void) const;
5755 		string	basicSubobjectAtIndex				(int index, int arraySize) const;
5756 
5757 	private:
5758 		string			m_blockName;
5759 		string			m_interfaceName;
5760 		vector<Member>	m_members;
5761 	};
5762 
5763 	static string							glslTraverseBasicTypes				(const string&			rootName,
5764 																				 const glu::VarType&	rootType,
5765 																				 int					arrayNestingDepth,
5766 																				 int					indentationDepth,
5767 																				 BasicTypeVisitFunc		visit);
5768 
5769 	static string							glslAssignBasicTypeObject			(const string& name, glu::DataType, int indentationDepth);
5770 	static string							glslCheckBasicTypeObject			(const string& name, glu::DataType, int indentationDepth);
5771 	static int								numBasicSubobjectsInElementType		(const vector<SharedPtr<TopLevelObject> >&);
5772 	static string							basicSubobjectAtIndex				(int index, const vector<SharedPtr<TopLevelObject> >&, int topLevelArraySizes);
5773 
5774 	enum
5775 	{
5776 		RENDER_SIZE = 256
5777 	};
5778 	enum
5779 	{
5780 		NUM_OUTPUT_VERTICES = 5
5781 	};
5782 	enum
5783 	{
5784 		NUM_PER_PATCH_ARRAY_ELEMS = 3
5785 	};
5786 	enum
5787 	{
5788 		NUM_PER_PATCH_BLOCKS = 2
5789 	};
5790 
5791 	const TessPrimitiveType					m_primitiveType;
5792 	const IOType							m_ioType;
5793 	const VertexIOArraySize					m_vertexIOArraySize;
5794 	const TessControlOutArraySize			m_tessControlOutArraySize;
5795 	const string							m_referenceImagePath;
5796 
5797 	vector<glu::StructType>					m_structTypes;
5798 	vector<SharedPtr<TopLevelObject> >		m_tcsOutputs;
5799 	vector<SharedPtr<TopLevelObject> >		m_tesInputs;
5800 
5801 	SharedPtr<const glu::ShaderProgram>		m_program;
5802 };
5803 
5804 /*--------------------------------------------------------------------*//*!
5805  * \brief Generate GLSL code to traverse (possibly aggregate) object
5806  *
5807  * Generates a string that represents GLSL code that traverses the
5808  * basic-type subobjects in a rootType-typed object named rootName. Arrays
5809  * are traversed with loops and struct members are each traversed
5810  * separately. The code for each basic-type subobject is generated with
5811  * the function given as the 'visit' argument.
5812  *//*--------------------------------------------------------------------*/
glslTraverseBasicTypes(const string & rootName,const glu::VarType & rootType,int arrayNestingDepth,int indentationDepth,BasicTypeVisitFunc visit)5813 string UserDefinedIOCase::glslTraverseBasicTypes (const string&			rootName,
5814 												  const glu::VarType&	rootType,
5815 												  int					arrayNestingDepth,
5816 												  int					indentationDepth,
5817 												  BasicTypeVisitFunc	visit)
5818 {
5819 	if (rootType.isBasicType())
5820 		return visit(rootName, rootType.getBasicType(), indentationDepth);
5821 	else if (rootType.isArrayType())
5822 	{
5823 		const string indentation	= string(indentationDepth, '\t');
5824 		const string loopIndexName	= "i" + de::toString(arrayNestingDepth);
5825 		const string arrayLength	= de::toString(rootType.getArraySize());
5826 		return indentation + "for (int " + loopIndexName + " = 0; " + loopIndexName + " < " + de::toString(rootType.getArraySize()) + "; " + loopIndexName + "++)\n" +
5827 			   indentation + "{\n" +
5828 			   glslTraverseBasicTypes(rootName + "[" + loopIndexName + "]", rootType.getElementType(), arrayNestingDepth+1, indentationDepth+1, visit) +
5829 			   indentation + "}\n";
5830 	}
5831 	else if (rootType.isStructType())
5832 	{
5833 		const glu::StructType&	structType = *rootType.getStructPtr();
5834 		const int				numMembers = structType.getNumMembers();
5835 		string					result;
5836 
5837 		for (int membNdx = 0; membNdx < numMembers; membNdx++)
5838 		{
5839 			const glu::StructMember& member = structType.getMember(membNdx);
5840 			result += glslTraverseBasicTypes(rootName + "." + member.getName(), member.getType(), arrayNestingDepth, indentationDepth, visit);
5841 		}
5842 
5843 		return result;
5844 	}
5845 	else
5846 	{
5847 		DE_ASSERT(false);
5848 		return DE_NULL;
5849 	}
5850 }
5851 
declare(void) const5852 string UserDefinedIOCase::Variable::declare (void) const
5853 {
5854 	DE_ASSERT(!m_isArray);
5855 	return de::toString(glu::declare(m_type, m_name)) + ";\n";
5856 }
5857 
declareArray(const string & sizeExpr) const5858 string UserDefinedIOCase::Variable::declareArray (const string& sizeExpr) const
5859 {
5860 	DE_ASSERT(m_isArray);
5861 	return de::toString(glu::declare(m_type, m_name)) + "[" + sizeExpr + "];\n";
5862 }
5863 
declare(void) const5864 string UserDefinedIOCase::IOBlock::declare (void) const
5865 {
5866 	std::ostringstream buf;
5867 
5868 	buf << m_blockName << "\n"
5869 		<< "{\n";
5870 
5871 	for (int i = 0; i < (int)m_members.size(); i++)
5872 		buf << "\t" << glu::declare(m_members[i].type, m_members[i].name) << ";\n";
5873 
5874 	buf << "} " << m_interfaceName << ";\n";
5875 	return buf.str();
5876 }
5877 
declareArray(const string & sizeExpr) const5878 string UserDefinedIOCase::IOBlock::declareArray (const string& sizeExpr) const
5879 {
5880 	std::ostringstream buf;
5881 
5882 	buf << m_blockName << "\n"
5883 		<< "{\n";
5884 
5885 	for (int i = 0; i < (int)m_members.size(); i++)
5886 		buf << "\t" << glu::declare(m_members[i].type, m_members[i].name) << ";\n";
5887 
5888 	buf << "} " << m_interfaceName << "[" << sizeExpr << "];\n";
5889 	return buf.str();
5890 }
5891 
glslTraverseBasicTypeArray(int numArrayElements,int indentationDepth,BasicTypeVisitFunc visit) const5892 string UserDefinedIOCase::Variable::glslTraverseBasicTypeArray (int numArrayElements, int indentationDepth, BasicTypeVisitFunc visit) const
5893 {
5894 	DE_ASSERT(m_isArray);
5895 
5896 	const bool				traverseAsArray		= numArrayElements >= 0;
5897 	const string			traversedName		= m_name + (!traverseAsArray ? "[gl_InvocationID]" : "");
5898 	const glu::VarType		type				= traverseAsArray ? glu::VarType(m_type, numArrayElements) : m_type;
5899 
5900 	return UserDefinedIOCase::glslTraverseBasicTypes(traversedName, type, 0, indentationDepth, visit);
5901 }
5902 
glslTraverseBasicType(int indentationDepth,BasicTypeVisitFunc visit) const5903 string UserDefinedIOCase::Variable::glslTraverseBasicType (int indentationDepth, BasicTypeVisitFunc visit) const
5904 {
5905 	DE_ASSERT(!m_isArray);
5906 
5907 	return UserDefinedIOCase::glslTraverseBasicTypes(m_name, m_type, 0, indentationDepth, visit);
5908 }
5909 
glslTraverseBasicTypeArray(int numArrayElements,int indentationDepth,BasicTypeVisitFunc visit) const5910 string UserDefinedIOCase::IOBlock::glslTraverseBasicTypeArray (int numArrayElements, int indentationDepth, BasicTypeVisitFunc visit) const
5911 {
5912 	if (numArrayElements >= 0)
5913 	{
5914 		const string	indentation			= string(indentationDepth, '\t');
5915 		string			result				= indentation + "for (int i0 = 0; i0 < " + de::toString(numArrayElements) + "; i0++)\n" +
5916 											  indentation + "{\n";
5917 		for (int i = 0; i < (int)m_members.size(); i++)
5918 			result += UserDefinedIOCase::glslTraverseBasicTypes(m_interfaceName + "[i0]." + m_members[i].name, m_members[i].type, 1, indentationDepth+1, visit);
5919 		result += indentation + "}\n";
5920 		return result;
5921 	}
5922 	else
5923 	{
5924 		string result;
5925 		for (int i = 0; i < (int)m_members.size(); i++)
5926 			result += UserDefinedIOCase::glslTraverseBasicTypes(m_interfaceName + "[gl_InvocationID]." + m_members[i].name, m_members[i].type, 0, indentationDepth, visit);
5927 		return result;
5928 	}
5929 }
5930 
5931 
glslTraverseBasicType(int indentationDepth,BasicTypeVisitFunc visit) const5932 string UserDefinedIOCase::IOBlock::glslTraverseBasicType (int indentationDepth, BasicTypeVisitFunc visit) const
5933 {
5934 	string result;
5935 	for (int i = 0; i < (int)m_members.size(); i++)
5936 		result += UserDefinedIOCase::glslTraverseBasicTypes(m_interfaceName + "." + m_members[i].name, m_members[i].type, 0, indentationDepth, visit);
5937 	return result;
5938 }
5939 
numBasicSubobjectsInElementType(void) const5940 int UserDefinedIOCase::Variable::numBasicSubobjectsInElementType (void) const
5941 {
5942 	return numBasicSubobjects(m_type);
5943 }
5944 
numBasicSubobjectsInElementType(void) const5945 int UserDefinedIOCase::IOBlock::numBasicSubobjectsInElementType (void) const
5946 {
5947 	int result = 0;
5948 	for (int i = 0; i < (int)m_members.size(); i++)
5949 		result += numBasicSubobjects(m_members[i].type);
5950 	return result;
5951 }
5952 
basicSubobjectAtIndex(int subobjectIndex,int arraySize) const5953 string UserDefinedIOCase::Variable::basicSubobjectAtIndex (int subobjectIndex, int arraySize) const
5954 {
5955 	const glu::VarType	type			= m_isArray ? glu::VarType(m_type, arraySize) : m_type;
5956 	int					currentIndex	= 0;
5957 
5958 	for (glu::BasicTypeIterator basicIt = glu::BasicTypeIterator::begin(&type);
5959 		 basicIt != glu::BasicTypeIterator::end(&type);
5960 		 ++basicIt)
5961 	{
5962 		if (currentIndex == subobjectIndex)
5963 			return m_name + de::toString(glu::TypeAccessFormat(type, basicIt.getPath()));
5964 		currentIndex++;
5965 	}
5966 	DE_ASSERT(false);
5967 	return DE_NULL;
5968 }
5969 
basicSubobjectAtIndex(int subobjectIndex,int arraySize) const5970 string UserDefinedIOCase::IOBlock::basicSubobjectAtIndex (int subobjectIndex, int arraySize) const
5971 {
5972 	int currentIndex = 0;
5973 	for (int arrayNdx = 0; arrayNdx < arraySize; arrayNdx++)
5974 	{
5975 		for (int memberNdx = 0; memberNdx < (int)m_members.size(); memberNdx++)
5976 		{
5977 			const glu::VarType& membType = m_members[memberNdx].type;
5978 			for (glu::BasicTypeIterator basicIt = glu::BasicTypeIterator::begin(&membType);
5979 				 basicIt != glu::BasicTypeIterator::end(&membType);
5980 				 ++basicIt)
5981 			{
5982 				if (currentIndex == subobjectIndex)
5983 					return m_interfaceName + "[" + de::toString(arrayNdx) + "]." + m_members[memberNdx].name + de::toString(glu::TypeAccessFormat(membType, basicIt.getPath()));
5984 				currentIndex++;
5985 			}
5986 		}
5987 	}
5988 	DE_ASSERT(false);
5989 	return DE_NULL;
5990 }
5991 
5992 // Used as the 'visit' argument for glslTraverseBasicTypes.
glslAssignBasicTypeObject(const string & name,glu::DataType type,int indentationDepth)5993 string UserDefinedIOCase::glslAssignBasicTypeObject (const string& name, glu::DataType type, int indentationDepth)
5994 {
5995 	const int		scalarSize		= glu::getDataTypeScalarSize(type);
5996 	const string	indentation		= string(indentationDepth, '\t');
5997 	string			result;
5998 
5999 	result += indentation + name + " = ";
6000 
6001 	if (type != glu::TYPE_FLOAT)
6002 		result += string() + glu::getDataTypeName(type) + "(";
6003 	for (int i = 0; i < scalarSize; i++)
6004 		result += (i > 0 ? ", v+" + de::floatToString(0.8f*(float)i, 1)
6005 						 : "v");
6006 	if (type != glu::TYPE_FLOAT)
6007 		result += ")";
6008 	result += ";\n" +
6009 			  indentation + "v += 0.4;\n";
6010 	return result;
6011 }
6012 
6013 // Used as the 'visit' argument for glslTraverseBasicTypes.
glslCheckBasicTypeObject(const string & name,glu::DataType type,int indentationDepth)6014 string UserDefinedIOCase::glslCheckBasicTypeObject (const string& name, glu::DataType type, int indentationDepth)
6015 {
6016 	const int		scalarSize		= glu::getDataTypeScalarSize(type);
6017 	const string	indentation		= string(indentationDepth, '\t');
6018 	string			result;
6019 
6020 	result += indentation + "allOk = allOk && compare_" + glu::getDataTypeName(type) + "(" + name + ", ";
6021 
6022 	if (type != glu::TYPE_FLOAT)
6023 		result += string() + glu::getDataTypeName(type) + "(";
6024 	for (int i = 0; i < scalarSize; i++)
6025 		result += (i > 0 ? ", v+" + de::floatToString(0.8f*(float)i, 1)
6026 						 : "v");
6027 	if (type != glu::TYPE_FLOAT)
6028 		result += ")";
6029 	result += ");\n" +
6030 			  indentation + "v += 0.4;\n" +
6031 			  indentation + "if (allOk) firstFailedInputIndex++;\n";
6032 
6033 	return result;
6034 }
6035 
numBasicSubobjectsInElementType(const vector<SharedPtr<TopLevelObject>> & objects)6036 int UserDefinedIOCase::numBasicSubobjectsInElementType (const vector<SharedPtr<TopLevelObject> >& objects)
6037 {
6038 	int result = 0;
6039 	for (int i = 0; i < (int)objects.size(); i++)
6040 		result += objects[i]->numBasicSubobjectsInElementType();
6041 	return result;
6042 }
6043 
basicSubobjectAtIndex(int subobjectIndex,const vector<SharedPtr<TopLevelObject>> & objects,int topLevelArraySize)6044 string UserDefinedIOCase::basicSubobjectAtIndex (int subobjectIndex, const vector<SharedPtr<TopLevelObject> >& objects, int topLevelArraySize)
6045 {
6046 	int currentIndex	= 0;
6047 	int objectIndex		= 0;
6048 	for (; currentIndex < subobjectIndex; objectIndex++)
6049 		currentIndex += objects[objectIndex]->numBasicSubobjectsInElementType() * topLevelArraySize;
6050 	if (currentIndex > subobjectIndex)
6051 	{
6052 		objectIndex--;
6053 		currentIndex -= objects[objectIndex]->numBasicSubobjectsInElementType() * topLevelArraySize;
6054 	}
6055 
6056 	return objects[objectIndex]->basicSubobjectAtIndex(subobjectIndex - currentIndex, topLevelArraySize);
6057 }
6058 
init(void)6059 void UserDefinedIOCase::init (void)
6060 {
6061 	checkTessellationSupport(m_context);
6062 	checkRenderTargetSize(m_context.getRenderTarget(), RENDER_SIZE);
6063 
6064 	const bool			isPerPatchIO				= m_ioType == IO_TYPE_PER_PATCH				||
6065 													  m_ioType == IO_TYPE_PER_PATCH_ARRAY		||
6066 													  m_ioType == IO_TYPE_PER_PATCH_BLOCK		||
6067 													  m_ioType == IO_TYPE_PER_PATCH_BLOCK_ARRAY;
6068 
6069 	const bool			isExplicitVertexArraySize	= m_vertexIOArraySize == VERTEX_IO_ARRAY_SIZE_EXPLICIT_SHADER_BUILTIN ||
6070 													  m_vertexIOArraySize == VERTEX_IO_ARRAY_SIZE_EXPLICIT_QUERY;
6071 
6072 	const string		vertexAttrArrayInputSize	= m_vertexIOArraySize == VERTEX_IO_ARRAY_SIZE_IMPLICIT					? ""
6073 													: m_vertexIOArraySize == VERTEX_IO_ARRAY_SIZE_EXPLICIT_SHADER_BUILTIN	? "gl_MaxPatchVertices"
6074 													: m_vertexIOArraySize == VERTEX_IO_ARRAY_SIZE_EXPLICIT_QUERY			? de::toString(m_context.getContextInfo().getInt(GL_MAX_PATCH_VERTICES))
6075 													: DE_NULL;
6076 
6077 	const char* const	maybePatch					= isPerPatchIO ? "patch " : "";
6078 	const string		outMaybePatch				= string() + maybePatch + "out ";
6079 	const string		inMaybePatch				= string() + maybePatch + "in ";
6080 	const bool			useBlock					= m_ioType == IO_TYPE_PER_VERTEX_BLOCK		||
6081 													  m_ioType == IO_TYPE_PER_PATCH_BLOCK		||
6082 													  m_ioType == IO_TYPE_PER_PATCH_BLOCK_ARRAY;
6083 
6084 	string				tcsDeclarations;
6085 	string				tcsStatements;
6086 
6087 	string				tesDeclarations;
6088 	string				tesStatements;
6089 
6090 	{
6091 		m_structTypes.push_back(glu::StructType("S"));
6092 
6093 		const glu::VarType	highpFloat		(glu::TYPE_FLOAT, glu::PRECISION_HIGHP);
6094 		glu::StructType&	structType		= m_structTypes.back();
6095 		const glu::VarType	structVarType	(&structType);
6096 		bool				usedStruct		= false;
6097 
6098 		structType.addMember("x", glu::VarType(glu::TYPE_INT, glu::PRECISION_HIGHP));
6099 		structType.addMember("y", glu::VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_HIGHP));
6100 
6101 		if (useBlock)
6102 		{
6103 			// It is illegal to have a structure containing an array as an output variable
6104 			structType.addMember("z", glu::VarType(highpFloat, 2));
6105 		}
6106 
6107 		if (useBlock)
6108 		{
6109 			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)
6110 			vector<IOBlock::Member>	blockMembers;
6111 
6112 			if (!useLightweightBlock)
6113 				blockMembers.push_back(IOBlock::Member("blockS",	structVarType));
6114 
6115 			blockMembers.push_back(IOBlock::Member("blockFa",	glu::VarType(highpFloat, 3)));
6116 			blockMembers.push_back(IOBlock::Member("blockSa",	glu::VarType(structVarType, 2)));
6117 			blockMembers.push_back(IOBlock::Member("blockF",	highpFloat));
6118 
6119 			m_tcsOutputs.push_back	(SharedPtr<TopLevelObject>(new IOBlock("TheBlock", "tcBlock", blockMembers)));
6120 			m_tesInputs.push_back	(SharedPtr<TopLevelObject>(new IOBlock("TheBlock", "teBlock", blockMembers)));
6121 
6122 			usedStruct = true;
6123 		}
6124 		else
6125 		{
6126 			const Variable var0("in_te_s", structVarType,	m_ioType != IO_TYPE_PER_PATCH);
6127 			const Variable var1("in_te_f", highpFloat,		m_ioType != IO_TYPE_PER_PATCH);
6128 
6129 			if (m_ioType != IO_TYPE_PER_PATCH_ARRAY)
6130 			{
6131 				// Arrays of structures are disallowed, add struct cases only if not arrayed variable
6132 				m_tcsOutputs.push_back	(SharedPtr<TopLevelObject>(new Variable(var0)));
6133 				m_tesInputs.push_back	(SharedPtr<TopLevelObject>(new Variable(var0)));
6134 
6135 				usedStruct = true;
6136 			}
6137 
6138 			m_tcsOutputs.push_back	(SharedPtr<TopLevelObject>(new Variable(var1)));
6139 			m_tesInputs.push_back	(SharedPtr<TopLevelObject>(new Variable(var1)));
6140 		}
6141 
6142 		tcsDeclarations += "in " + Variable("in_tc_attr", highpFloat, true).declareArray(vertexAttrArrayInputSize);
6143 
6144 		if (usedStruct)
6145 			tcsDeclarations += de::toString(glu::declare(structType)) + ";\n";
6146 
6147 		tcsStatements += "\t{\n"
6148 						 "\t\thighp float v = 1.3;\n";
6149 
6150 		for (int tcsOutputNdx = 0; tcsOutputNdx < (int)m_tcsOutputs.size(); tcsOutputNdx++)
6151 		{
6152 			const TopLevelObject&	output		= *m_tcsOutputs[tcsOutputNdx];
6153 			const int				numElements	= !isPerPatchIO								? -1	//!< \note -1 means indexing with gl_InstanceID
6154 												: m_ioType == IO_TYPE_PER_PATCH				? 1
6155 												: m_ioType == IO_TYPE_PER_PATCH_ARRAY		? NUM_PER_PATCH_ARRAY_ELEMS
6156 												: m_ioType == IO_TYPE_PER_PATCH_BLOCK		? 1
6157 												: m_ioType == IO_TYPE_PER_PATCH_BLOCK_ARRAY	? NUM_PER_PATCH_BLOCKS
6158 												: -2;
6159 			const bool				isArray		= (numElements != 1);
6160 
6161 			DE_ASSERT(numElements != -2);
6162 
6163 			if (isArray)
6164 			{
6165 				tcsDeclarations += outMaybePatch + output.declareArray(m_ioType == IO_TYPE_PER_PATCH_ARRAY											? de::toString(int(NUM_PER_PATCH_ARRAY_ELEMS))
6166 																	   : m_ioType == IO_TYPE_PER_PATCH_BLOCK_ARRAY									? de::toString(int(NUM_PER_PATCH_BLOCKS))
6167 																	   : m_tessControlOutArraySize == TESS_CONTROL_OUT_ARRAY_SIZE_LAYOUT			? de::toString(int(NUM_OUTPUT_VERTICES))
6168 																	   : m_tessControlOutArraySize == TESS_CONTROL_OUT_ARRAY_SIZE_QUERY				? de::toString(m_context.getContextInfo().getInt(GL_MAX_PATCH_VERTICES))
6169 																	   : m_tessControlOutArraySize == TESS_CONTROL_OUT_ARRAY_SIZE_SHADER_BUILTIN	? "gl_MaxPatchVertices"
6170 																	   : "");
6171 			}
6172 			else
6173 				tcsDeclarations += outMaybePatch + output.declare();
6174 
6175 			if (!isPerPatchIO)
6176 				tcsStatements += "\t\tv += float(gl_InvocationID)*" + de::floatToString(0.4f * (float)output.numBasicSubobjectsInElementType(), 1) + ";\n";
6177 
6178 			tcsStatements += "\n\t\t// Assign values to output " + output.name() + "\n";
6179 			if (isArray)
6180 				tcsStatements += output.glslTraverseBasicTypeArray(numElements, 2, glslAssignBasicTypeObject);
6181 			else
6182 				tcsStatements += output.glslTraverseBasicType(2, glslAssignBasicTypeObject);
6183 
6184 			if (!isPerPatchIO)
6185 				tcsStatements += "\t\tv += float(" + de::toString(int(NUM_OUTPUT_VERTICES)) + "-gl_InvocationID-1)*" + de::floatToString(0.4f * (float)output.numBasicSubobjectsInElementType(), 1) + ";\n";
6186 		}
6187 		tcsStatements += "\t}\n";
6188 
6189 		if (usedStruct)
6190 			tesDeclarations += de::toString(glu::declare(structType)) + ";\n";
6191 
6192 		tesStatements += "\tbool allOk = true;\n"
6193 						 "\thighp uint firstFailedInputIndex = 0u;\n"
6194 						 "\t{\n"
6195 						 "\t\thighp float v = 1.3;\n";
6196 		for (int tesInputNdx = 0; tesInputNdx < (int)m_tesInputs.size(); tesInputNdx++)
6197 		{
6198 			const TopLevelObject&	input		= *m_tesInputs[tesInputNdx];
6199 			const int				numElements	= !isPerPatchIO								? (int)NUM_OUTPUT_VERTICES
6200 												: m_ioType == IO_TYPE_PER_PATCH				? 1
6201 												: m_ioType == IO_TYPE_PER_PATCH_BLOCK		? 1
6202 												: m_ioType == IO_TYPE_PER_PATCH_ARRAY		? NUM_PER_PATCH_ARRAY_ELEMS
6203 												: m_ioType == IO_TYPE_PER_PATCH_BLOCK_ARRAY	? NUM_PER_PATCH_BLOCKS
6204 												: -2;
6205 			const bool				isArray		= (numElements != 1);
6206 
6207 			DE_ASSERT(numElements != -2);
6208 
6209 			if (isArray)
6210 				tesDeclarations += inMaybePatch + input.declareArray(m_ioType == IO_TYPE_PER_PATCH_ARRAY			? de::toString(int(NUM_PER_PATCH_ARRAY_ELEMS))
6211 																	 : m_ioType == IO_TYPE_PER_PATCH_BLOCK_ARRAY	? de::toString(int(NUM_PER_PATCH_BLOCKS))
6212 																	 : isExplicitVertexArraySize					? de::toString(vertexAttrArrayInputSize)
6213 																	 : "");
6214 			else
6215 				tesDeclarations += inMaybePatch + input.declare();
6216 
6217 			tesStatements += "\n\t\t// Check values in input " + input.name() + "\n";
6218 			if (isArray)
6219 				tesStatements += input.glslTraverseBasicTypeArray(numElements, 2, glslCheckBasicTypeObject);
6220 			else
6221 				tesStatements += input.glslTraverseBasicType(2, glslCheckBasicTypeObject);
6222 		}
6223 		tesStatements += "\t}\n";
6224 	}
6225 
6226 	std::string vertexShaderTemplate			("${GLSL_VERSION_DECL}\n"
6227 												 "${GLSL_PER_VERTEX_OUT}\n"
6228 												 "\n"
6229 												 "in highp float in_v_attr;\n"
6230 												 "out highp float in_tc_attr;\n"
6231 												 "\n"
6232 												 "void main (void)\n"
6233 												 "{\n"
6234 												 "	in_tc_attr = in_v_attr;\n"
6235 												 "}\n");
6236 	std::string tessellationControlTemplate		("${GLSL_VERSION_DECL}\n"
6237 												 "${TESSELLATION_SHADER_REQUIRE}\n"
6238 												 "${GLSL_PER_VERTEX_IN_ARR}\n"
6239 												 "${GLSL_PER_VERTEX_OUT_ARR}\n"
6240 												 "\n"
6241 												 "layout (vertices = " + de::toString(int(NUM_OUTPUT_VERTICES)) + ") out;\n"
6242 												 "\n"
6243 												 + tcsDeclarations +
6244 												 "\n"
6245 												 "patch out highp vec2 in_te_positionScale;\n"
6246 												 "patch out highp vec2 in_te_positionOffset;\n"
6247 												 "\n"
6248 												 "void main (void)\n"
6249 												 "{\n"
6250 												 + tcsStatements +
6251 												 "\n"
6252 												 "	in_te_positionScale  = vec2(in_tc_attr[6], in_tc_attr[7]);\n"
6253 												 "	in_te_positionOffset = vec2(in_tc_attr[8], in_tc_attr[9]);\n"
6254 												 "\n"
6255 												 "	gl_TessLevelInner[0] = in_tc_attr[0];\n"
6256 												 "	gl_TessLevelInner[1] = in_tc_attr[1];\n"
6257 												 "\n"
6258 												 "	gl_TessLevelOuter[0] = in_tc_attr[2];\n"
6259 												 "	gl_TessLevelOuter[1] = in_tc_attr[3];\n"
6260 												 "	gl_TessLevelOuter[2] = in_tc_attr[4];\n"
6261 												 "	gl_TessLevelOuter[3] = in_tc_attr[5];\n"
6262 												 "}\n");
6263 	std::string tessellationEvaluationTemplate	("${GLSL_VERSION_DECL}\n"
6264 												 "${TESSELLATION_SHADER_REQUIRE}\n"
6265 												 "${GLSL_PER_VERTEX_IN_ARR}\n"
6266 												 "${GLSL_PER_VERTEX_OUT}\n"
6267 												 "\n"
6268 												 + getTessellationEvaluationInLayoutString(m_primitiveType) +
6269 												 "\n"
6270 												 + tesDeclarations +
6271 												 "\n"
6272 												 "patch in highp vec2 in_te_positionScale;\n"
6273 												 "patch in highp vec2 in_te_positionOffset;\n"
6274 												 "\n"
6275 												 "out highp vec4 in_f_color;\n"
6276 												 "// Will contain the index of the first incorrect input,\n"
6277 												 "// or the number of inputs if all are correct\n"
6278 												 "flat out highp uint out_te_firstFailedInputIndex;\n"
6279 												 "\n"
6280 												 "bool compare_int   (int   a, int   b) { return a == b; }\n"
6281 												 "bool compare_float (float a, float b) { return abs(a - b) < 0.01f; }\n"
6282 												 "bool compare_vec4  (vec4  a, vec4  b) { return all(lessThan(abs(a - b), vec4(0.01f))); }\n"
6283 												 "\n"
6284 												 "void main (void)\n"
6285 												 "{\n"
6286 												 + tesStatements +
6287 												 "\n"
6288 												 "	gl_Position = vec4(gl_TessCoord.xy*in_te_positionScale + in_te_positionOffset, 0.0, 1.0);\n"
6289 												 "	in_f_color = allOk ? vec4(0.0, 1.0, 0.0, 1.0)\n"
6290 												 "	                   : vec4(1.0, 0.0, 0.0, 1.0);\n"
6291 												 "	out_te_firstFailedInputIndex = firstFailedInputIndex;\n"
6292 												 "}\n");
6293 	std::string fragmentShaderTemplate			("${GLSL_VERSION_DECL}\n"
6294 												 "\n"
6295 												 "layout (location = 0) out mediump vec4 o_color;\n"
6296 												 "\n"
6297 												 "in highp vec4 in_f_color;\n"
6298 												 "\n"
6299 												 "void main (void)\n"
6300 												 "{\n"
6301 												 "	o_color = in_f_color;\n"
6302 												 "}\n");
6303 
6304 	m_program = SharedPtr<const ShaderProgram>(new ShaderProgram(m_context.getRenderContext(), glu::ProgramSources()
6305 		<< glu::VertexSource					(specializeShader(m_context, vertexShaderTemplate.c_str()))
6306 		<< glu::TessellationControlSource		(specializeShader(m_context, tessellationControlTemplate.c_str()))
6307 		<< glu::TessellationEvaluationSource	(specializeShader(m_context, tessellationEvaluationTemplate.c_str()))
6308 		<< glu::FragmentSource					(specializeShader(m_context, fragmentShaderTemplate.c_str()))
6309 		<< glu::TransformFeedbackVarying		("out_te_firstFailedInputIndex")
6310 		<< glu::TransformFeedbackMode			(GL_INTERLEAVED_ATTRIBS)));
6311 
6312 	m_testCtx.getLog() << *m_program;
6313 	if (!m_program->isOk())
6314 		TCU_FAIL("Program compilation failed");
6315 }
6316 
deinit(void)6317 void UserDefinedIOCase::deinit (void)
6318 {
6319 	m_program.clear();
6320 }
6321 
iterate(void)6322 UserDefinedIOCase::IterateResult UserDefinedIOCase::iterate (void)
6323 {
6324 	typedef TransformFeedbackHandler<deUint32> TFHandler;
6325 
6326 	TestLog&				log						= m_testCtx.getLog();
6327 	const RenderContext&	renderCtx				= m_context.getRenderContext();
6328 	const RandomViewport	viewport				(renderCtx.getRenderTarget(), RENDER_SIZE, RENDER_SIZE, deStringHash(getName()));
6329 	const glw::Functions&	gl						= renderCtx.getFunctions();
6330 	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 };
6331 	const deUint32			programGL				= m_program->getProgram();
6332 	const int				numVertices				= referenceVertexCount(m_primitiveType, SPACINGMODE_EQUAL, false, &attributes[0], &attributes[2]);
6333 	const TFHandler			tfHandler				(renderCtx, numVertices);
6334 	tcu::ResultCollector	result;
6335 
6336 	gl.useProgram(programGL);
6337 	setViewport(gl, viewport);
6338 	gl.patchParameteri(GL_PATCH_VERTICES, DE_LENGTH_OF_ARRAY(attributes));
6339 
6340 	gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
6341 	gl.clear(GL_COLOR_BUFFER_BIT);
6342 
6343 	{
6344 		const glu::VertexArrayBinding	bindings[]	= { glu::va::Float("in_v_attr", 1, DE_LENGTH_OF_ARRAY(attributes), 0, &attributes[0]) };
6345 		const TFHandler::Result			tfResult	= tfHandler.renderAndGetPrimitives(programGL, outputPrimitiveTypeGL(m_primitiveType, false),
6346 																					   DE_LENGTH_OF_ARRAY(bindings), &bindings[0], DE_LENGTH_OF_ARRAY(attributes));
6347 
6348 		{
6349 			const tcu::Surface			pixels		= getPixels(renderCtx, viewport);
6350 			const tcu::TextureLevel		reference	= getPNG(m_testCtx.getArchive(), m_referenceImagePath.c_str());
6351 			const bool					success		= tcu::fuzzyCompare(log, "ImageComparison", "Image Comparison", reference.getAccess(), pixels.getAccess(), 0.02f, tcu::COMPARE_LOG_RESULT);
6352 
6353 			if (!success)
6354 				result.fail("Image comparison failed");
6355 		}
6356 
6357 		if ((int)tfResult.varying.size() != numVertices)
6358 		{
6359 			log << TestLog::Message << "Failure: transform feedback returned " << tfResult.varying.size() << " vertices; expected " << numVertices << TestLog::EndMessage;
6360 			result.fail("Wrong number of vertices");
6361 		}
6362 		else
6363 		{
6364 			const int topLevelArraySize		= (m_ioType == IO_TYPE_PER_PATCH				? 1
6365 											 : m_ioType == IO_TYPE_PER_PATCH_ARRAY			? NUM_PER_PATCH_ARRAY_ELEMS
6366 											 : m_ioType == IO_TYPE_PER_PATCH_BLOCK			? 1
6367 											 : m_ioType == IO_TYPE_PER_PATCH_BLOCK_ARRAY	? NUM_PER_PATCH_BLOCKS
6368 											 : (int)NUM_OUTPUT_VERTICES);
6369 			const int numTEInputs			= numBasicSubobjectsInElementType(m_tesInputs) * topLevelArraySize;
6370 
6371 			for (int vertexNdx = 0; vertexNdx < (int)numVertices; vertexNdx++)
6372 			{
6373 				if (tfResult.varying[vertexNdx] > (deUint32)numTEInputs)
6374 				{
6375 					log << TestLog::Message << "Failure: out_te_firstFailedInputIndex has value " << tfResult.varying[vertexNdx]
6376 											<< ", should be in range [0, " << numTEInputs << "]" << TestLog::EndMessage;
6377 					result.fail("Invalid transform feedback output");
6378 				}
6379 				else if (tfResult.varying[vertexNdx] != (deUint32)numTEInputs)
6380 				{
6381 					log << TestLog::Message << "Failure: in tessellation evaluation shader, check for input "
6382 											<< basicSubobjectAtIndex(tfResult.varying[vertexNdx], m_tesInputs, topLevelArraySize) << " failed" << TestLog::EndMessage;
6383 					result.fail("Invalid input value in tessellation evaluation shader");
6384 				}
6385 			}
6386 		}
6387 	}
6388 
6389 	result.setTestContextResult(m_testCtx);
6390 	return STOP;
6391 }
6392 
6393 /*--------------------------------------------------------------------*//*!
6394  * \brief Pass gl_Position between VS and TCS, or between TCS and TES.
6395  *
6396  * In TCS gl_Position is in the gl_out[] block and in TES in the gl_in[]
6397  * block, and has no special semantics in those. Arbitrary vec4 data can
6398  * thus be passed there.
6399  *//*--------------------------------------------------------------------*/
6400 class GLPositionCase : public TestCase
6401 {
6402 public:
6403 	enum CaseType
6404 	{
6405 		CASETYPE_VS_TO_TCS = 0,
6406 		CASETYPE_TCS_TO_TES,
6407 		CASETYPE_VS_TO_TCS_TO_TES,
6408 
6409 		CASETYPE_LAST
6410 	};
6411 
GLPositionCase(Context & context,const char * name,const char * description,CaseType caseType,const char * referenceImagePath)6412 	GLPositionCase (Context& context, const char* name, const char* description, CaseType caseType, const char* referenceImagePath)
6413 		: TestCase				(context, name, description)
6414 		, m_caseType			(caseType)
6415 		, m_referenceImagePath	(referenceImagePath)
6416 	{
6417 	}
6418 
6419 	void									init				(void);
6420 	void									deinit				(void);
6421 	IterateResult							iterate				(void);
6422 
6423 	static const char*						getCaseTypeName		(CaseType type);
6424 
6425 private:
6426 	static const int						RENDER_SIZE = 256;
6427 
6428 	const CaseType							m_caseType;
6429 	const string							m_referenceImagePath;
6430 
6431 	SharedPtr<const glu::ShaderProgram>		m_program;
6432 };
6433 
getCaseTypeName(CaseType type)6434 const char* GLPositionCase::getCaseTypeName (CaseType type)
6435 {
6436 	switch (type)
6437 	{
6438 		case CASETYPE_VS_TO_TCS:			return "gl_position_vs_to_tcs";
6439 		case CASETYPE_TCS_TO_TES:			return "gl_position_tcs_to_tes";
6440 		case CASETYPE_VS_TO_TCS_TO_TES:		return "gl_position_vs_to_tcs_to_tes";
6441 		default:
6442 			DE_ASSERT(false); return DE_NULL;
6443 	}
6444 }
6445 
init(void)6446 void GLPositionCase::init (void)
6447 {
6448 	checkTessellationSupport(m_context);
6449 	checkRenderTargetSize(m_context.getRenderTarget(), RENDER_SIZE);
6450 
6451 	const bool		vsToTCS		= m_caseType == CASETYPE_VS_TO_TCS		|| m_caseType == CASETYPE_VS_TO_TCS_TO_TES;
6452 	const bool		tcsToTES	= m_caseType == CASETYPE_TCS_TO_TES		|| m_caseType == CASETYPE_VS_TO_TCS_TO_TES;
6453 
6454 	const string	tesIn0		= tcsToTES ? "gl_in[0].gl_Position" : "in_te_attr[0]";
6455 	const string	tesIn1		= tcsToTES ? "gl_in[1].gl_Position" : "in_te_attr[1]";
6456 	const string	tesIn2		= tcsToTES ? "gl_in[2].gl_Position" : "in_te_attr[2]";
6457 
6458 	std::string vertexShaderTemplate			("${GLSL_VERSION_DECL}\n"
6459 												 "${GLSL_PER_VERTEX_OUT}\n"
6460 												 "\n"
6461 												 "in highp vec4 in_v_attr;\n"
6462 												 + string(!vsToTCS ? "out highp vec4 in_tc_attr;\n" : "") +
6463 												 "\n"
6464 												 "void main (void)\n"
6465 												 "{\n"
6466 												 "	" + (vsToTCS ? "gl_Position" : "in_tc_attr") + " = in_v_attr;\n"
6467 												 "}\n");
6468 	std::string tessellationControlTemplate		("${GLSL_VERSION_DECL}\n"
6469 												 "${TESSELLATION_SHADER_REQUIRE}\n"
6470 												 "${GLSL_PER_VERTEX_IN_ARR}\n"
6471 												 "${GLSL_PER_VERTEX_OUT_ARR}\n"
6472 												 "\n"
6473 												 "layout (vertices = 3) out;\n"
6474 												 "\n"
6475 												 + string(!vsToTCS ? "in highp vec4 in_tc_attr[];\n" : "") +
6476 												 "\n"
6477 												 + (!tcsToTES ? "out highp vec4 in_te_attr[];\n" : "") +
6478 												 "\n"
6479 												 "void main (void)\n"
6480 												 "{\n"
6481 												 "	" + (tcsToTES ? "gl_out[gl_InvocationID].gl_Position" : "in_te_attr[gl_InvocationID]") + " = "
6482 													  + (vsToTCS ? "gl_in[gl_InvocationID].gl_Position" : "in_tc_attr[gl_InvocationID]") + ";\n"
6483 												 "\n"
6484 												 "	gl_TessLevelInner[0] = 2.0;\n"
6485 												 "	gl_TessLevelInner[1] = 3.0;\n"
6486 												 "\n"
6487 												 "	gl_TessLevelOuter[0] = 4.0;\n"
6488 												 "	gl_TessLevelOuter[1] = 5.0;\n"
6489 												 "	gl_TessLevelOuter[2] = 6.0;\n"
6490 												 "	gl_TessLevelOuter[3] = 7.0;\n"
6491 												 "}\n");
6492 	std::string tessellationEvaluationTemplate	("${GLSL_VERSION_DECL}\n"
6493 												 "${TESSELLATION_SHADER_REQUIRE}\n"
6494 												 "${GLSL_PER_VERTEX_IN_ARR}\n"
6495 												 "${GLSL_PER_VERTEX_OUT}\n"
6496 												 "\n"
6497 												 + getTessellationEvaluationInLayoutString(TESSPRIMITIVETYPE_TRIANGLES) +
6498 												 "\n"
6499 												 + (!tcsToTES ? "in highp vec4 in_te_attr[];\n" : "") +
6500 												 "\n"
6501 												 "out highp vec4 in_f_color;\n"
6502 												 "\n"
6503 												 "void main (void)\n"
6504 												 "{\n"
6505 												 "	highp vec2 xy = gl_TessCoord.x * " + tesIn0 + ".xy\n"
6506 												 "	              + gl_TessCoord.y * " + tesIn1 + ".xy\n"
6507 												 "	              + gl_TessCoord.z * " + tesIn2 + ".xy;\n"
6508 												 "	gl_Position = vec4(xy, 0.0, 1.0);\n"
6509 												 "	in_f_color = vec4(" + tesIn0 + ".z + " + tesIn1 + ".w,\n"
6510 												 "	                  " + tesIn2 + ".z + " + tesIn0 + ".w,\n"
6511 												 "	                  " + tesIn1 + ".z + " + tesIn2 + ".w,\n"
6512 												 "	                  1.0);\n"
6513 												 "}\n");
6514 	std::string fragmentShaderTemplate			("${GLSL_VERSION_DECL}\n"
6515 												 "\n"
6516 												 "layout (location = 0) out mediump vec4 o_color;\n"
6517 												 "\n"
6518 												 "in highp vec4 in_f_color;\n"
6519 												 "\n"
6520 												 "void main (void)\n"
6521 												 "{\n"
6522 												 "	o_color = in_f_color;\n"
6523 												 "}\n");
6524 
6525 	m_program = SharedPtr<const ShaderProgram>(new ShaderProgram(m_context.getRenderContext(), glu::ProgramSources()
6526 		<< glu::VertexSource					(specializeShader(m_context, vertexShaderTemplate.c_str()))
6527 		<< glu::TessellationControlSource		(specializeShader(m_context, tessellationControlTemplate.c_str()))
6528 		<< glu::TessellationEvaluationSource	(specializeShader(m_context, tessellationEvaluationTemplate.c_str()))
6529 		<< glu::FragmentSource					(specializeShader(m_context, fragmentShaderTemplate.c_str()))));
6530 
6531 	m_testCtx.getLog() << *m_program;
6532 	if (!m_program->isOk())
6533 		TCU_FAIL("Program compilation failed");
6534 }
6535 
deinit(void)6536 void GLPositionCase::deinit (void)
6537 {
6538 	m_program.clear();
6539 }
6540 
iterate(void)6541 GLPositionCase::IterateResult GLPositionCase::iterate (void)
6542 {
6543 	TestLog&				log						= m_testCtx.getLog();
6544 	const RenderContext&	renderCtx				= m_context.getRenderContext();
6545 	const RandomViewport	viewport				(renderCtx.getRenderTarget(), RENDER_SIZE, RENDER_SIZE, deStringHash(getName()));
6546 	const glw::Functions&	gl						= renderCtx.getFunctions();
6547 	const deUint32			programGL				= m_program->getProgram();
6548 
6549 	static const float attributes[3*4] =
6550 	{
6551 		-0.8f, -0.7f, 0.1f, 0.7f,
6552 		-0.5f,  0.4f, 0.2f, 0.5f,
6553 		 0.3f,  0.2f, 0.3f, 0.45f
6554 	};
6555 
6556 	gl.useProgram(programGL);
6557 	setViewport(gl, viewport);
6558 	gl.patchParameteri(GL_PATCH_VERTICES, 3);
6559 
6560 	gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
6561 	gl.clear(GL_COLOR_BUFFER_BIT);
6562 
6563 	log << TestLog::Message << "Note: input data for in_v_attr:\n" << arrayStr(attributes, 4) << TestLog::EndMessage;
6564 
6565 	{
6566 		const glu::VertexArrayBinding bindings[] = { glu::va::Float("in_v_attr", 4, 3, 0, &attributes[0]) };
6567 		glu::draw(renderCtx, programGL, DE_LENGTH_OF_ARRAY(bindings), &bindings[0], glu::pr::Patches(3));
6568 
6569 		{
6570 			const tcu::Surface			pixels		= getPixels(renderCtx, viewport);
6571 			const tcu::TextureLevel		reference	= getPNG(m_testCtx.getArchive(), m_referenceImagePath.c_str());
6572 			const bool					success		= tcu::fuzzyCompare(log, "ImageComparison", "Image Comparison", reference.getAccess(), pixels.getAccess(), 0.02f, tcu::COMPARE_LOG_RESULT);
6573 
6574 			if (!success)
6575 			{
6576 				m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed");
6577 				return STOP;
6578 			}
6579 		}
6580 	}
6581 
6582 	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
6583 	return STOP;
6584 }
6585 
6586 class LimitQueryCase : public TestCase
6587 {
6588 public:
6589 						LimitQueryCase	(Context& context, const char* name, const char* desc, glw::GLenum target, int minValue);
6590 private:
6591 	IterateResult		iterate			(void);
6592 
6593 	const glw::GLenum	m_target;
6594 	const int			m_minValue;
6595 };
6596 
LimitQueryCase(Context & context,const char * name,const char * desc,glw::GLenum target,int minValue)6597 LimitQueryCase::LimitQueryCase (Context& context, const char* name, const char* desc, glw::GLenum target, int minValue)
6598 	: TestCase			(context, name, desc)
6599 	, m_target			(target)
6600 	, m_minValue		(minValue)
6601 {
6602 }
6603 
iterate(void)6604 LimitQueryCase::IterateResult LimitQueryCase::iterate (void)
6605 {
6606 	checkTessellationSupport(m_context);
6607 
6608 	glu::CallLogWrapper		gl		(m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
6609 	tcu::ResultCollector	result	(m_testCtx.getLog(), " // ERROR: ");
6610 
6611 	gl.enableLogging(true);
6612 	verifyStateIntegerMin(result, gl, m_target, m_minValue, QUERY_INTEGER);
6613 
6614 	{
6615 		const tcu::ScopedLogSection	section(m_testCtx.getLog(), "Types", "Alternative queries");
6616 		verifyStateIntegerMin(result, gl, m_target, m_minValue, QUERY_BOOLEAN);
6617 		verifyStateIntegerMin(result, gl, m_target, m_minValue, QUERY_INTEGER64);
6618 		verifyStateIntegerMin(result, gl, m_target, m_minValue, QUERY_FLOAT);
6619 	}
6620 
6621 	result.setTestContextResult(m_testCtx);
6622 	return STOP;
6623 }
6624 
6625 class CombinedUniformLimitCase : public TestCase
6626 {
6627 public:
6628 						CombinedUniformLimitCase	(Context& context, const char* name, const char* desc, glw::GLenum combined, glw::GLenum numBlocks, glw::GLenum defaultComponents);
6629 private:
6630 	IterateResult		iterate						(void);
6631 
6632 	const glw::GLenum	m_combined;
6633 	const glw::GLenum	m_numBlocks;
6634 	const glw::GLenum	m_defaultComponents;
6635 };
6636 
CombinedUniformLimitCase(Context & context,const char * name,const char * desc,glw::GLenum combined,glw::GLenum numBlocks,glw::GLenum defaultComponents)6637 CombinedUniformLimitCase::CombinedUniformLimitCase (Context& context, const char* name, const char* desc, glw::GLenum combined, glw::GLenum numBlocks, glw::GLenum defaultComponents)
6638 	: TestCase				(context, name, desc)
6639 	, m_combined			(combined)
6640 	, m_numBlocks			(numBlocks)
6641 	, m_defaultComponents	(defaultComponents)
6642 {
6643 }
6644 
iterate(void)6645 CombinedUniformLimitCase::IterateResult CombinedUniformLimitCase::iterate (void)
6646 {
6647 	checkTessellationSupport(m_context);
6648 
6649 	glu::CallLogWrapper		gl		(m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
6650 	tcu::ResultCollector	result	(m_testCtx.getLog(), " // ERROR: ");
6651 
6652 	gl.enableLogging(true);
6653 
6654 	m_testCtx.getLog()	<< tcu::TestLog::Message
6655 						<< "The minimum value of " << glu::getGettableStateStr(m_combined)
6656 						<< " is " << glu::getGettableStateStr(m_numBlocks)
6657 						<< " x MAX_UNIFORM_BLOCK_SIZE / 4 + "
6658 						<< glu::getGettableStateStr(m_defaultComponents)
6659 						<< tcu::TestLog::EndMessage;
6660 
6661 	StateQueryMemoryWriteGuard<glw::GLint> maxUniformBlocks;
6662 	gl.glGetIntegerv(m_numBlocks, &maxUniformBlocks);
6663 	GLS_COLLECT_GL_ERROR(result, gl.glGetError(), "glGetIntegerv");
6664 
6665 	StateQueryMemoryWriteGuard<glw::GLint> maxUniformBlockSize;
6666 	gl.glGetIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE, &maxUniformBlockSize);
6667 	GLS_COLLECT_GL_ERROR(result, gl.glGetError(), "glGetIntegerv");
6668 
6669 	StateQueryMemoryWriteGuard<glw::GLint> maxUniformComponents;
6670 	gl.glGetIntegerv(m_defaultComponents, &maxUniformComponents);
6671 	GLS_COLLECT_GL_ERROR(result, gl.glGetError(), "glGetIntegerv");
6672 
6673 	if (maxUniformBlocks.verifyValidity(result) && maxUniformBlockSize.verifyValidity(result) && maxUniformComponents.verifyValidity(result))
6674 	{
6675 		const int limit = ((int)maxUniformBlocks) * ((int)maxUniformBlockSize) / 4 + (int)maxUniformComponents;
6676 		verifyStateIntegerMin(result, gl, m_combined, limit, QUERY_INTEGER);
6677 
6678 		{
6679 			const tcu::ScopedLogSection	section(m_testCtx.getLog(), "Types", "Alternative queries");
6680 			verifyStateIntegerMin(result, gl, m_combined, limit, QUERY_BOOLEAN);
6681 			verifyStateIntegerMin(result, gl, m_combined, limit, QUERY_INTEGER64);
6682 			verifyStateIntegerMin(result, gl, m_combined, limit, QUERY_FLOAT);
6683 		}
6684 	}
6685 
6686 	result.setTestContextResult(m_testCtx);
6687 	return STOP;
6688 }
6689 
6690 class PatchVerticesStateCase : public TestCase
6691 {
6692 public:
6693 						PatchVerticesStateCase	(Context& context, const char* name, const char* desc);
6694 private:
6695 	IterateResult		iterate					(void);
6696 };
6697 
PatchVerticesStateCase(Context & context,const char * name,const char * desc)6698 PatchVerticesStateCase::PatchVerticesStateCase (Context& context, const char* name, const char* desc)
6699 	: TestCase(context, name, desc)
6700 {
6701 }
6702 
iterate(void)6703 PatchVerticesStateCase::IterateResult PatchVerticesStateCase::iterate (void)
6704 {
6705 	checkTessellationSupport(m_context);
6706 
6707 	glu::CallLogWrapper		gl		(m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
6708 	tcu::ResultCollector	result	(m_testCtx.getLog(), " // ERROR: ");
6709 
6710 	gl.enableLogging(true);
6711 
6712 	// initial
6713 	{
6714 		const tcu::ScopedLogSection section(m_testCtx.getLog(), "initial", "Initial value");
6715 
6716 		verifyStateInteger(result, gl, GL_PATCH_VERTICES, 3, QUERY_INTEGER);
6717 	}
6718 
6719 	// bind
6720 	{
6721 		const tcu::ScopedLogSection section(m_testCtx.getLog(), "set", "After set");
6722 
6723 		gl.glPatchParameteri(GL_PATCH_VERTICES, 22);
6724 		GLS_COLLECT_GL_ERROR(result, gl.glGetError(), "glPatchParameteri");
6725 
6726 		verifyStateInteger(result, gl, GL_PATCH_VERTICES, 22, QUERY_INTEGER);
6727 		{
6728 			const tcu::ScopedLogSection	subsection(m_testCtx.getLog(), "Types", "Alternative queries");
6729 			verifyStateIntegerMin(result, gl, GL_PATCH_VERTICES, 22, QUERY_BOOLEAN);
6730 			verifyStateIntegerMin(result, gl, GL_PATCH_VERTICES, 22, QUERY_INTEGER64);
6731 			verifyStateIntegerMin(result, gl, GL_PATCH_VERTICES, 22, QUERY_FLOAT);
6732 		}
6733 	}
6734 
6735 	result.setTestContextResult(m_testCtx);
6736 	return STOP;
6737 }
6738 
6739 class PrimitiveRestartForPatchesSupportedCase : public TestCase
6740 {
6741 public:
6742 						PrimitiveRestartForPatchesSupportedCase	(Context& context, const char* name, const char* desc);
6743 private:
6744 	IterateResult		iterate									(void);
6745 };
6746 
PrimitiveRestartForPatchesSupportedCase(Context & context,const char * name,const char * desc)6747 PrimitiveRestartForPatchesSupportedCase::PrimitiveRestartForPatchesSupportedCase (Context& context, const char* name, const char* desc)
6748 	: TestCase(context, name, desc)
6749 {
6750 }
6751 
iterate(void)6752 PrimitiveRestartForPatchesSupportedCase::IterateResult PrimitiveRestartForPatchesSupportedCase::iterate (void)
6753 {
6754 	checkTessellationSupport(m_context);
6755 
6756 	glu::CallLogWrapper		gl		(m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
6757 	tcu::ResultCollector	result	(m_testCtx.getLog(), " // ERROR: ");
6758 	QueriedState			state;
6759 
6760 	gl.enableLogging(true);
6761 
6762 	queryState(result, gl, QUERY_BOOLEAN, GL_PRIMITIVE_RESTART_FOR_PATCHES_SUPPORTED, state);
6763 
6764 	if (!state.isUndefined())
6765 	{
6766 		const tcu::ScopedLogSection	subsection(m_testCtx.getLog(), "Types", "Alternative types");
6767 		verifyStateBoolean(result, gl, GL_PRIMITIVE_RESTART_FOR_PATCHES_SUPPORTED, state.getBoolAccess(), QUERY_INTEGER);
6768 		verifyStateBoolean(result, gl, GL_PRIMITIVE_RESTART_FOR_PATCHES_SUPPORTED, state.getBoolAccess(), QUERY_INTEGER64);
6769 		verifyStateBoolean(result, gl, GL_PRIMITIVE_RESTART_FOR_PATCHES_SUPPORTED, state.getBoolAccess(), QUERY_FLOAT);
6770 	}
6771 
6772 	result.setTestContextResult(m_testCtx);
6773 	return STOP;
6774 }
6775 
6776 class TessProgramQueryCase : public TestCase
6777 {
6778 public:
6779 						TessProgramQueryCase	(Context& context, const char* name, const char* desc);
6780 
6781 	std::string			getVertexSource			(void) const;
6782 	std::string			getFragmentSource		(void) const;
6783 	std::string			getTessCtrlSource		(const char* globalLayouts) const;
6784 	std::string			getTessEvalSource		(const char* globalLayouts) const;
6785 };
6786 
TessProgramQueryCase(Context & context,const char * name,const char * desc)6787 TessProgramQueryCase::TessProgramQueryCase (Context& context, const char* name, const char* desc)
6788 	: TestCase(context, name, desc)
6789 {
6790 }
6791 
getVertexSource(void) const6792 std::string TessProgramQueryCase::getVertexSource (void) const
6793 {
6794 	return	"${GLSL_VERSION_DECL}\n"
6795 			"${GLSL_PER_VERTEX_OUT}\n"
6796 			"void main (void)\n"
6797 			"{\n"
6798 			"	gl_Position = vec4(float(gl_VertexID), float(gl_VertexID / 2), 0.0, 1.0);\n"
6799 			"}\n";
6800 }
6801 
getFragmentSource(void) const6802 std::string TessProgramQueryCase::getFragmentSource (void) const
6803 {
6804 	return	"${GLSL_VERSION_DECL}\n"
6805 			"layout (location = 0) out mediump vec4 o_color;\n"
6806 			"void main (void)\n"
6807 			"{\n"
6808 			"	o_color = vec4(0.0, 1.0, 0.0, 1.0);\n"
6809 			"}\n";
6810 }
6811 
getTessCtrlSource(const char * globalLayouts) const6812 std::string TessProgramQueryCase::getTessCtrlSource (const char* globalLayouts) const
6813 {
6814 	return	"${GLSL_VERSION_DECL}\n"
6815 			"${TESSELLATION_SHADER_REQUIRE}\n"
6816 			"${GLSL_PER_VERTEX_IN_ARR}\n"
6817 			"${GLSL_PER_VERTEX_OUT_ARR}\n"
6818 			+ std::string(globalLayouts) + ";\n"
6819 			"void main (void)\n"
6820 			"{\n"
6821 			"	gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
6822 			"	gl_TessLevelInner[0] = 2.8;\n"
6823 			"	gl_TessLevelInner[1] = 2.8;\n"
6824 			"	gl_TessLevelOuter[0] = 2.8;\n"
6825 			"	gl_TessLevelOuter[1] = 2.8;\n"
6826 			"	gl_TessLevelOuter[2] = 2.8;\n"
6827 			"	gl_TessLevelOuter[3] = 2.8;\n"
6828 			"}\n";
6829 }
6830 
getTessEvalSource(const char * globalLayouts) const6831 std::string TessProgramQueryCase::getTessEvalSource (const char* globalLayouts) const
6832 {
6833 	return	"${GLSL_VERSION_DECL}\n"
6834 			"${TESSELLATION_SHADER_REQUIRE}\n"
6835 			"${GLSL_PER_VERTEX_IN_ARR}\n"
6836 			"${GLSL_PER_VERTEX_OUT}\n"
6837 			+ std::string(globalLayouts) + ";\n"
6838 			"void main (void)\n"
6839 			"{\n"
6840 			"	gl_Position = gl_TessCoord.x * gl_in[0].gl_Position\n"
6841 			"	            + gl_TessCoord.y * gl_in[1].gl_Position\n"
6842 			"	            + gl_TessCoord.y * gl_in[2].gl_Position\n"
6843 			"	            + gl_TessCoord.z * gl_in[3].gl_Position;\n"
6844 			"}\n";
6845 }
6846 
6847 class TessControlOutputVerticesCase : public TessProgramQueryCase
6848 {
6849 public:
6850 						TessControlOutputVerticesCase	(Context& context, const char* name, const char* desc);
6851 private:
6852 	IterateResult		iterate							(void);
6853 };
6854 
TessControlOutputVerticesCase(Context & context,const char * name,const char * desc)6855 TessControlOutputVerticesCase::TessControlOutputVerticesCase (Context& context, const char* name, const char* desc)
6856 	: TessProgramQueryCase(context, name, desc)
6857 {
6858 }
6859 
iterate(void)6860 TessControlOutputVerticesCase::IterateResult TessControlOutputVerticesCase::iterate (void)
6861 {
6862 	checkTessellationSupport(m_context);
6863 
6864 	glu::ShaderProgram program (m_context.getRenderContext(), glu::ProgramSources()
6865 																<< glu::VertexSource(specializeShader(m_context, getVertexSource().c_str()))
6866 																<< glu::FragmentSource(specializeShader(m_context, getFragmentSource().c_str()))
6867 																<< glu::TessellationControlSource(specializeShader(m_context, getTessCtrlSource("layout(vertices=4) out").c_str()))
6868 																<< glu::TessellationEvaluationSource(specializeShader(m_context, getTessEvalSource("layout(triangles) in").c_str())));
6869 
6870 	m_testCtx.getLog() << program;
6871 	if (!program.isOk())
6872 		throw tcu::TestError("failed to build program");
6873 
6874 	{
6875 		glu::CallLogWrapper		gl		(m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
6876 		tcu::ResultCollector	result	(m_testCtx.getLog(), " // ERROR: ");
6877 
6878 		gl.enableLogging(true);
6879 		verifyStateProgramInteger(result, gl, program.getProgram(), GL_TESS_CONTROL_OUTPUT_VERTICES, 4, QUERY_PROGRAM_INTEGER);
6880 
6881 		result.setTestContextResult(m_testCtx);
6882 	}
6883 	return STOP;
6884 }
6885 
6886 class TessGenModeQueryCase : public TessProgramQueryCase
6887 {
6888 public:
6889 						TessGenModeQueryCase	(Context& context, const char* name, const char* desc);
6890 private:
6891 	IterateResult		iterate					(void);
6892 };
6893 
TessGenModeQueryCase(Context & context,const char * name,const char * desc)6894 TessGenModeQueryCase::TessGenModeQueryCase (Context& context, const char* name, const char* desc)
6895 	: TessProgramQueryCase(context, name, desc)
6896 {
6897 }
6898 
iterate(void)6899 TessGenModeQueryCase::IterateResult TessGenModeQueryCase::iterate (void)
6900 {
6901 	tcu::ResultCollector	result	(m_testCtx.getLog(), " // ERROR: ");
6902 	glu::CallLogWrapper		gl		(m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
6903 
6904 	static const struct
6905 	{
6906 		const char* description;
6907 		const char* layout;
6908 		glw::GLenum mode;
6909 	} s_modes[] =
6910 	{
6911 		{ "Triangles",	"layout(triangles) in",	GL_TRIANGLES	},
6912 		{ "Isolines",	"layout(isolines) in",	GL_ISOLINES		},
6913 		{ "Quads",		"layout(quads) in",		GL_QUADS		},
6914 	};
6915 
6916 	checkTessellationSupport(m_context);
6917 	gl.enableLogging(true);
6918 
6919 	for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(s_modes); ++ndx)
6920 	{
6921 		const tcu::ScopedLogSection	section(m_testCtx.getLog(), "Type", s_modes[ndx].description);
6922 
6923 		glu::ShaderProgram program (m_context.getRenderContext(), glu::ProgramSources()
6924 																	<< glu::VertexSource(specializeShader(m_context, getVertexSource().c_str()))
6925 																	<< glu::FragmentSource(specializeShader(m_context, getFragmentSource().c_str()))
6926 																	<< glu::TessellationControlSource(specializeShader(m_context, getTessCtrlSource("layout(vertices=6) out").c_str()))
6927 																	<< glu::TessellationEvaluationSource(specializeShader(m_context, getTessEvalSource(s_modes[ndx].layout).c_str())));
6928 
6929 		m_testCtx.getLog() << program;
6930 		if (!program.isOk())
6931 			result.fail("failed to build program");
6932 		else
6933 			verifyStateProgramInteger(result, gl, program.getProgram(), GL_TESS_GEN_MODE, s_modes[ndx].mode, QUERY_PROGRAM_INTEGER);
6934 	}
6935 
6936 	result.setTestContextResult(m_testCtx);
6937 	return STOP;
6938 }
6939 
6940 class TessGenSpacingQueryCase : public TessProgramQueryCase
6941 {
6942 public:
6943 						TessGenSpacingQueryCase	(Context& context, const char* name, const char* desc);
6944 private:
6945 	IterateResult		iterate					(void);
6946 };
6947 
TessGenSpacingQueryCase(Context & context,const char * name,const char * desc)6948 TessGenSpacingQueryCase::TessGenSpacingQueryCase (Context& context, const char* name, const char* desc)
6949 	: TessProgramQueryCase(context, name, desc)
6950 {
6951 }
6952 
iterate(void)6953 TessGenSpacingQueryCase::IterateResult TessGenSpacingQueryCase::iterate (void)
6954 {
6955 	tcu::ResultCollector	result	(m_testCtx.getLog(), " // ERROR: ");
6956 	glu::CallLogWrapper		gl		(m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
6957 
6958 	static const struct
6959 	{
6960 		const char* description;
6961 		const char* layout;
6962 		glw::GLenum spacing;
6963 	} s_modes[] =
6964 	{
6965 		{ "Default spacing",			"layout(triangles) in",								GL_EQUAL			},
6966 		{ "Equal spacing",				"layout(triangles, equal_spacing) in",				GL_EQUAL			},
6967 		{ "Fractional even spacing",	"layout(triangles, fractional_even_spacing) in",	GL_FRACTIONAL_EVEN	},
6968 		{ "Fractional odd spacing",		"layout(triangles, fractional_odd_spacing) in",		GL_FRACTIONAL_ODD	},
6969 	};
6970 
6971 	checkTessellationSupport(m_context);
6972 	gl.enableLogging(true);
6973 
6974 	for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(s_modes); ++ndx)
6975 	{
6976 		const tcu::ScopedLogSection	section(m_testCtx.getLog(), "Type", s_modes[ndx].description);
6977 
6978 		glu::ShaderProgram program (m_context.getRenderContext(), glu::ProgramSources()
6979 																	<< glu::VertexSource(specializeShader(m_context, getVertexSource().c_str()))
6980 																	<< glu::FragmentSource(specializeShader(m_context, getFragmentSource().c_str()))
6981 																	<< glu::TessellationControlSource(specializeShader(m_context, getTessCtrlSource("layout(vertices=6) out").c_str()))
6982 																	<< glu::TessellationEvaluationSource(specializeShader(m_context, getTessEvalSource(s_modes[ndx].layout).c_str())));
6983 
6984 		m_testCtx.getLog() << program;
6985 		if (!program.isOk())
6986 			result.fail("failed to build program");
6987 		else
6988 			verifyStateProgramInteger(result, gl, program.getProgram(), GL_TESS_GEN_SPACING, s_modes[ndx].spacing, QUERY_PROGRAM_INTEGER);
6989 	}
6990 
6991 	result.setTestContextResult(m_testCtx);
6992 	return STOP;
6993 }
6994 
6995 class TessGenVertexOrderQueryCase : public TessProgramQueryCase
6996 {
6997 public:
6998 						TessGenVertexOrderQueryCase	(Context& context, const char* name, const char* desc);
6999 private:
7000 	IterateResult		iterate						(void);
7001 };
7002 
TessGenVertexOrderQueryCase(Context & context,const char * name,const char * desc)7003 TessGenVertexOrderQueryCase::TessGenVertexOrderQueryCase (Context& context, const char* name, const char* desc)
7004 	: TessProgramQueryCase(context, name, desc)
7005 {
7006 }
7007 
iterate(void)7008 TessGenVertexOrderQueryCase::IterateResult TessGenVertexOrderQueryCase::iterate (void)
7009 {
7010 	tcu::ResultCollector	result	(m_testCtx.getLog(), " // ERROR: ");
7011 	glu::CallLogWrapper		gl		(m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
7012 
7013 	static const struct
7014 	{
7015 		const char* description;
7016 		const char* layout;
7017 		glw::GLenum order;
7018 	} s_modes[] =
7019 	{
7020 		{ "Default order",	"layout(triangles) in",			GL_CCW	},
7021 		{ "CW order",		"layout(triangles, cw) in",		GL_CW	},
7022 		{ "CCW order",		"layout(triangles, ccw) in",	GL_CCW	},
7023 	};
7024 
7025 	checkTessellationSupport(m_context);
7026 	gl.enableLogging(true);
7027 
7028 	for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(s_modes); ++ndx)
7029 	{
7030 		const tcu::ScopedLogSection	section(m_testCtx.getLog(), "Type", s_modes[ndx].description);
7031 
7032 		glu::ShaderProgram program (m_context.getRenderContext(), glu::ProgramSources()
7033 																	<< glu::VertexSource(specializeShader(m_context, getVertexSource().c_str()))
7034 																	<< glu::FragmentSource(specializeShader(m_context, getFragmentSource().c_str()))
7035 																	<< glu::TessellationControlSource(specializeShader(m_context, getTessCtrlSource("layout(vertices=6) out").c_str()))
7036 																	<< glu::TessellationEvaluationSource(specializeShader(m_context, getTessEvalSource(s_modes[ndx].layout).c_str())));
7037 
7038 		m_testCtx.getLog() << program;
7039 		if (!program.isOk())
7040 			result.fail("failed to build program");
7041 		else
7042 			verifyStateProgramInteger(result, gl, program.getProgram(), GL_TESS_GEN_VERTEX_ORDER, s_modes[ndx].order, QUERY_PROGRAM_INTEGER);
7043 	}
7044 
7045 	result.setTestContextResult(m_testCtx);
7046 	return STOP;
7047 }
7048 
7049 class TessGenPointModeQueryCase : public TessProgramQueryCase
7050 {
7051 public:
7052 						TessGenPointModeQueryCase	(Context& context, const char* name, const char* desc);
7053 private:
7054 	IterateResult		iterate						(void);
7055 };
7056 
TessGenPointModeQueryCase(Context & context,const char * name,const char * desc)7057 TessGenPointModeQueryCase::TessGenPointModeQueryCase (Context& context, const char* name, const char* desc)
7058 	: TessProgramQueryCase(context, name, desc)
7059 {
7060 }
7061 
iterate(void)7062 TessGenPointModeQueryCase::IterateResult TessGenPointModeQueryCase::iterate (void)
7063 {
7064 	tcu::ResultCollector	result	(m_testCtx.getLog(), " // ERROR: ");
7065 	glu::CallLogWrapper		gl		(m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
7066 
7067 	static const struct
7068 	{
7069 		const char* description;
7070 		const char* layout;
7071 		glw::GLenum mode;
7072 	} s_modes[] =
7073 	{
7074 		{ "Default mode",	"layout(triangles) in",			GL_FALSE	},
7075 		{ "Point mode",		"layout(triangles, point_mode) in",		GL_TRUE		},
7076 	};
7077 
7078 	checkTessellationSupport(m_context);
7079 	gl.enableLogging(true);
7080 
7081 	for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(s_modes); ++ndx)
7082 	{
7083 		const tcu::ScopedLogSection	section(m_testCtx.getLog(), "Type", s_modes[ndx].description);
7084 
7085 		glu::ShaderProgram program (m_context.getRenderContext(), glu::ProgramSources()
7086 																	<< glu::VertexSource(specializeShader(m_context, getVertexSource().c_str()))
7087 																	<< glu::FragmentSource(specializeShader(m_context, getFragmentSource().c_str()))
7088 																	<< glu::TessellationControlSource(specializeShader(m_context, getTessCtrlSource("layout(vertices=6) out").c_str()))
7089 																	<< glu::TessellationEvaluationSource(specializeShader(m_context, getTessEvalSource(s_modes[ndx].layout).c_str())));
7090 
7091 		m_testCtx.getLog() << program;
7092 		if (!program.isOk())
7093 			result.fail("failed to build program");
7094 		else
7095 			verifyStateProgramInteger(result, gl, program.getProgram(), GL_TESS_GEN_POINT_MODE, s_modes[ndx].mode, QUERY_PROGRAM_INTEGER);
7096 	}
7097 
7098 	result.setTestContextResult(m_testCtx);
7099 	return STOP;
7100 }
7101 
7102 class ReferencedByTessellationQueryCase : public TestCase
7103 {
7104 public:
7105 					ReferencedByTessellationQueryCase	(Context& context, const char* name, const char* desc, bool isCtrlCase);
7106 private:
7107 	void			init								(void);
7108 	IterateResult	iterate								(void);
7109 
7110 	std::string		getVertexSource						(void) const;
7111 	std::string		getFragmentSource					(void) const;
7112 	std::string		getTessCtrlSource					(void) const;
7113 	std::string		getTessEvalSource					(void) const;
7114 
7115 	const bool		m_isCtrlCase;
7116 };
7117 
ReferencedByTessellationQueryCase(Context & context,const char * name,const char * desc,bool isCtrlCase)7118 ReferencedByTessellationQueryCase::ReferencedByTessellationQueryCase (Context& context, const char* name, const char* desc, bool isCtrlCase)
7119 	: TestCase		(context, name, desc)
7120 	, m_isCtrlCase	(isCtrlCase)
7121 {
7122 }
7123 
init(void)7124 void ReferencedByTessellationQueryCase::init (void)
7125 {
7126 	checkTessellationSupport(m_context);
7127 }
7128 
iterate(void)7129 ReferencedByTessellationQueryCase::IterateResult ReferencedByTessellationQueryCase::iterate (void)
7130 {
7131 	tcu::ResultCollector	result	(m_testCtx.getLog(), " // ERROR: ");
7132 	glu::CallLogWrapper		gl		(m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
7133 	glu::ShaderProgram		program	(m_context.getRenderContext(), glu::ProgramSources()
7134 																	<< glu::VertexSource(specializeShader(m_context, getVertexSource().c_str()))
7135 																	<< glu::FragmentSource(specializeShader(m_context, getFragmentSource().c_str()))
7136 																	<< glu::TessellationControlSource(specializeShader(m_context, getTessCtrlSource().c_str()))
7137 																	<< glu::TessellationEvaluationSource(specializeShader(m_context, getTessEvalSource().c_str())));
7138 
7139 	gl.enableLogging(true);
7140 
7141 	m_testCtx.getLog() << program;
7142 	if (!program.isOk())
7143 		result.fail("failed to build program");
7144 	else
7145 	{
7146 		const deUint32 props[1] = { (deUint32)((m_isCtrlCase) ? (GL_REFERENCED_BY_TESS_CONTROL_SHADER) : (GL_REFERENCED_BY_TESS_EVALUATION_SHADER)) };
7147 
7148 		{
7149 			const tcu::ScopedLogSection section		(m_testCtx.getLog(), "UnreferencedUniform", "Unreferenced uniform u_unreferenced");
7150 			deUint32					resourcePos;
7151 			glw::GLsizei				length		= 0;
7152 			glw::GLint					referenced	= 0;
7153 
7154 			resourcePos = gl.glGetProgramResourceIndex(program.getProgram(), GL_UNIFORM, "u_unreferenced");
7155 			m_testCtx.getLog() << tcu::TestLog::Message << "u_unreferenced resource index: " << resourcePos << tcu::TestLog::EndMessage;
7156 
7157 			if (resourcePos == GL_INVALID_INDEX)
7158 				result.fail("resourcePos was GL_INVALID_INDEX");
7159 			else
7160 			{
7161 				gl.glGetProgramResourceiv(program.getProgram(), GL_UNIFORM, resourcePos, 1, props, 1, &length, &referenced);
7162 				m_testCtx.getLog()
7163 					<< tcu::TestLog::Message
7164 					<< "Query " << glu::getProgramResourcePropertyStr(props[0])
7165 					<< ", got " << length << " value(s), value[0] = " << glu::getBooleanStr(referenced)
7166 					<< tcu::TestLog::EndMessage;
7167 
7168 				GLS_COLLECT_GL_ERROR(result, gl.glGetError(), "query resource");
7169 
7170 				if (length == 0 || referenced != GL_FALSE)
7171 					result.fail("expected GL_FALSE");
7172 			}
7173 		}
7174 
7175 		{
7176 			const tcu::ScopedLogSection section		(m_testCtx.getLog(), "ReferencedUniform", "Referenced uniform u_referenced");
7177 			deUint32					resourcePos;
7178 			glw::GLsizei				length		= 0;
7179 			glw::GLint					referenced	= 0;
7180 
7181 			resourcePos = gl.glGetProgramResourceIndex(program.getProgram(), GL_UNIFORM, "u_referenced");
7182 			m_testCtx.getLog() << tcu::TestLog::Message << "u_referenced resource index: " << resourcePos << tcu::TestLog::EndMessage;
7183 
7184 			if (resourcePos == GL_INVALID_INDEX)
7185 				result.fail("resourcePos was GL_INVALID_INDEX");
7186 			else
7187 			{
7188 				gl.glGetProgramResourceiv(program.getProgram(), GL_UNIFORM, resourcePos, 1, props, 1, &length, &referenced);
7189 				m_testCtx.getLog()
7190 					<< tcu::TestLog::Message
7191 					<< "Query " << glu::getProgramResourcePropertyStr(props[0])
7192 					<< ", got " << length << " value(s), value[0] = " << glu::getBooleanStr(referenced)
7193 					<< tcu::TestLog::EndMessage;
7194 
7195 				GLU_EXPECT_NO_ERROR(gl.glGetError(), "query resource");
7196 
7197 				if (length == 0 || referenced != GL_TRUE)
7198 					result.fail("expected GL_TRUE");
7199 			}
7200 		}
7201 	}
7202 
7203 	result.setTestContextResult(m_testCtx);
7204 	return STOP;
7205 }
7206 
getVertexSource(void) const7207 std::string ReferencedByTessellationQueryCase::getVertexSource (void) const
7208 {
7209 	return	"${GLSL_VERSION_DECL}\n"
7210 			"${GLSL_PER_VERTEX_OUT}\n"
7211 			"void main (void)\n"
7212 			"{\n"
7213 			"	gl_Position = vec4(float(gl_VertexID), float(gl_VertexID / 2), 0.0, 1.0);\n"
7214 			"}\n";
7215 }
7216 
getFragmentSource(void) const7217 std::string ReferencedByTessellationQueryCase::getFragmentSource (void) const
7218 {
7219 	return	"${GLSL_VERSION_DECL}\n"
7220 			"layout (location = 0) out mediump vec4 o_color;\n"
7221 			"void main (void)\n"
7222 			"{\n"
7223 			"	o_color = vec4(0.0, 1.0, 0.0, 1.0);\n"
7224 			"}\n";
7225 }
7226 
getTessCtrlSource(void) const7227 std::string ReferencedByTessellationQueryCase::getTessCtrlSource (void) const
7228 {
7229 	std::ostringstream buf;
7230 	buf <<	"${GLSL_VERSION_DECL}\n"
7231 			"${TESSELLATION_SHADER_REQUIRE}\n"
7232 			"${GLSL_PER_VERTEX_IN_ARR}\n"
7233 			"${GLSL_PER_VERTEX_OUT_ARR}\n"
7234 			"layout(vertices = 3) out;\n"
7235 			"uniform highp vec4 " << ((m_isCtrlCase) ? ("u_referenced") : ("u_unreferenced")) << ";\n"
7236 			"void main (void)\n"
7237 			"{\n"
7238 			"	vec4 offset = " << ((m_isCtrlCase) ? ("u_referenced") : ("u_unreferenced")) << ";\n"
7239 			"	gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position + offset;\n"
7240 			"	gl_TessLevelInner[0] = 2.8;\n"
7241 			"	gl_TessLevelInner[1] = 2.8;\n"
7242 			"	gl_TessLevelOuter[0] = 2.8;\n"
7243 			"	gl_TessLevelOuter[1] = 2.8;\n"
7244 			"	gl_TessLevelOuter[2] = 2.8;\n"
7245 			"	gl_TessLevelOuter[3] = 2.8;\n"
7246 			"}\n";
7247 	return buf.str();
7248 }
7249 
getTessEvalSource(void) const7250 std::string ReferencedByTessellationQueryCase::getTessEvalSource (void) const
7251 {
7252 	std::ostringstream buf;
7253 	buf <<	"${GLSL_VERSION_DECL}\n"
7254 			"${TESSELLATION_SHADER_REQUIRE}\n"
7255 			"${GLSL_PER_VERTEX_IN_ARR}\n"
7256 			"${GLSL_PER_VERTEX_OUT}\n"
7257 			"layout(triangles) in;\n"
7258 			"uniform highp vec4 " << ((m_isCtrlCase) ? ("u_unreferenced") : ("u_referenced")) << ";\n"
7259 			"void main (void)\n"
7260 			"{\n"
7261 			"	vec4 offset = " << ((m_isCtrlCase) ? ("u_unreferenced") : ("u_referenced")) << ";\n"
7262 			"	gl_Position = gl_TessCoord.x * gl_in[0].gl_Position\n"
7263 			"	            + gl_TessCoord.y * gl_in[1].gl_Position\n"
7264 			"	            + gl_TessCoord.z * gl_in[2].gl_Position\n"
7265 			"	            + offset;\n"
7266 			"}\n";
7267 
7268 	return buf.str();
7269 }
7270 
7271 class IsPerPatchQueryCase : public TestCase
7272 {
7273 public:
7274 					IsPerPatchQueryCase		(Context& context, const char* name, const char* desc);
7275 private:
7276 	void			init					(void);
7277 	IterateResult	iterate					(void);
7278 };
7279 
IsPerPatchQueryCase(Context & context,const char * name,const char * desc)7280 IsPerPatchQueryCase::IsPerPatchQueryCase (Context& context, const char* name, const char* desc)
7281 	: TestCase(context, name, desc)
7282 {
7283 }
7284 
init(void)7285 void IsPerPatchQueryCase::init (void)
7286 {
7287 	checkTessellationSupport(m_context);
7288 }
7289 
iterate(void)7290 IsPerPatchQueryCase::IterateResult IsPerPatchQueryCase::iterate (void)
7291 {
7292 	static const char* const s_controlSource =	"${GLSL_VERSION_DECL}\n"
7293 												"${TESSELLATION_SHADER_REQUIRE}\n"
7294 												"${GLSL_PER_VERTEX_IN_ARR}\n"
7295 												"${GLSL_PER_VERTEX_OUT_ARR}\n"
7296 												"layout(vertices = 3) out;\n"
7297 												"patch out highp vec4 v_perPatch;\n"
7298 												"out highp vec4 v_perVertex[];\n"
7299 												"void main (void)\n"
7300 												"{\n"
7301 												"	gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
7302 												"	v_perPatch = gl_in[0].gl_Position;\n"
7303 												"	v_perVertex[gl_InvocationID] = -gl_in[gl_InvocationID].gl_Position;\n"
7304 												"	gl_TessLevelInner[0] = 2.8;\n"
7305 												"	gl_TessLevelInner[1] = 2.8;\n"
7306 												"	gl_TessLevelOuter[0] = 2.8;\n"
7307 												"	gl_TessLevelOuter[1] = 2.8;\n"
7308 												"	gl_TessLevelOuter[2] = 2.8;\n"
7309 												"	gl_TessLevelOuter[3] = 2.8;\n"
7310 												"}\n";
7311 	tcu::ResultCollector	result	(m_testCtx.getLog(), " // ERROR: ");
7312 	glu::CallLogWrapper		gl		(m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
7313 	glu::ShaderProgram		program	(m_context.getRenderContext(), glu::ProgramSources()
7314 																	<< glu::TessellationControlSource(specializeShader(m_context, s_controlSource))
7315 																	<< glu::ProgramSeparable(true));
7316 
7317 	gl.enableLogging(true);
7318 
7319 	m_testCtx.getLog() << program;
7320 	if (!program.isOk())
7321 		result.fail("failed to build program");
7322 	else
7323 	{
7324 		const deUint32 props[1] = { GL_IS_PER_PATCH };
7325 
7326 		{
7327 			const tcu::ScopedLogSection section		(m_testCtx.getLog(), "PerPatchOutput", "Per patch v_perPatch");
7328 			deUint32					resourcePos;
7329 			glw::GLsizei				length		= 0;
7330 			glw::GLint					referenced	= 0;
7331 
7332 			resourcePos = gl.glGetProgramResourceIndex(program.getProgram(), GL_PROGRAM_OUTPUT, "v_perPatch");
7333 			m_testCtx.getLog() << tcu::TestLog::Message << "v_perPatch resource index: " << resourcePos << tcu::TestLog::EndMessage;
7334 
7335 			if (resourcePos == GL_INVALID_INDEX)
7336 				result.fail("resourcePos was GL_INVALID_INDEX");
7337 			else
7338 			{
7339 				gl.glGetProgramResourceiv(program.getProgram(), GL_PROGRAM_OUTPUT, resourcePos, 1, props, 1, &length, &referenced);
7340 				m_testCtx.getLog()
7341 					<< tcu::TestLog::Message
7342 					<< "Query " << glu::getProgramResourcePropertyStr(props[0])
7343 					<< ", got " << length << " value(s), value[0] = " << glu::getBooleanStr(referenced)
7344 					<< tcu::TestLog::EndMessage;
7345 
7346 				GLS_COLLECT_GL_ERROR(result, gl.glGetError(), "query resource");
7347 
7348 				if (length == 0 || referenced != GL_TRUE)
7349 					result.fail("expected GL_TRUE");
7350 			}
7351 		}
7352 
7353 		{
7354 			const tcu::ScopedLogSection section		(m_testCtx.getLog(), "PerVertexhOutput", "Per vertex v_perVertex");
7355 			deUint32					resourcePos;
7356 			glw::GLsizei				length		= 0;
7357 			glw::GLint					referenced	= 0;
7358 
7359 			resourcePos = gl.glGetProgramResourceIndex(program.getProgram(), GL_PROGRAM_OUTPUT, "v_perVertex");
7360 			m_testCtx.getLog() << tcu::TestLog::Message << "v_perVertex resource index: " << resourcePos << tcu::TestLog::EndMessage;
7361 
7362 			if (resourcePos == GL_INVALID_INDEX)
7363 				result.fail("resourcePos was GL_INVALID_INDEX");
7364 			else
7365 			{
7366 				gl.glGetProgramResourceiv(program.getProgram(), GL_PROGRAM_OUTPUT, resourcePos, 1, props, 1, &length, &referenced);
7367 				m_testCtx.getLog()
7368 					<< tcu::TestLog::Message
7369 					<< "Query " << glu::getProgramResourcePropertyStr(props[0])
7370 					<< ", got " << length << " value(s), value[0] = " << glu::getBooleanStr(referenced)
7371 					<< tcu::TestLog::EndMessage;
7372 
7373 				GLU_EXPECT_NO_ERROR(gl.glGetError(), "query resource");
7374 
7375 				if (length == 0 || referenced != GL_FALSE)
7376 					result.fail("expected GL_FALSE");
7377 			}
7378 		}
7379 	}
7380 
7381 	result.setTestContextResult(m_testCtx);
7382 	return STOP;
7383 }
7384 
7385 } // anonymous
7386 
TessellationTests(Context & context,bool isGL45)7387 TessellationTests::TessellationTests (Context& context, bool isGL45)
7388 	: TestCaseGroup(context, "tessellation", "Tessellation Tests")
7389 	, m_isGL45(isGL45)
7390 {
7391 }
7392 
~TessellationTests(void)7393 TessellationTests::~TessellationTests (void)
7394 {
7395 }
7396 
init(void)7397 void TessellationTests::init (void)
7398 {
7399 	{
7400 		tcu::TestCaseGroup* const queryGroup = new tcu::TestCaseGroup(m_testCtx, "state_query", "Query tests");
7401 		addChild(queryGroup);
7402 
7403 		// new limits
7404 		queryGroup->addChild(new LimitQueryCase(m_context, "max_patch_vertices",								"Test MAX_PATCH_VERTICES",								GL_MAX_PATCH_VERTICES,							32));
7405 		queryGroup->addChild(new LimitQueryCase(m_context, "max_tess_gen_level",								"Test MAX_TESS_GEN_LEVEL",								GL_MAX_TESS_GEN_LEVEL,							64));
7406 		queryGroup->addChild(new LimitQueryCase(m_context, "max_tess_control_uniform_components",				"Test MAX_TESS_CONTROL_UNIFORM_COMPONENTS",				GL_MAX_TESS_CONTROL_UNIFORM_COMPONENTS,			1024));
7407 		queryGroup->addChild(new LimitQueryCase(m_context, "max_tess_evaluation_uniform_components",			"Test MAX_TESS_EVALUATION_UNIFORM_COMPONENTS",			GL_MAX_TESS_EVALUATION_UNIFORM_COMPONENTS,		1024));
7408 		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));
7409 		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));
7410 		queryGroup->addChild(new LimitQueryCase(m_context, "max_tess_control_output_components",				"Test MAX_TESS_CONTROL_OUTPUT_COMPONENTS",				GL_MAX_TESS_CONTROL_OUTPUT_COMPONENTS,			64));
7411 		queryGroup->addChild(new LimitQueryCase(m_context, "max_tess_patch_components",							"Test MAX_TESS_PATCH_COMPONENTS",						GL_MAX_TESS_PATCH_COMPONENTS,					120));
7412 		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));
7413 		queryGroup->addChild(new LimitQueryCase(m_context, "max_tess_evaluation_output_components",				"Test MAX_TESS_EVALUATION_OUTPUT_COMPONENTS",			GL_MAX_TESS_EVALUATION_OUTPUT_COMPONENTS,		64));
7414 		queryGroup->addChild(new LimitQueryCase(m_context, "max_tess_control_uniform_blocks",					"Test MAX_TESS_CONTROL_UNIFORM_BLOCKS",					GL_MAX_TESS_CONTROL_UNIFORM_BLOCKS,				12));
7415 		queryGroup->addChild(new LimitQueryCase(m_context, "max_tess_evaluation_uniform_blocks",				"Test MAX_TESS_EVALUATION_UNIFORM_BLOCKS",				GL_MAX_TESS_EVALUATION_UNIFORM_BLOCKS,			12));
7416 		queryGroup->addChild(new LimitQueryCase(m_context, "max_tess_control_input_components",					"Test MAX_TESS_CONTROL_INPUT_COMPONENTS",				GL_MAX_TESS_CONTROL_INPUT_COMPONENTS,			64));
7417 		queryGroup->addChild(new LimitQueryCase(m_context, "max_tess_evaluation_input_components",				"Test MAX_TESS_EVALUATION_INPUT_COMPONENTS",			GL_MAX_TESS_EVALUATION_INPUT_COMPONENTS,		64));
7418 		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));
7419 		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));
7420 		queryGroup->addChild(new LimitQueryCase(m_context, "max_tess_control_atomic_counters",					"Test MAX_TESS_CONTROL_ATOMIC_COUNTERS",				GL_MAX_TESS_CONTROL_ATOMIC_COUNTERS,			0));
7421 		queryGroup->addChild(new LimitQueryCase(m_context, "max_tess_evaluation_atomic_counters",				"Test MAX_TESS_EVALUATION_ATOMIC_COUNTERS",				GL_MAX_TESS_EVALUATION_ATOMIC_COUNTERS,			0));
7422 		queryGroup->addChild(new LimitQueryCase(m_context, "max_tess_control_image_uniforms",					"Test MAX_TESS_CONTROL_IMAGE_UNIFORMS",					GL_MAX_TESS_CONTROL_IMAGE_UNIFORMS,				0));
7423 		queryGroup->addChild(new LimitQueryCase(m_context, "max_tess_evaluation_image_uniforms",				"Test MAX_TESS_EVALUATION_IMAGE_UNIFORMS",				GL_MAX_TESS_EVALUATION_IMAGE_UNIFORMS,			0));
7424 		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));
7425 		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));
7426 
7427 		// modified limits
7428 		queryGroup->addChild(new LimitQueryCase(m_context, "max_uniform_buffer_bindings",						"Test MAX_UNIFORM_BUFFER_BINDINGS",						GL_MAX_UNIFORM_BUFFER_BINDINGS,					72));
7429 		queryGroup->addChild(new LimitQueryCase(m_context, "max_combined_uniform_blocks",						"Test MAX_COMBINED_UNIFORM_BLOCKS",						GL_MAX_COMBINED_UNIFORM_BLOCKS,					60));
7430 		queryGroup->addChild(new LimitQueryCase(m_context, "max_combined_texture_image_units",					"Test MAX_COMBINED_TEXTURE_IMAGE_UNITS",				GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS,			96));
7431 
7432 		// combined limits
7433 		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));
7434 		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));
7435 
7436 		// features
7437 		queryGroup->addChild(new PrimitiveRestartForPatchesSupportedCase(m_context, "primitive_restart_for_patches_supported", "Test PRIMITIVE_RESTART_FOR_PATCHES_SUPPORTED"));
7438 
7439 		// states
7440 		queryGroup->addChild(new PatchVerticesStateCase(m_context, "patch_vertices", "Test PATCH_VERTICES"));
7441 
7442 		// program states
7443 		queryGroup->addChild(new TessControlOutputVerticesCase	(m_context, "tess_control_output_vertices",	"Test TESS_CONTROL_OUTPUT_VERTICES"));
7444 		queryGroup->addChild(new TessGenModeQueryCase			(m_context, "tess_gen_mode",				"Test TESS_GEN_MODE"));
7445 		queryGroup->addChild(new TessGenSpacingQueryCase		(m_context, "tess_gen_spacing",				"Test TESS_GEN_SPACING"));
7446 		queryGroup->addChild(new TessGenVertexOrderQueryCase	(m_context, "tess_gen_vertex_order",		"Test TESS_GEN_VERTEX_ORDER"));
7447 		queryGroup->addChild(new TessGenPointModeQueryCase		(m_context, "tess_gen_point_mode",			"Test TESS_GEN_POINT_MODE"));
7448 
7449 		// resource queries
7450 		queryGroup->addChild(new ReferencedByTessellationQueryCase	(m_context, "referenced_by_tess_control_shader",	"Test REFERENCED_BY_TESS_CONTROL_SHADER",		true));
7451 		queryGroup->addChild(new ReferencedByTessellationQueryCase	(m_context, "referenced_by_tess_evaluation_shader",	"Test REFERENCED_BY_TESS_EVALUATION_SHADER",	false));
7452 		queryGroup->addChild(new IsPerPatchQueryCase				(m_context, "is_per_patch",							"Test IS_PER_PATCH"));
7453 	}
7454 
7455 	{
7456 		TestCaseGroup* const tessCoordGroup = new TestCaseGroup(m_context, "tesscoord", "Get tessellation coordinates with transform feedback and validate them");
7457 		addChild(tessCoordGroup);
7458 
7459 		for (int primitiveTypeI = 0; primitiveTypeI < TESSPRIMITIVETYPE_LAST; primitiveTypeI++)
7460 		{
7461 			const TessPrimitiveType primitiveType = (TessPrimitiveType)primitiveTypeI;
7462 
7463 			for (int spacingI = 0; spacingI < SPACINGMODE_LAST; spacingI++)
7464 				tessCoordGroup->addChild(new TessCoordCase(m_context,
7465 														   (string() + getTessPrimitiveTypeShaderName(primitiveType) + "_" + getSpacingModeShaderName((SpacingMode)spacingI)).c_str(), "",
7466 														   primitiveType, (SpacingMode)spacingI));
7467 		}
7468 	}
7469 
7470 	{
7471 		TestCaseGroup* const windingGroup = new TestCaseGroup(m_context, "winding", "Test the cw and ccw input layout qualifiers");
7472 		addChild(windingGroup);
7473 
7474 		for (int primitiveTypeI = 0; primitiveTypeI < TESSPRIMITIVETYPE_LAST; primitiveTypeI++)
7475 		{
7476 			const TessPrimitiveType primitiveType = (TessPrimitiveType)primitiveTypeI;
7477 			if (primitiveType == TESSPRIMITIVETYPE_ISOLINES)
7478 				continue;
7479 
7480 			for (int windingI = 0; windingI < WINDING_LAST; windingI++)
7481 			{
7482 				const Winding winding = (Winding)windingI;
7483 				windingGroup->addChild(new WindingCase(m_context, (string() + getTessPrimitiveTypeShaderName(primitiveType) + "_" + getWindingShaderName(winding)).c_str(), "", primitiveType, winding));
7484 			}
7485 		}
7486 	}
7487 
7488 	{
7489 		TestCaseGroup* const shaderInputOutputGroup = new TestCaseGroup(m_context, "shader_input_output", "Test tessellation control and evaluation shader inputs and outputs");
7490 		addChild(shaderInputOutputGroup);
7491 
7492 		{
7493 			static const struct
7494 			{
7495 				int inPatchSize;
7496 				int outPatchSize;
7497 			} patchVertexCountCases[] =
7498 			{
7499 				{  5, 10 },
7500 				{ 10,  5 }
7501 			};
7502 
7503 			for (int caseNdx = 0; caseNdx < DE_LENGTH_OF_ARRAY(patchVertexCountCases); caseNdx++)
7504 			{
7505 				const int inSize	= patchVertexCountCases[caseNdx].inPatchSize;
7506 				const int outSize	= patchVertexCountCases[caseNdx].outPatchSize;
7507 
7508 				const string caseName = "patch_vertices_" + de::toString(inSize) + "_in_" + de::toString(outSize) + "_out";
7509 
7510 				shaderInputOutputGroup->addChild(new PatchVertexCountCase(m_context, caseName.c_str(), "Test input and output patch vertex counts", inSize, outSize,
7511 																		  ("data/tessellation/" + caseName + "_ref.png").c_str()));
7512 			}
7513 		}
7514 
7515 		for (int caseTypeI = 0; caseTypeI < PerPatchDataCase::CASETYPE_LAST; caseTypeI++)
7516 		{
7517 			const PerPatchDataCase::CaseType	caseType	= (PerPatchDataCase::CaseType)caseTypeI;
7518 			const char* const					caseName	= PerPatchDataCase::getCaseTypeName(caseType);
7519 
7520 			shaderInputOutputGroup->addChild(new PerPatchDataCase(m_context, caseName, PerPatchDataCase::getCaseTypeDescription(caseType), caseType,
7521 																  PerPatchDataCase::caseTypeUsesRefImageFromFile(caseType) ? (string() + "data/tessellation/" + caseName + "_ref.png").c_str() : DE_NULL));
7522 		}
7523 
7524 		for (int caseTypeI = 0; caseTypeI < GLPositionCase::CASETYPE_LAST; caseTypeI++)
7525 		{
7526 			const GLPositionCase::CaseType	caseType	= (GLPositionCase::CaseType)caseTypeI;
7527 			const char* const				caseName	= GLPositionCase::getCaseTypeName(caseType);
7528 
7529 			shaderInputOutputGroup->addChild(new GLPositionCase(m_context, caseName, "", caseType, "data/tessellation/gl_position_ref.png"));
7530 		}
7531 
7532 		shaderInputOutputGroup->addChild(new BarrierCase(m_context, "barrier", "Basic barrier usage", "data/tessellation/barrier_ref.png"));
7533 	}
7534 
7535 	{
7536 		TestCaseGroup* const miscDrawGroup = new TestCaseGroup(m_context, "misc_draw", "Miscellaneous draw-result-verifying cases");
7537 		addChild(miscDrawGroup);
7538 
7539 		for (int primitiveTypeI = 0; primitiveTypeI < TESSPRIMITIVETYPE_LAST; primitiveTypeI++)
7540 		{
7541 			const TessPrimitiveType primitiveType = (TessPrimitiveType)primitiveTypeI;
7542 			if (primitiveType == TESSPRIMITIVETYPE_ISOLINES)
7543 				continue;
7544 
7545 			const char* const primTypeName = getTessPrimitiveTypeShaderName(primitiveType);
7546 
7547 			for (int spacingI = 0; spacingI < SPACINGMODE_LAST; spacingI++)
7548 			{
7549 				const string caseName = string() + "fill_cover_" + primTypeName + "_" + getSpacingModeShaderName((SpacingMode)spacingI);
7550 
7551 				miscDrawGroup->addChild(new BasicTriangleFillCoverCase(m_context,
7552 																	   caseName.c_str(), "Check that there are no obvious gaps in the triangle-filled area of a tessellated shape",
7553 																	   primitiveType, (SpacingMode)spacingI,
7554 																	   ("data/tessellation/" + caseName + "_ref").c_str()));
7555 			}
7556 		}
7557 
7558 		for (int primitiveTypeI = 0; primitiveTypeI < TESSPRIMITIVETYPE_LAST; primitiveTypeI++)
7559 		{
7560 			const TessPrimitiveType primitiveType = (TessPrimitiveType)primitiveTypeI;
7561 			if (primitiveType == TESSPRIMITIVETYPE_ISOLINES)
7562 				continue;
7563 
7564 			const char* const primTypeName = getTessPrimitiveTypeShaderName(primitiveType);
7565 
7566 			for (int spacingI = 0; spacingI < SPACINGMODE_LAST; spacingI++)
7567 			{
7568 				const string caseName = string() + "fill_overlap_" + primTypeName + "_" + getSpacingModeShaderName((SpacingMode)spacingI);
7569 
7570 				miscDrawGroup->addChild(new BasicTriangleFillNonOverlapCase(m_context,
7571 																			caseName.c_str(), "Check that there are no obvious triangle overlaps in the triangle-filled area of a tessellated shape",
7572 																			primitiveType, (SpacingMode)spacingI,
7573 																			("data/tessellation/" + caseName + "_ref").c_str()));
7574 			}
7575 		}
7576 
7577 		for (int spacingI = 0; spacingI < SPACINGMODE_LAST; spacingI++)
7578 		{
7579 			const string caseName = string() + "isolines_" + getSpacingModeShaderName((SpacingMode)spacingI);
7580 
7581 			miscDrawGroup->addChild(new IsolinesRenderCase(m_context,
7582 														   caseName.c_str(), "Basic isolines render test",
7583 														   (SpacingMode)spacingI,
7584 														   ("data/tessellation/" + caseName + "_ref").c_str()));
7585 		}
7586 	}
7587 
7588 	{
7589 		TestCaseGroup* const commonEdgeGroup = new TestCaseGroup(m_context, "common_edge", "Draw multiple adjacent shapes and check that no cracks appear between them");
7590 		addChild(commonEdgeGroup);
7591 
7592 		for (int caseTypeI = 0; caseTypeI < CommonEdgeCase::CASETYPE_LAST; caseTypeI++)
7593 		{
7594 			for (int primitiveTypeI = 0; primitiveTypeI < TESSPRIMITIVETYPE_LAST; primitiveTypeI++)
7595 			{
7596 				const CommonEdgeCase::CaseType	caseType		= (CommonEdgeCase::CaseType)caseTypeI;
7597 				const TessPrimitiveType			primitiveType	= (TessPrimitiveType)primitiveTypeI;
7598 				if (primitiveType == TESSPRIMITIVETYPE_ISOLINES)
7599 						continue;
7600 
7601 				for (int spacingI = 0; spacingI < SPACINGMODE_LAST; spacingI++)
7602 				{
7603 					const SpacingMode	spacing		= (SpacingMode)spacingI;
7604 					const string		caseName	= (string() + getTessPrimitiveTypeShaderName(primitiveType)
7605 																+ "_" + getSpacingModeShaderName(spacing)
7606 																+ (caseType == CommonEdgeCase::CASETYPE_BASIC		? ""
7607 																 : caseType == CommonEdgeCase::CASETYPE_PRECISE		? "_precise"
7608 																 : DE_NULL));
7609 
7610 					commonEdgeGroup->addChild(new CommonEdgeCase(m_context, caseName.c_str(), "", primitiveType, spacing, caseType));
7611 				}
7612 			}
7613 		}
7614 	}
7615 
7616 	{
7617 		TestCaseGroup* const fractionalSpacingModeGroup = new TestCaseGroup(m_context, "fractional_spacing", "Test fractional spacing modes");
7618 		addChild(fractionalSpacingModeGroup);
7619 
7620 		fractionalSpacingModeGroup->addChild(new FractionalSpacingModeCase(m_context, "odd",	"", SPACINGMODE_FRACTIONAL_ODD));
7621 		fractionalSpacingModeGroup->addChild(new FractionalSpacingModeCase(m_context, "even",	"", SPACINGMODE_FRACTIONAL_EVEN));
7622 	}
7623 
7624 	{
7625 		TestCaseGroup* const primitiveDiscardGroup = new TestCaseGroup(m_context, "primitive_discard", "Test primitive discard with relevant outer tessellation level <= 0.0");
7626 		addChild(primitiveDiscardGroup);
7627 
7628 		for (int primitiveTypeI = 0; primitiveTypeI < TESSPRIMITIVETYPE_LAST; primitiveTypeI++)
7629 		{
7630 			for (int spacingI = 0; spacingI < SPACINGMODE_LAST; spacingI++)
7631 			{
7632 				for (int windingI = 0; windingI < WINDING_LAST; windingI++)
7633 				{
7634 					for (int usePointModeI = 0; usePointModeI <= 1; usePointModeI++)
7635 					{
7636 						const TessPrimitiveType		primitiveType	= (TessPrimitiveType)primitiveTypeI;
7637 						const SpacingMode			spacing			= (SpacingMode)spacingI;
7638 						const Winding				winding			= (Winding)windingI;
7639 						const bool					usePointMode	= usePointModeI != 0;
7640 
7641 						primitiveDiscardGroup->addChild(new PrimitiveDiscardCase(m_context, (string() + getTessPrimitiveTypeShaderName(primitiveType)
7642 																									  + "_" + getSpacingModeShaderName(spacing)
7643 																									  + "_" + getWindingShaderName(winding)
7644 																									  + (usePointMode ? "_point_mode" : "")).c_str(), "",
7645 																				 primitiveType, spacing, winding, usePointMode));
7646 					}
7647 				}
7648 			}
7649 		}
7650 	}
7651 
7652 	{
7653 		TestCaseGroup* const invarianceGroup							= new TestCaseGroup(m_context, "invariance",						"Test tessellation invariance rules");
7654 
7655 		TestCaseGroup* const invariantPrimitiveSetGroup					= new TestCaseGroup(m_context, "primitive_set",						"Test invariance rule #1");
7656 		TestCaseGroup* const invariantOuterEdgeGroup					= new TestCaseGroup(m_context, "outer_edge_division",				"Test invariance rule #2");
7657 		TestCaseGroup* const symmetricOuterEdgeGroup					= new TestCaseGroup(m_context, "outer_edge_symmetry",				"Test invariance rule #3");
7658 		TestCaseGroup* const outerEdgeVertexSetIndexIndependenceGroup	= new TestCaseGroup(m_context, "outer_edge_index_independence",		"Test invariance rule #4");
7659 		TestCaseGroup* const invariantTriangleSetGroup					= new TestCaseGroup(m_context, "triangle_set",						"Test invariance rule #5");
7660 		TestCaseGroup* const invariantInnerTriangleSetGroup				= new TestCaseGroup(m_context, "inner_triangle_set",				"Test invariance rule #6");
7661 		TestCaseGroup* const invariantOuterTriangleSetGroup				= new TestCaseGroup(m_context, "outer_triangle_set",				"Test invariance rule #7");
7662 		TestCaseGroup* const tessCoordComponentRangeGroup				= new TestCaseGroup(m_context, "tess_coord_component_range",		"Test invariance rule #8, first part");
7663 		TestCaseGroup* const oneMinusTessCoordComponentGroup			= new TestCaseGroup(m_context, "one_minus_tess_coord_component",	"Test invariance rule #8, second part");
7664 
7665 		addChild(invarianceGroup);
7666 		invarianceGroup->addChild(invariantPrimitiveSetGroup);
7667 		invarianceGroup->addChild(invariantOuterEdgeGroup);
7668 		invarianceGroup->addChild(symmetricOuterEdgeGroup);
7669 		invarianceGroup->addChild(outerEdgeVertexSetIndexIndependenceGroup);
7670 		invarianceGroup->addChild(invariantTriangleSetGroup);
7671 		invarianceGroup->addChild(invariantInnerTriangleSetGroup);
7672 		invarianceGroup->addChild(invariantOuterTriangleSetGroup);
7673 		invarianceGroup->addChild(tessCoordComponentRangeGroup);
7674 		invarianceGroup->addChild(oneMinusTessCoordComponentGroup);
7675 
7676 		for (int primitiveTypeI = 0; primitiveTypeI < TESSPRIMITIVETYPE_LAST; primitiveTypeI++)
7677 		{
7678 			const TessPrimitiveType		primitiveType	= (TessPrimitiveType)primitiveTypeI;
7679 			const string				primName		= getTessPrimitiveTypeShaderName(primitiveType);
7680 			const bool					triOrQuad		= primitiveType == TESSPRIMITIVETYPE_TRIANGLES || primitiveType == TESSPRIMITIVETYPE_QUADS;
7681 
7682 			for (int spacingI = 0; spacingI < SPACINGMODE_LAST; spacingI++)
7683 			{
7684 				const SpacingMode	spacing			= (SpacingMode)spacingI;
7685 				const string		primSpacName	= primName + "_" + getSpacingModeShaderName(spacing);
7686 
7687 				if (triOrQuad)
7688 				{
7689 					invariantOuterEdgeGroup->addChild		(new InvariantOuterEdgeCase			(m_context, primSpacName.c_str(), "", primitiveType, spacing));
7690 					invariantTriangleSetGroup->addChild		(new InvariantTriangleSetCase		(m_context, primSpacName.c_str(), "", primitiveType, spacing));
7691 					invariantInnerTriangleSetGroup->addChild(new InvariantInnerTriangleSetCase	(m_context, primSpacName.c_str(), "", primitiveType, spacing));
7692 					invariantOuterTriangleSetGroup->addChild(new InvariantOuterTriangleSetCase	(m_context, primSpacName.c_str(), "", primitiveType, spacing));
7693 				}
7694 
7695 				for (int windingI = 0; windingI < WINDING_LAST; windingI++)
7696 				{
7697 					const Winding	winding				= (Winding)windingI;
7698 					const string	primSpacWindName	= primSpacName + "_" + getWindingShaderName(winding);
7699 
7700 					for (int usePointModeI = 0; usePointModeI <= 1; usePointModeI++)
7701 					{
7702 						const bool		usePointMode			= usePointModeI != 0;
7703 						const string	primSpacWindPointName	= primSpacWindName + (usePointMode ? "_point_mode" : "");
7704 
7705 						invariantPrimitiveSetGroup->addChild		(new InvariantPrimitiveSetCase			(m_context, primSpacWindPointName.c_str(), "", primitiveType, spacing, winding, usePointMode));
7706 						symmetricOuterEdgeGroup->addChild			(new SymmetricOuterEdgeCase				(m_context, primSpacWindPointName.c_str(), "", primitiveType, spacing, winding, usePointMode));
7707 						tessCoordComponentRangeGroup->addChild		(new TessCoordComponentRangeCase		(m_context, primSpacWindPointName.c_str(), "", primitiveType, spacing, winding, usePointMode));
7708 						oneMinusTessCoordComponentGroup->addChild	(new OneMinusTessCoordComponentCase		(m_context, primSpacWindPointName.c_str(), "", primitiveType, spacing, winding, usePointMode));
7709 
7710 						if (triOrQuad)
7711 							outerEdgeVertexSetIndexIndependenceGroup->addChild(new OuterEdgeVertexSetIndexIndependenceCase(m_context, primSpacWindPointName.c_str(), "",
7712 																														   primitiveType, spacing, winding, usePointMode));
7713 					}
7714 				}
7715 			}
7716 		}
7717 	}
7718 
7719 	{
7720 		static const struct
7721 		{
7722 			const char*					name;
7723 			const char*					description;
7724 			UserDefinedIOCase::IOType	ioType;
7725 		} ioCases[] =
7726 		{
7727 			{ "per_patch",					"Per-patch TCS outputs",					UserDefinedIOCase::IO_TYPE_PER_PATCH				},
7728 			{ "per_patch_array",			"Per-patch array TCS outputs",				UserDefinedIOCase::IO_TYPE_PER_PATCH_ARRAY			},
7729 			{ "per_patch_block",			"Per-patch TCS outputs in IO block",		UserDefinedIOCase::IO_TYPE_PER_PATCH_BLOCK			},
7730 			{ "per_patch_block_array",		"Per-patch TCS outputs in IO block array",	UserDefinedIOCase::IO_TYPE_PER_PATCH_BLOCK_ARRAY	},
7731 			{ "per_vertex",					"Per-vertex TCS outputs",					UserDefinedIOCase::IO_TYPE_PER_VERTEX				},
7732 			{ "per_vertex_block",			"Per-vertex TCS outputs in IO block",		UserDefinedIOCase::IO_TYPE_PER_VERTEX_BLOCK			},
7733 		};
7734 
7735 		TestCaseGroup* const userDefinedIOGroup = new TestCaseGroup(m_context, "user_defined_io", "Test non-built-in per-patch and per-vertex inputs and outputs");
7736 		addChild(userDefinedIOGroup);
7737 
7738 		for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(ioCases); ++ndx)
7739 		{
7740 			TestCaseGroup* const ioTypeGroup = new TestCaseGroup(m_context, ioCases[ndx].name, ioCases[ndx].description);
7741 			userDefinedIOGroup->addChild(ioTypeGroup);
7742 
7743 			for (int vertexArraySizeI = 0; vertexArraySizeI < UserDefinedIOCase::VERTEX_IO_ARRAY_SIZE_LAST; vertexArraySizeI++)
7744 			{
7745 				const UserDefinedIOCase::VertexIOArraySize	vertexArraySize			= (UserDefinedIOCase::VertexIOArraySize)vertexArraySizeI;
7746 				TestCaseGroup* const						vertexArraySizeGroup	= new TestCaseGroup(m_context,
7747 																										vertexArraySizeI == UserDefinedIOCase::VERTEX_IO_ARRAY_SIZE_IMPLICIT
7748 																											? "vertex_io_array_size_implicit"
7749 																									  : vertexArraySizeI == UserDefinedIOCase::VERTEX_IO_ARRAY_SIZE_EXPLICIT_SHADER_BUILTIN
7750 																											? "vertex_io_array_size_shader_builtin"
7751 																									  : vertexArraySizeI == UserDefinedIOCase::VERTEX_IO_ARRAY_SIZE_EXPLICIT_QUERY
7752 																											? "vertex_io_array_size_query"
7753 																									  : DE_NULL,
7754 																									    "");
7755 				ioTypeGroup->addChild(vertexArraySizeGroup);
7756 
7757 				for (int primitiveTypeI = 0; primitiveTypeI < TESSPRIMITIVETYPE_LAST; primitiveTypeI++)
7758 				{
7759 					const TessPrimitiveType primitiveType = (TessPrimitiveType)primitiveTypeI;
7760 					vertexArraySizeGroup->addChild(new UserDefinedIOCase(m_context, getTessPrimitiveTypeShaderName(primitiveType), "", primitiveType, ioCases[ndx].ioType, vertexArraySize, UserDefinedIOCase::TESS_CONTROL_OUT_ARRAY_SIZE_IMPLICIT,
7761 																		 (string() + "data/tessellation/user_defined_io_" + getTessPrimitiveTypeShaderName(primitiveType) + "_ref.png").c_str()));
7762 				}
7763 
7764 				if (ioCases[ndx].ioType == UserDefinedIOCase::IO_TYPE_PER_VERTEX
7765 					|| ioCases[ndx].ioType == UserDefinedIOCase::IO_TYPE_PER_VERTEX_BLOCK)
7766 				{
7767 					for (int primitiveTypeI = 0; primitiveTypeI < TESSPRIMITIVETYPE_LAST; primitiveTypeI++)
7768 					{
7769 						const TessPrimitiveType primitiveType = (TessPrimitiveType)primitiveTypeI;
7770 						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,
7771 																			 (string() + "data/tessellation/user_defined_io_" + getTessPrimitiveTypeShaderName(primitiveType) + "_ref.png").c_str()));
7772 					}
7773 				}
7774 			}
7775 		}
7776 
7777 		// ES only
7778 		if (!m_isGL45)
7779 		{
7780 			de::MovePtr<TestCaseGroup>	negativeGroup	(new TestCaseGroup(m_context, "negative", "Negative cases"));
7781 
7782 			{
7783 				de::MovePtr<TestCaseGroup>			es31Group		(new TestCaseGroup(m_context, "es31", "GLSL ES 3.1 Negative cases"));
7784 				gls::ShaderLibrary					shaderLibrary	(m_testCtx, m_context.getRenderContext(), m_context.getContextInfo());
7785 				const std::vector<tcu::TestNode*>	children		= shaderLibrary.loadShaderFile("shaders/es31/tessellation_negative_user_defined_io.test");
7786 
7787 				for (int i = 0; i < (int)children.size(); i++)
7788 					es31Group->addChild(children[i]);
7789 
7790 				negativeGroup->addChild(es31Group.release());
7791 			}
7792 
7793 			{
7794 				de::MovePtr<TestCaseGroup>			es32Group		(new TestCaseGroup(m_context, "es32", "GLSL ES 3.2 Negative cases"));
7795 				gls::ShaderLibrary					shaderLibrary	(m_testCtx, m_context.getRenderContext(), m_context.getContextInfo());
7796 				const std::vector<tcu::TestNode*>	children		= shaderLibrary.loadShaderFile("shaders/es32/tessellation_negative_user_defined_io.test");
7797 
7798 				for (int i = 0; i < (int)children.size(); i++)
7799 					es32Group->addChild(children[i]);
7800 
7801 				negativeGroup->addChild(es32Group.release());
7802 			}
7803 
7804 			userDefinedIOGroup->addChild(negativeGroup.release());
7805 		}
7806 	}
7807 }
7808 
7809 } // Functional
7810 } // gles31
7811 } // deqp
7812