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