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