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