Home | History | Annotate | Download | only in functional
      1 /*-------------------------------------------------------------------------
      2  * drawElements Quality Program OpenGL ES 3.0 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 Transform feedback tests.
     22  *//*--------------------------------------------------------------------*/
     23 
     24 #include "es3fTransformFeedbackTests.hpp"
     25 #include "tcuTestLog.hpp"
     26 #include "tcuSurface.hpp"
     27 #include "tcuImageCompare.hpp"
     28 #include "tcuVector.hpp"
     29 #include "tcuFormatUtil.hpp"
     30 #include "tcuRenderTarget.hpp"
     31 #include "gluShaderUtil.hpp"
     32 #include "gluVarType.hpp"
     33 #include "gluVarTypeUtil.hpp"
     34 #include "gluPixelTransfer.hpp"
     35 #include "gluRenderContext.hpp"
     36 #include "gluShaderProgram.hpp"
     37 #include "gluObjectWrapper.hpp"
     38 #include "glwFunctions.hpp"
     39 #include "glwEnums.hpp"
     40 #include "deRandom.hpp"
     41 #include "deStringUtil.hpp"
     42 #include "deMemory.h"
     43 #include "deString.h"
     44 
     45 #include <set>
     46 #include <map>
     47 #include <algorithm>
     48 
     49 using std::string;
     50 using std::vector;
     51 using std::set;
     52 
     53 using std::map;
     54 using std::set;
     55 
     56 using tcu::TestLog;
     57 
     58 namespace deqp
     59 {
     60 namespace gles3
     61 {
     62 namespace Functional
     63 {
     64 namespace TransformFeedback
     65 {
     66 
     67 enum
     68 {
     69 	VIEWPORT_WIDTH			= 128,
     70 	VIEWPORT_HEIGHT			= 128,
     71 	BUFFER_GUARD_MULTIPLIER = 2		//!< stride*BUFFER_GUARD_MULTIPLIER bytes are added to the end of tf buffer and used to check for overruns.
     72 };
     73 
     74 enum Interpolation
     75 {
     76 	INTERPOLATION_SMOOTH = 0,
     77 	INTERPOLATION_FLAT,
     78 	INTERPOLATION_CENTROID,
     79 
     80 	INTERPOLATION_LAST
     81 };
     82 
     83 static const char* getInterpolationName (Interpolation interp)
     84 {
     85 	switch (interp)
     86 	{
     87 		case INTERPOLATION_SMOOTH:		return "smooth";
     88 		case INTERPOLATION_FLAT:		return "flat";
     89 		case INTERPOLATION_CENTROID:	return "centroid";
     90 		default:
     91 			DE_ASSERT(false);
     92 			return DE_NULL;
     93 	}
     94 }
     95 
     96 struct Varying
     97 {
     98 						Varying				(const char* name_, const glu::VarType& type_, Interpolation interp_)
     99 							: name			(name_)
    100 							, type			(type_)
    101 							, interpolation	(interp_)
    102 						{
    103 						}
    104 
    105 	std::string			name;				//!< Variable name.
    106 	glu::VarType		type;				//!< Variable type.
    107 	Interpolation		interpolation;		//!< Interpolation mode (smooth, flat, centroid).
    108 };
    109 
    110 struct VaryingNameEquals
    111 {
    112 					VaryingNameEquals	(const std::string& name_) : name(name_) {}
    113 	bool			operator()			(const Varying& var) const { return var.name == name; }
    114 
    115 	std::string		name;
    116 };
    117 
    118 struct Attribute
    119 {
    120 	Attribute (const std::string& name_, const glu::VarType& type_, int offset_)
    121 		: name		(name_)
    122 		, type		(type_)
    123 		, offset	(offset_)
    124 	{
    125 	}
    126 
    127 	std::string			name;
    128 	glu::VarType		type;
    129 	int					offset;
    130 };
    131 
    132 struct AttributeNameEquals
    133 {
    134 					AttributeNameEquals	(const std::string& name_) : name(name_) {}
    135 	bool			operator()			(const Attribute& attr) const { return attr.name == name; }
    136 
    137 	std::string		name;
    138 };
    139 
    140 struct Output
    141 {
    142 	Output (void)
    143 		: bufferNdx	(0)
    144 		, offset	(0)
    145 	{
    146 	}
    147 
    148 	std::string					name;
    149 	glu::VarType				type;
    150 	int							bufferNdx;
    151 	int							offset;
    152 	vector<const Attribute*>	inputs;
    153 };
    154 
    155 struct DrawCall
    156 {
    157 				DrawCall (int numElements_, bool tfEnabled_)
    158 					: numElements				(numElements_)
    159 					, transformFeedbackEnabled	(tfEnabled_)
    160 				{
    161 				}
    162 
    163 				DrawCall (void)
    164 					: numElements				(0)
    165 					, transformFeedbackEnabled	(false)
    166 				{
    167 				}
    168 
    169 	int			numElements;
    170 	bool		transformFeedbackEnabled;
    171 };
    172 
    173 std::ostream& operator<< (std::ostream& str, const DrawCall& call)
    174 {
    175 	return str << "(" << call.numElements << ", " << (call.transformFeedbackEnabled ? "resumed" : "paused") << ")";
    176 }
    177 
    178 class ProgramSpec
    179 {
    180 public:
    181 									ProgramSpec						(void);
    182 									~ProgramSpec					(void);
    183 
    184 	glu::StructType*				createStruct					(const char* name);
    185 	void							addVarying						(const char* name, const glu::VarType& type, Interpolation interp);
    186 	void							addTransformFeedbackVarying		(const char* name);
    187 
    188 	const vector<glu::StructType*>&	getStructs						(void) const { return m_structs;	}
    189 	const vector<Varying>&			getVaryings						(void) const { return m_varyings;	}
    190 	const vector<string>&			getTransformFeedbackVaryings	(void) const { return m_transformFeedbackVaryings; }
    191 	bool							isPointSizeUsed					(void) const;
    192 
    193 private:
    194 									ProgramSpec						(const ProgramSpec& other);
    195 	ProgramSpec&					operator=						(const ProgramSpec& other);
    196 
    197 	vector<glu::StructType*>		m_structs;
    198 	vector<Varying>					m_varyings;
    199 	vector<string>					m_transformFeedbackVaryings;
    200 };
    201 
    202 // ProgramSpec
    203 
    204 ProgramSpec::ProgramSpec (void)
    205 {
    206 }
    207 
    208 ProgramSpec::~ProgramSpec (void)
    209 {
    210 	for (vector<glu::StructType*>::iterator i = m_structs.begin(); i != m_structs.end(); i++)
    211 		delete *i;
    212 }
    213 
    214 glu::StructType* ProgramSpec::createStruct (const char* name)
    215 {
    216 	m_structs.reserve(m_structs.size()+1);
    217 	m_structs.push_back(new glu::StructType(name));
    218 	return m_structs.back();
    219 }
    220 
    221 void ProgramSpec::addVarying (const char* name, const glu::VarType& type, Interpolation interp)
    222 {
    223 	m_varyings.push_back(Varying(name, type, interp));
    224 }
    225 
    226 void ProgramSpec::addTransformFeedbackVarying (const char* name)
    227 {
    228 	m_transformFeedbackVaryings.push_back(name);
    229 }
    230 
    231 bool ProgramSpec::isPointSizeUsed (void) const
    232 {
    233 	return std::find(m_transformFeedbackVaryings.begin(), m_transformFeedbackVaryings.end(), "gl_PointSize") != m_transformFeedbackVaryings.end();
    234 }
    235 
    236 static bool isProgramSupported (const glw::Functions& gl, const ProgramSpec& spec, deUint32 tfMode)
    237 {
    238 	int		maxVertexAttribs			= 0;
    239 	int		maxTfInterleavedComponents	= 0;
    240 	int		maxTfSeparateAttribs		= 0;
    241 	int		maxTfSeparateComponents		= 0;
    242 
    243 	gl.getIntegerv(GL_MAX_VERTEX_ATTRIBS,								&maxVertexAttribs);
    244 	gl.getIntegerv(GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS,	&maxTfInterleavedComponents);
    245 	gl.getIntegerv(GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS,			&maxTfSeparateAttribs);
    246 	gl.getIntegerv(GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS,		&maxTfSeparateComponents);
    247 
    248 	// Check vertex attribs.
    249 	int totalVertexAttribs	= 1 /* a_position */ + (spec.isPointSizeUsed() ? 1 : 0);
    250 	for (vector<Varying>::const_iterator var = spec.getVaryings().begin(); var != spec.getVaryings().end(); var++)
    251 	{
    252 		for (glu::VectorTypeIterator vecIter = glu::VectorTypeIterator::begin(&var->type); vecIter != glu::VectorTypeIterator::end(&var->type); vecIter++)
    253 			totalVertexAttribs += 1;
    254 	}
    255 
    256 	if (totalVertexAttribs > maxVertexAttribs)
    257 		return false; // Vertex attribute count exceeded.
    258 
    259 	// Check varyings.
    260 	int totalTfComponents	= 0;
    261 	int totalTfAttribs		= 0;
    262 	for (vector<string>::const_iterator iter = spec.getTransformFeedbackVaryings().begin(); iter != spec.getTransformFeedbackVaryings().end(); iter++)
    263 	{
    264 		const string&	name			= *iter;
    265 		int				numComponents	= 0;
    266 
    267 		if (name == "gl_Position")
    268 			numComponents = 4;
    269 		else if (name == "gl_PointSize")
    270 			numComponents = 1;
    271 		else
    272 		{
    273 			string						varName		= glu::parseVariableName(name.c_str());
    274 			const Varying&				varying		= *std::find_if(spec.getVaryings().begin(), spec.getVaryings().end(), VaryingNameEquals(varName));
    275 			glu::TypeComponentVector	varPath;
    276 
    277 			glu::parseTypePath(name.c_str(), varying.type, varPath);
    278 			numComponents = glu::getVarType(varying.type, varPath).getScalarSize();
    279 		}
    280 
    281 		if (tfMode == GL_SEPARATE_ATTRIBS && numComponents > maxTfSeparateComponents)
    282 			return false; // Per-attribute component count exceeded.
    283 
    284 		totalTfComponents	+= numComponents;
    285 		totalTfAttribs		+= 1;
    286 	}
    287 
    288 	if (tfMode == GL_SEPARATE_ATTRIBS && totalTfAttribs > maxTfSeparateAttribs)
    289 		return false;
    290 
    291 	if (tfMode == GL_INTERLEAVED_ATTRIBS && totalTfComponents > maxTfInterleavedComponents)
    292 		return false;
    293 
    294 	return true;
    295 }
    296 
    297 // Program
    298 
    299 static std::string getAttributeName (const char* varyingName, const glu::TypeComponentVector& path)
    300 {
    301 	std::ostringstream str;
    302 
    303 	str << "a_" << (deStringBeginsWith(varyingName, "v_") ? varyingName+2 : varyingName);
    304 
    305 	for (glu::TypeComponentVector::const_iterator iter = path.begin(); iter != path.end(); iter++)
    306 	{
    307 		const char* prefix = DE_NULL;
    308 
    309 		switch (iter->type)
    310 		{
    311 			case glu::VarTypeComponent::STRUCT_MEMBER:		prefix = "_m";	break;
    312 			case glu::VarTypeComponent::ARRAY_ELEMENT:		prefix = "_e";	break;
    313 			case glu::VarTypeComponent::MATRIX_COLUMN:		prefix = "_c";	break;
    314 			case glu::VarTypeComponent::VECTOR_COMPONENT:	prefix = "_s";	break;
    315 			default:
    316 				DE_ASSERT(false);
    317 		}
    318 
    319 		str << prefix << iter->index;
    320 	}
    321 
    322 	return str.str();
    323 }
    324 
    325 static void genShaderSources (const ProgramSpec& spec, std::string& vertSource, std::string& fragSource, bool pointSizeRequired)
    326 {
    327 	std::ostringstream	vtx;
    328 	std::ostringstream	frag;
    329 	bool				addPointSize	= spec.isPointSizeUsed();
    330 
    331 	vtx << "#version 300 es\n"
    332 		<< "in highp vec4 a_position;\n";
    333 	frag << "#version 300 es\n"
    334 		 << "layout(location = 0) out mediump vec4 o_color;\n"
    335 		 << "uniform highp vec4 u_scale;\n"
    336 		 << "uniform highp vec4 u_bias;\n";
    337 
    338 	if (addPointSize)
    339 		vtx << "in highp float a_pointSize;\n";
    340 
    341 	// Declare attributes.
    342 	for (vector<Varying>::const_iterator var = spec.getVaryings().begin(); var != spec.getVaryings().end(); var++)
    343 	{
    344 		const char*			name	= var->name.c_str();
    345 		const glu::VarType&	type	= var->type;
    346 
    347 		for (glu::VectorTypeIterator vecIter = glu::VectorTypeIterator::begin(&type); vecIter != glu::VectorTypeIterator::end(&type); vecIter++)
    348 		{
    349 			glu::VarType	attribType	= glu::getVarType(type, vecIter.getPath());
    350 			string			attribName	= getAttributeName(name, vecIter.getPath());
    351 
    352 			vtx << "in " << glu::declare(attribType, attribName.c_str()) << ";\n";
    353 		}
    354 	}
    355 
    356 	// Declare vayrings.
    357 	for (int ndx = 0; ndx < 2; ndx++)
    358 	{
    359 		const char*			inout	= ndx ? "in" : "out";
    360 		std::ostringstream&	str		= ndx ? frag : vtx;
    361 
    362 		// Declare structs that have type name.
    363 		for (vector<glu::StructType*>::const_iterator structIter = spec.getStructs().begin(); structIter != spec.getStructs().end(); structIter++)
    364 		{
    365 			const glu::StructType* structPtr = *structIter;
    366 			if (structPtr->hasTypeName())
    367 				str << glu::declare(structPtr) << ";\n";
    368 		}
    369 
    370 		for (vector<Varying>::const_iterator var = spec.getVaryings().begin(); var != spec.getVaryings().end(); var++)
    371 			str << getInterpolationName(var->interpolation) << " " << inout << " " << glu::declare(var->type, var->name.c_str()) << ";\n";
    372 	}
    373 
    374 	vtx << "\nvoid main (void)\n{\n"
    375 		<< "\tgl_Position = a_position;\n";
    376 	frag << "\nvoid main (void)\n{\n"
    377 		 << "\thighp vec4 res = vec4(0.0);\n";
    378 
    379 	if (addPointSize)
    380 		vtx << "\tgl_PointSize = a_pointSize;\n";
    381 	else if (pointSizeRequired)
    382 		vtx << "\tgl_PointSize = 1.0;\n";
    383 
    384 	// Generate assignments / usage.
    385 	for (vector<Varying>::const_iterator var = spec.getVaryings().begin(); var != spec.getVaryings().end(); var++)
    386 	{
    387 		const char*			name	= var->name.c_str();
    388 		const glu::VarType&	type	= var->type;
    389 
    390 		for (glu::VectorTypeIterator vecIter = glu::VectorTypeIterator::begin(&type); vecIter != glu::VectorTypeIterator::end(&type); vecIter++)
    391 		{
    392 			glu::VarType	subType		= glu::getVarType(type, vecIter.getPath());
    393 			string			attribName	= getAttributeName(name, vecIter.getPath());
    394 
    395 			DE_ASSERT(subType.isBasicType() && glu::isDataTypeScalarOrVector(subType.getBasicType()));
    396 
    397 			// Vertex: assign from attribute.
    398 			vtx << "\t" << name << vecIter << " = " << attribName << ";\n";
    399 
    400 			// Fragment: add to res variable.
    401 			int scalarSize = glu::getDataTypeScalarSize(subType.getBasicType());
    402 
    403 			frag << "\tres += ";
    404 			if (scalarSize == 1)		frag << "vec4(" << name << vecIter << ")";
    405 			else if (scalarSize == 2)	frag << "vec2(" << name << vecIter << ").xxyy";
    406 			else if (scalarSize == 3)	frag << "vec3(" << name << vecIter << ").xyzx";
    407 			else if (scalarSize == 4)	frag << "vec4(" << name << vecIter << ")";
    408 
    409 			frag << ";\n";
    410 		}
    411 	}
    412 
    413 	frag << "\to_color = res * u_scale + u_bias;\n";
    414 
    415 	vtx << "}\n";
    416 	frag << "}\n";
    417 
    418 	vertSource = vtx.str();
    419 	fragSource = frag.str();
    420 }
    421 
    422 static glu::ShaderProgram* createVertexCaptureProgram (const glu::RenderContext& context, const ProgramSpec& spec, deUint32 bufferMode, deUint32 primitiveType)
    423 {
    424 	std::string vertSource, fragSource;
    425 
    426 	genShaderSources(spec, vertSource, fragSource, primitiveType == GL_POINTS /* Is point size required? */);
    427 
    428 	return new glu::ShaderProgram(context, glu::ProgramSources()
    429 										   << glu::VertexSource(vertSource)
    430 										   << glu::FragmentSource(fragSource)
    431 										   << glu::TransformFeedbackVaryings<vector<string>::const_iterator>(spec.getTransformFeedbackVaryings().begin(), spec.getTransformFeedbackVaryings().end())
    432 										   << glu::TransformFeedbackMode(bufferMode));
    433 }
    434 
    435 // Helpers.
    436 
    437 static void computeInputLayout (vector<Attribute>& attributes, int& inputStride, const vector<Varying>& varyings, bool usePointSize)
    438 {
    439 	inputStride = 0;
    440 
    441 	// Add position.
    442 	attributes.push_back(Attribute("a_position", glu::VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_HIGHP), inputStride));
    443 	inputStride += 4*sizeof(deUint32);
    444 
    445 	if (usePointSize)
    446 	{
    447 		attributes.push_back(Attribute("a_pointSize", glu::VarType(glu::TYPE_FLOAT, glu::PRECISION_HIGHP), inputStride));
    448 		inputStride += 1*sizeof(deUint32);
    449 	}
    450 
    451 	// Compute attribute vector.
    452 	for (vector<Varying>::const_iterator var = varyings.begin(); var != varyings.end(); var++)
    453 	{
    454 		for (glu::VectorTypeIterator vecIter = glu::VectorTypeIterator::begin(&var->type); vecIter != glu::VectorTypeIterator::end(&var->type); vecIter++)
    455 		{
    456 			glu::VarType	type	= vecIter.getType();
    457 			string			name	= getAttributeName(var->name.c_str(), vecIter.getPath());
    458 
    459 			attributes.push_back(Attribute(name, type, inputStride));
    460 			inputStride += glu::getDataTypeScalarSize(type.getBasicType())*sizeof(deUint32);
    461 		}
    462 	}
    463 }
    464 
    465 static void computeTransformFeedbackOutputs (vector<Output>& transformFeedbackOutputs, const vector<Attribute>& attributes, const vector<Varying>& varyings, const vector<string>& transformFeedbackVaryings, deUint32 bufferMode)
    466 {
    467 	int accumulatedSize = 0;
    468 
    469 	transformFeedbackOutputs.resize(transformFeedbackVaryings.size());
    470 	for (int varNdx = 0; varNdx < (int)transformFeedbackVaryings.size(); varNdx++)
    471 	{
    472 		const string&	name		= transformFeedbackVaryings[varNdx];
    473 		int				bufNdx		= (bufferMode == GL_SEPARATE_ATTRIBS ? varNdx : 0);
    474 		int				offset		= (bufferMode == GL_SEPARATE_ATTRIBS ? 0 : accumulatedSize);
    475 		Output&			output		= transformFeedbackOutputs[varNdx];
    476 
    477 		output.name			= name;
    478 		output.bufferNdx	= bufNdx;
    479 		output.offset		= offset;
    480 
    481 		if (name == "gl_Position")
    482 		{
    483 			const Attribute* posIn = &(*std::find_if(attributes.begin(), attributes.end(), AttributeNameEquals("a_position")));
    484 			output.type = posIn->type;
    485 			output.inputs.push_back(posIn);
    486 		}
    487 		else if (name == "gl_PointSize")
    488 		{
    489 			const Attribute* sizeIn = &(*std::find_if(attributes.begin(), attributes.end(), AttributeNameEquals("a_pointSize")));
    490 			output.type = sizeIn->type;
    491 			output.inputs.push_back(sizeIn);
    492 		}
    493 		else
    494 		{
    495 			string						varName		= glu::parseVariableName(name.c_str());
    496 			const Varying&				varying		= *std::find_if(varyings.begin(), varyings.end(), VaryingNameEquals(varName));
    497 			glu::TypeComponentVector	varPath;
    498 
    499 			glu::parseTypePath(name.c_str(), varying.type, varPath);
    500 
    501 			output.type = glu::getVarType(varying.type, varPath);
    502 
    503 			// Add all vectorized attributes as inputs.
    504 			for (glu::VectorTypeIterator iter = glu::VectorTypeIterator::begin(&output.type); iter != glu::VectorTypeIterator::end(&output.type); iter++)
    505 			{
    506 				// Full path.
    507 				glu::TypeComponentVector fullPath(varPath.size() + iter.getPath().size());
    508 
    509 				std::copy(varPath.begin(), varPath.end(), fullPath.begin());
    510 				std::copy(iter.getPath().begin(), iter.getPath().end(), fullPath.begin()+varPath.size());
    511 
    512 				string				attribName	= getAttributeName(varName.c_str(), fullPath);
    513 				const Attribute*	attrib		= &(*std::find_if(attributes.begin(), attributes.end(), AttributeNameEquals(attribName)));
    514 
    515 				output.inputs.push_back(attrib);
    516 			}
    517 		}
    518 
    519 		accumulatedSize += output.type.getScalarSize()*sizeof(deUint32);
    520 	}
    521 }
    522 
    523 static void genAttributeData (const Attribute& attrib, deUint8* basePtr, int stride, int numElements, de::Random& rnd)
    524 {
    525 	const int		elementSize	= (int)sizeof(deUint32);
    526 	bool			isFloat		= glu::isDataTypeFloatOrVec(attrib.type.getBasicType());
    527 	bool			isInt		= glu::isDataTypeIntOrIVec(attrib.type.getBasicType());
    528 	bool			isUint		= glu::isDataTypeIntOrIVec(attrib.type.getBasicType());
    529 	glu::Precision	precision	= attrib.type.getPrecision();
    530 	int				numComps	= glu::getDataTypeScalarSize(attrib.type.getBasicType());
    531 
    532 	for (int elemNdx = 0; elemNdx < numElements; elemNdx++)
    533 	{
    534 		for (int compNdx = 0; compNdx < numComps; compNdx++)
    535 		{
    536 			int offset = attrib.offset+elemNdx*stride+compNdx*elementSize;
    537 			if (isFloat)
    538 			{
    539 				float* comp = (float*)(basePtr+offset);
    540 				switch (precision)
    541 				{
    542 					case glu::PRECISION_LOWP:		*comp = 0.0f + 0.25f*(float)rnd.getInt(0, 4);	break;
    543 					case glu::PRECISION_MEDIUMP:	*comp = rnd.getFloat(-1e3f, 1e3f);				break;
    544 					case glu::PRECISION_HIGHP:		*comp = rnd.getFloat(-1e5f, 1e5f);				break;
    545 					default:
    546 						DE_ASSERT(false);
    547 				}
    548 			}
    549 			else if (isInt)
    550 			{
    551 				int* comp = (int*)(basePtr+offset);
    552 				switch (precision)
    553 				{
    554 					case glu::PRECISION_LOWP:		*comp = (int)(rnd.getUint32()&0xff) << 24 >> 24;	break;
    555 					case glu::PRECISION_MEDIUMP:	*comp = (int)(rnd.getUint32()&0xffff) << 16 >> 16;	break;
    556 					case glu::PRECISION_HIGHP:		*comp = (int)rnd.getUint32();						break;
    557 					default:
    558 						DE_ASSERT(false);
    559 				}
    560 			}
    561 			else if (isUint)
    562 			{
    563 				deUint32* comp = (deUint32*)(basePtr+offset);
    564 				switch (precision)
    565 				{
    566 					case glu::PRECISION_LOWP:		*comp = rnd.getUint32()&0xff;	break;
    567 					case glu::PRECISION_MEDIUMP:	*comp = rnd.getUint32()&0xffff;	break;
    568 					case glu::PRECISION_HIGHP:		*comp = rnd.getUint32();		break;
    569 					default:
    570 						DE_ASSERT(false);
    571 				}
    572 			}
    573 		}
    574 	}
    575 }
    576 
    577 static void genInputData (const vector<Attribute>& attributes, int numInputs, int inputStride, deUint8* inputBasePtr, de::Random& rnd)
    578 {
    579 	// Random positions.
    580 	const Attribute& position = *std::find_if(attributes.begin(), attributes.end(), AttributeNameEquals("a_position"));
    581 
    582 	for (int ndx = 0; ndx < numInputs; ndx++)
    583 	{
    584 		deUint8* ptr = inputBasePtr + position.offset + inputStride*ndx;
    585 		*((float*)(ptr+ 0)) = rnd.getFloat(-1.2f, 1.2f);
    586 		*((float*)(ptr+ 4)) = rnd.getFloat(-1.2f, 1.2f);
    587 		*((float*)(ptr+ 8)) = rnd.getFloat(-1.2f, 1.2f);
    588 		*((float*)(ptr+12)) = rnd.getFloat(0.1f, 2.0f);
    589 	}
    590 
    591 	// Point size.
    592 	vector<Attribute>::const_iterator pointSizePos = std::find_if(attributes.begin(), attributes.end(), AttributeNameEquals("a_pointSize"));
    593 	if (pointSizePos != attributes.end())
    594 	{
    595 		for (int ndx = 0; ndx < numInputs; ndx++)
    596 		{
    597 			deUint8* ptr = inputBasePtr + pointSizePos->offset + inputStride*ndx;
    598 			*((float*)ptr) = rnd.getFloat(1.0f, 8.0f);
    599 		}
    600 	}
    601 
    602 	// Random data for rest of components.
    603 	for (vector<Attribute>::const_iterator attrib = attributes.begin(); attrib != attributes.end(); attrib++)
    604 	{
    605 		if (attrib->name == "a_position" || attrib->name == "a_pointSize")
    606 			continue;
    607 
    608 		genAttributeData(*attrib, inputBasePtr, inputStride, numInputs, rnd);
    609 	}
    610 }
    611 
    612 static deUint32 getTransformFeedbackOutputCount (deUint32 primitiveType, int numElements)
    613 {
    614 	switch (primitiveType)
    615 	{
    616 		case GL_TRIANGLES:			return numElements - numElements%3;
    617 		case GL_TRIANGLE_STRIP:		return de::max(0, numElements-2)*3;
    618 		case GL_TRIANGLE_FAN:		return de::max(0, numElements-2)*3;
    619 		case GL_LINES:				return numElements - numElements%2;
    620 		case GL_LINE_STRIP:			return de::max(0, numElements-1)*2;
    621 		case GL_LINE_LOOP:			return numElements > 1 ? numElements*2 : 0;
    622 		case GL_POINTS:				return numElements;
    623 
    624 		default:
    625 			DE_ASSERT(false);
    626 			return 0;
    627 	}
    628 }
    629 
    630 static deUint32 getTransformFeedbackPrimitiveCount (deUint32 primitiveType, int numElements)
    631 {
    632 	switch (primitiveType)
    633 	{
    634 		case GL_TRIANGLES:			return numElements/3;
    635 		case GL_TRIANGLE_STRIP:		return de::max(0, numElements-2);
    636 		case GL_TRIANGLE_FAN:		return de::max(0, numElements-2);
    637 		case GL_LINES:				return numElements/2;
    638 		case GL_LINE_STRIP:			return de::max(0, numElements-1);
    639 		case GL_LINE_LOOP:			return numElements > 1 ? numElements : 0;
    640 		case GL_POINTS:				return numElements;
    641 
    642 		default:
    643 			DE_ASSERT(false);
    644 			return 0;
    645 	}
    646 }
    647 
    648 static deUint32 getTransformFeedbackPrimitiveMode (deUint32 primitiveType)
    649 {
    650 	switch (primitiveType)
    651 	{
    652 		case GL_TRIANGLES:
    653 		case GL_TRIANGLE_STRIP:
    654 		case GL_TRIANGLE_FAN:
    655 			return GL_TRIANGLES;
    656 
    657 		case GL_LINES:
    658 		case GL_LINE_LOOP:
    659 		case GL_LINE_STRIP:
    660 			return GL_LINES;
    661 
    662 		case GL_POINTS:
    663 			return GL_POINTS;
    664 
    665 		default:
    666 			DE_ASSERT(false);
    667 			return 0;
    668 	}
    669 }
    670 
    671 static int getAttributeIndex (deUint32 primitiveType, int numInputs, int outNdx)
    672 {
    673 	switch (primitiveType)
    674 	{
    675 		case GL_TRIANGLES:			return outNdx;
    676 		case GL_LINES:				return outNdx;
    677 		case GL_POINTS:				return outNdx;
    678 
    679 		case GL_TRIANGLE_STRIP:
    680 		{
    681 			int triNdx = outNdx/3;
    682 			int vtxNdx = outNdx%3;
    683 			return (triNdx%2 != 0 && vtxNdx < 2) ? (triNdx+1-vtxNdx) : (triNdx+vtxNdx);
    684 		}
    685 
    686 		case GL_TRIANGLE_FAN:
    687 			return (outNdx%3 != 0) ? (outNdx/3 + outNdx%3) : 0;
    688 
    689 		case GL_LINE_STRIP:
    690 			return outNdx/2 + outNdx%2;
    691 
    692 		case GL_LINE_LOOP:
    693 		{
    694 			int inNdx = outNdx/2 + outNdx%2;
    695 			return inNdx < numInputs ? inNdx : 0;
    696 		}
    697 
    698 		default:
    699 			DE_ASSERT(false);
    700 			return 0;
    701 	}
    702 }
    703 
    704 static bool compareTransformFeedbackOutput (tcu::TestLog& log, deUint32 primitiveType, const Output& output, int numInputs, const deUint8* inBasePtr, int inStride, const deUint8* outBasePtr, int outStride)
    705 {
    706 	bool		isOk		= true;
    707 	int			outOffset	= output.offset;
    708 
    709 	for (int attrNdx = 0; attrNdx < (int)output.inputs.size(); attrNdx++)
    710 	{
    711 		const Attribute&	attribute		= *output.inputs[attrNdx];
    712 		glu::DataType		type			= attribute.type.getBasicType();
    713 		int					numComponents	= glu::getDataTypeScalarSize(type);
    714 		glu::Precision		precision		= attribute.type.getPrecision();
    715 		glu::DataType		scalarType		= glu::getDataTypeScalarType(type);
    716 		int					numOutputs		= getTransformFeedbackOutputCount(primitiveType, numInputs);
    717 
    718 		for (int outNdx = 0; outNdx < numOutputs; outNdx++)
    719 		{
    720 			int inNdx = getAttributeIndex(primitiveType, numInputs, outNdx);
    721 
    722 			for (int compNdx = 0; compNdx < numComponents; compNdx++)
    723 			{
    724 				const deUint8*	inPtr	= inBasePtr + inStride*inNdx + attribute.offset + compNdx*sizeof(deUint32);
    725 				const deUint8*	outPtr	= outBasePtr + outStride*outNdx + outOffset + compNdx*sizeof(deUint32);
    726 				deUint32		inVal	= *(const deUint32*)inPtr;
    727 				deUint32		outVal	= *(const deUint32*)outPtr;
    728 				bool			isEqual	= false;
    729 
    730 				if (scalarType == glu::TYPE_FLOAT)
    731 				{
    732 					// ULP comparison is used for highp and mediump. Lowp uses threshold-comparison.
    733 					switch (precision)
    734 					{
    735 						case glu::PRECISION_HIGHP:		isEqual = de::abs((int)inVal - (int)outVal) < 2;				break;
    736 						case glu::PRECISION_MEDIUMP:	isEqual = de::abs((int)inVal - (int)outVal) < 2+(1<<13);		break;
    737 						case glu::PRECISION_LOWP:
    738 						{
    739 							float inF	= *(const float*)inPtr;
    740 							float outF	= *(const float*)outPtr;
    741 							isEqual = de::abs(inF - outF) < 0.1f;
    742 							break;
    743 						}
    744 						default:
    745 							DE_ASSERT(false);
    746 					}
    747 				}
    748 				else
    749 					isEqual = (inVal == outVal); // Bit-exact match required for integer types.
    750 
    751 				if (!isEqual)
    752 				{
    753 					log << TestLog::Message << "Mismatch in " << output.name << " (" << attribute.name << "), output = " << outNdx << ", input = " << inNdx << ", component = " << compNdx << TestLog::EndMessage;
    754 					isOk = false;
    755 					break;
    756 				}
    757 			}
    758 
    759 			if (!isOk)
    760 				break;
    761 		}
    762 
    763 		if (!isOk)
    764 			break;
    765 
    766 		outOffset += numComponents*sizeof(deUint32);
    767 	}
    768 
    769 	return isOk;
    770 }
    771 
    772 static int computeTransformFeedbackPrimitiveCount (deUint32 primitiveType, const DrawCall* first, const DrawCall* end)
    773 {
    774 	int primCount = 0;
    775 
    776 	for (const DrawCall* call = first; call != end; ++call)
    777 	{
    778 		if (call->transformFeedbackEnabled)
    779 			primCount += getTransformFeedbackPrimitiveCount(primitiveType, call->numElements);
    780 	}
    781 
    782 	return primCount;
    783 }
    784 
    785 static void writeBufferGuard (const glw::Functions& gl, deUint32 target, int bufferSize, int guardSize)
    786 {
    787 	deUint8* ptr = (deUint8*)gl.mapBufferRange(target, bufferSize, guardSize, GL_MAP_WRITE_BIT);
    788 	if (ptr)
    789 		deMemset(ptr, 0xcd, guardSize);
    790 	gl.unmapBuffer(target);
    791 	GLU_EXPECT_NO_ERROR(gl.getError(), "guardband write");
    792 }
    793 
    794 static bool verifyGuard (const deUint8* ptr, int guardSize)
    795 {
    796 	for (int ndx = 0; ndx < guardSize; ndx++)
    797 	{
    798 		if (ptr[ndx] != 0xcd)
    799 			return false;
    800 	}
    801 	return true;
    802 }
    803 
    804 static void logTransformFeedbackVaryings (TestLog& log, const glw::Functions& gl, deUint32 program)
    805 {
    806 	int numTfVaryings	= 0;
    807 	int	maxNameLen		= 0;
    808 
    809 	gl.getProgramiv(program, GL_TRANSFORM_FEEDBACK_VARYINGS, &numTfVaryings);
    810 	gl.getProgramiv(program, GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH, &maxNameLen);
    811 	GLU_EXPECT_NO_ERROR(gl.getError(), "Query TF varyings");
    812 
    813 	log << TestLog::Message << "GL_TRANSFORM_FEEDBACK_VARYINGS = " << numTfVaryings << TestLog::EndMessage;
    814 
    815 	vector<char> nameBuf(maxNameLen+1);
    816 
    817 	for (int ndx = 0; ndx < numTfVaryings; ndx++)
    818 	{
    819 		glw::GLsizei	size	= 0;
    820 		glw::GLenum		type	= 0;
    821 
    822 		gl.getTransformFeedbackVarying(program, ndx, (glw::GLsizei)nameBuf.size(), DE_NULL, &size, &type, &nameBuf[0]);
    823 		GLU_EXPECT_NO_ERROR(gl.getError(), "glGetTransformFeedbackVarying()");
    824 
    825 		const glu::DataType	dataType	= glu::getDataTypeFromGLType(type);
    826 		const std::string	typeName	= dataType != glu::TYPE_LAST ? std::string(glu::getDataTypeName(dataType))
    827 																	 : (std::string("unknown(") + tcu::toHex(type).toString() + ")");
    828 
    829 		log << TestLog::Message << (const char*)&nameBuf[0] << ": " << typeName << "[" << size << "]" << TestLog::EndMessage;
    830 	}
    831 }
    832 
    833 class TransformFeedbackCase : public TestCase
    834 {
    835 public:
    836 								TransformFeedbackCase		(Context& context, const char* name, const char* desc, deUint32 bufferMode, deUint32 primitiveType);
    837 								~TransformFeedbackCase		(void);
    838 
    839 	void						init						(void);
    840 	void						deinit						(void);
    841 	IterateResult				iterate						(void);
    842 
    843 protected:
    844 	ProgramSpec					m_progSpec;
    845 	deUint32					m_bufferMode;
    846 	deUint32					m_primitiveType;
    847 
    848 private:
    849 								TransformFeedbackCase		(const TransformFeedbackCase& other);
    850 	TransformFeedbackCase&		operator=					(const TransformFeedbackCase& other);
    851 
    852 	bool						runTest						(const DrawCall* first, const DrawCall* end, deUint32 seed);
    853 
    854 	// Derived from ProgramSpec in init()
    855 	int							m_inputStride;
    856 	vector<Attribute>			m_attributes;
    857 	vector<Output>				m_transformFeedbackOutputs;
    858 	vector<int>					m_bufferStrides;
    859 
    860 	// GL state.
    861 	glu::ShaderProgram*			m_program;
    862 	glu::TransformFeedback*		m_transformFeedback;
    863 	vector<deUint32>			m_outputBuffers;
    864 
    865 	int							m_iterNdx;
    866 };
    867 
    868 TransformFeedbackCase::TransformFeedbackCase (Context& context, const char* name, const char* desc, deUint32 bufferMode, deUint32 primitiveType)
    869 	: TestCase				(context, name, desc)
    870 	, m_bufferMode			(bufferMode)
    871 	, m_primitiveType		(primitiveType)
    872 	, m_inputStride			(0)
    873 	, m_program				(DE_NULL)
    874 	, m_transformFeedback	(DE_NULL)
    875 	, m_iterNdx				(0)
    876 {
    877 }
    878 
    879 TransformFeedbackCase::~TransformFeedbackCase (void)
    880 {
    881 	TransformFeedbackCase::deinit();
    882 }
    883 
    884 static bool hasArraysInTFVaryings (const ProgramSpec& spec)
    885 {
    886 	for (vector<string>::const_iterator tfVar = spec.getTransformFeedbackVaryings().begin(); tfVar != spec.getTransformFeedbackVaryings().end(); ++tfVar)
    887 	{
    888 		string							varName	= glu::parseVariableName(tfVar->c_str());
    889 		vector<Varying>::const_iterator	varIter	= std::find_if(spec.getVaryings().begin(), spec.getVaryings().end(), VaryingNameEquals(varName));
    890 
    891 		if (varName == "gl_Position" || varName == "gl_PointSize")
    892 			continue;
    893 
    894 		DE_ASSERT(varIter != spec.getVaryings().end());
    895 
    896 		if (varIter->type.isArrayType())
    897 			return true;
    898 	}
    899 
    900 	return false;
    901 }
    902 
    903 void TransformFeedbackCase::init (void)
    904 {
    905 	TestLog&				log	= m_testCtx.getLog();
    906 	const glw::Functions&	gl	= m_context.getRenderContext().getFunctions();
    907 
    908 	DE_ASSERT(!m_program);
    909 	m_program = createVertexCaptureProgram(m_context.getRenderContext(), m_progSpec, m_bufferMode, m_primitiveType);
    910 
    911 	log << *m_program;
    912 	if (!m_program->isOk())
    913 	{
    914 		const bool linkFail = m_program->getShaderInfo(glu::SHADERTYPE_VERTEX).compileOk &&
    915 							  m_program->getShaderInfo(glu::SHADERTYPE_FRAGMENT).compileOk &&
    916 							  !m_program->getProgramInfo().linkOk;
    917 
    918 		if (linkFail)
    919 		{
    920 			if (!isProgramSupported(gl, m_progSpec, m_bufferMode))
    921 				throw tcu::NotSupportedError("Implementation limits execeeded", "", __FILE__, __LINE__);
    922 			else if (hasArraysInTFVaryings(m_progSpec))
    923 				throw tcu::NotSupportedError("Capturing arrays is not supported (undefined in specification)", "", __FILE__, __LINE__);
    924 			else
    925 				throw tcu::TestError("Link failed", "", __FILE__, __LINE__);
    926 		}
    927 		else
    928 			throw tcu::TestError("Compile failed", "", __FILE__, __LINE__);
    929 	}
    930 
    931 	log << TestLog::Message << "Transform feedback varyings: " << tcu::formatArray(m_progSpec.getTransformFeedbackVaryings().begin(), m_progSpec.getTransformFeedbackVaryings().end()) << TestLog::EndMessage;
    932 
    933 	// Print out transform feedback points reported by GL.
    934 	log << TestLog::Message << "Transform feedback varyings reported by compiler:" << TestLog::EndMessage;
    935 	logTransformFeedbackVaryings(log, gl, m_program->getProgram());
    936 
    937 	// Compute input specification.
    938 	computeInputLayout(m_attributes, m_inputStride, m_progSpec.getVaryings(), m_progSpec.isPointSizeUsed());
    939 
    940 	// Build list of varyings used in transform feedback.
    941 	computeTransformFeedbackOutputs(m_transformFeedbackOutputs, m_attributes, m_progSpec.getVaryings(), m_progSpec.getTransformFeedbackVaryings(), m_bufferMode);
    942 	DE_ASSERT(!m_transformFeedbackOutputs.empty());
    943 
    944 	// Buffer strides.
    945 	DE_ASSERT(m_bufferStrides.empty());
    946 	if (m_bufferMode == GL_SEPARATE_ATTRIBS)
    947 	{
    948 		for (vector<Output>::const_iterator outIter = m_transformFeedbackOutputs.begin(); outIter != m_transformFeedbackOutputs.end(); outIter++)
    949 			m_bufferStrides.push_back(outIter->type.getScalarSize()*sizeof(deUint32));
    950 	}
    951 	else
    952 	{
    953 		int totalSize = 0;
    954 		for (vector<Output>::const_iterator outIter = m_transformFeedbackOutputs.begin(); outIter != m_transformFeedbackOutputs.end(); outIter++)
    955 			totalSize += outIter->type.getScalarSize()*sizeof(deUint32);
    956 
    957 		m_bufferStrides.push_back(totalSize);
    958 	}
    959 
    960 	// \note Actual storage is allocated in iterate().
    961 	m_outputBuffers.resize(m_bufferStrides.size());
    962 	gl.genBuffers((glw::GLsizei)m_outputBuffers.size(), &m_outputBuffers[0]);
    963 
    964 	DE_ASSERT(!m_transformFeedback);
    965 	m_transformFeedback = new glu::TransformFeedback(m_context.getRenderContext());
    966 
    967 	GLU_EXPECT_NO_ERROR(gl.getError(), "init");
    968 
    969 	m_iterNdx = 0;
    970 	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
    971 }
    972 
    973 void TransformFeedbackCase::deinit (void)
    974 {
    975 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
    976 
    977 	if (!m_outputBuffers.empty())
    978 	{
    979 		gl.deleteBuffers((glw::GLsizei)m_outputBuffers.size(), &m_outputBuffers[0]);
    980 		m_outputBuffers.clear();
    981 	}
    982 
    983 	delete m_transformFeedback;
    984 	m_transformFeedback = DE_NULL;
    985 
    986 	delete m_program;
    987 	m_program = DE_NULL;
    988 
    989 	// Clean up state.
    990 	m_attributes.clear();
    991 	m_transformFeedbackOutputs.clear();
    992 	m_bufferStrides.clear();
    993 	m_inputStride = 0;
    994 }
    995 
    996 TransformFeedbackCase::IterateResult TransformFeedbackCase::iterate (void)
    997 {
    998 	// Test cases.
    999 	static const DrawCall s_elemCount1[]	= { DrawCall(1, true) };
   1000 	static const DrawCall s_elemCount2[]	= { DrawCall(2, true) };
   1001 	static const DrawCall s_elemCount3[]	= { DrawCall(3, true) };
   1002 	static const DrawCall s_elemCount4[]	= { DrawCall(4, true) };
   1003 	static const DrawCall s_elemCount123[]	= { DrawCall(123, true) };
   1004 	static const DrawCall s_basicPause1[]	= { DrawCall(64, true), DrawCall(64, false), DrawCall(64, true) };
   1005 	static const DrawCall s_basicPause2[]	= { DrawCall(13, true), DrawCall(5, true), DrawCall(17, false), DrawCall(3, true), DrawCall(7, false) };
   1006 	static const DrawCall s_startPaused[]	= { DrawCall(123, false), DrawCall(123, true) };
   1007 	static const DrawCall s_random1[]		= { DrawCall(65, true), DrawCall(135, false), DrawCall(74, true), DrawCall(16, false), DrawCall(226, false), DrawCall(9, true), DrawCall(174, false) };
   1008 	static const DrawCall s_random2[]		= { DrawCall(217, true), DrawCall(171, true), DrawCall(147, true), DrawCall(152, false), DrawCall(55, true) };
   1009 
   1010 	static const struct
   1011 	{
   1012 		const DrawCall*		calls;
   1013 		int					numCalls;
   1014 	} s_iterations[] =
   1015 	{
   1016 #define ITER(ARR) { ARR, DE_LENGTH_OF_ARRAY(ARR) }
   1017 		ITER(s_elemCount1),
   1018 		ITER(s_elemCount2),
   1019 		ITER(s_elemCount3),
   1020 		ITER(s_elemCount4),
   1021 		ITER(s_elemCount123),
   1022 		ITER(s_basicPause1),
   1023 		ITER(s_basicPause2),
   1024 		ITER(s_startPaused),
   1025 		ITER(s_random1),
   1026 		ITER(s_random2)
   1027 #undef ITER
   1028 	};
   1029 
   1030 	TestLog&				log				= m_testCtx.getLog();
   1031 	bool					isOk			= true;
   1032 	deUint32				seed			= deStringHash(getName()) ^ deInt32Hash(m_iterNdx);
   1033 	int						numIterations	= DE_LENGTH_OF_ARRAY(s_iterations);
   1034 	const DrawCall*			first			= s_iterations[m_iterNdx].calls;
   1035 	const DrawCall*			end				= s_iterations[m_iterNdx].calls + s_iterations[m_iterNdx].numCalls;
   1036 
   1037 	std::string				sectionName		= std::string("Iteration") + de::toString(m_iterNdx+1);
   1038 	std::string				sectionDesc		= std::string("Iteration ") + de::toString(m_iterNdx+1) + " / " + de::toString(numIterations);
   1039 	tcu::ScopedLogSection	section			(log, sectionName, sectionDesc);
   1040 
   1041 	log << TestLog::Message << "Testing " << s_iterations[m_iterNdx].numCalls << " draw calls, (element count, TF state): " << tcu::formatArray(first, end) << TestLog::EndMessage;
   1042 
   1043 	isOk = runTest(first, end, seed);
   1044 
   1045 	if (!isOk)
   1046 		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Result comparison failed");
   1047 
   1048 	m_iterNdx += 1;
   1049 	return (isOk && m_iterNdx < numIterations) ? CONTINUE : STOP;
   1050 }
   1051 
   1052 bool TransformFeedbackCase::runTest (const DrawCall* first, const DrawCall* end, deUint32 seed)
   1053 {
   1054 	TestLog&				log				= m_testCtx.getLog();
   1055 	const glw::Functions&	gl				= m_context.getRenderContext().getFunctions();
   1056 	de::Random				rnd				(seed);
   1057 	int						numInputs		= 0;		//!< Sum of element counts in calls.
   1058 	int						numOutputs		= 0;		//!< Sum of output counts for calls that have transform feedback enabled.
   1059 	int						width			= m_context.getRenderContext().getRenderTarget().getWidth();
   1060 	int						height			= m_context.getRenderContext().getRenderTarget().getHeight();
   1061 	int						viewportW		= de::min((int)VIEWPORT_WIDTH, width);
   1062 	int						viewportH		= de::min((int)VIEWPORT_HEIGHT, height);
   1063 	int						viewportX		= rnd.getInt(0, width-viewportW);
   1064 	int						viewportY		= rnd.getInt(0, height-viewportH);
   1065 	tcu::Surface			frameWithTf		(viewportW, viewportH);
   1066 	tcu::Surface			frameWithoutTf	(viewportW, viewportH);
   1067 	glu::Query				primitiveQuery	(m_context.getRenderContext());
   1068 	bool					outputsOk		= true;
   1069 	bool					imagesOk		= true;
   1070 	bool					queryOk			= true;
   1071 
   1072 	// Compute totals.
   1073 	for (const DrawCall* call = first; call != end; call++)
   1074 	{
   1075 		numInputs	+= call->numElements;
   1076 		numOutputs	+= call->transformFeedbackEnabled ? getTransformFeedbackOutputCount(m_primitiveType, call->numElements) : 0;
   1077 	}
   1078 
   1079 	// Input data.
   1080 	vector<deUint8> inputData(m_inputStride*numInputs);
   1081 	genInputData(m_attributes, numInputs, m_inputStride, &inputData[0], rnd);
   1082 
   1083 	gl.bindTransformFeedback(GL_TRANSFORM_FEEDBACK, m_transformFeedback->get());
   1084 	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTransformFeedback()");
   1085 
   1086 	// Allocate storage for transform feedback output buffers and bind to targets.
   1087 	for (int bufNdx = 0; bufNdx < (int)m_outputBuffers.size(); bufNdx++)
   1088 	{
   1089 		deUint32		buffer		= m_outputBuffers[bufNdx];
   1090 		int				stride		= m_bufferStrides[bufNdx];
   1091 		int				target		= bufNdx;
   1092 		int				size		= stride*numOutputs;
   1093 		int				guardSize	= stride*BUFFER_GUARD_MULTIPLIER;
   1094 		const deUint32	usage		= GL_DYNAMIC_READ;
   1095 
   1096 		gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, buffer);
   1097 		gl.bufferData(GL_TRANSFORM_FEEDBACK_BUFFER, size+guardSize, DE_NULL, usage);
   1098 		writeBufferGuard(gl, GL_TRANSFORM_FEEDBACK_BUFFER, size, guardSize);
   1099 
   1100 		// \todo [2012-07-30 pyry] glBindBufferRange()?
   1101 		gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, target, buffer);
   1102 
   1103 		GLU_EXPECT_NO_ERROR(gl.getError(), "transform feedback buffer setup");
   1104 	}
   1105 
   1106 	// Setup attributes.
   1107 	for (vector<Attribute>::const_iterator attrib = m_attributes.begin(); attrib != m_attributes.end(); attrib++)
   1108 	{
   1109 		int				loc				= gl.getAttribLocation(m_program->getProgram(), attrib->name.c_str());
   1110 		glu::DataType	scalarType		= glu::getDataTypeScalarType(attrib->type.getBasicType());
   1111 		int				numComponents	= glu::getDataTypeScalarSize(attrib->type.getBasicType());
   1112 		const void*		ptr				= &inputData[0] + attrib->offset;
   1113 
   1114 		if (loc >= 0)
   1115 		{
   1116 			gl.enableVertexAttribArray(loc);
   1117 
   1118 			if (scalarType == glu::TYPE_FLOAT)		gl.vertexAttribPointer	(loc, numComponents, GL_FLOAT, GL_FALSE, m_inputStride, ptr);
   1119 			else if (scalarType == glu::TYPE_INT)	gl.vertexAttribIPointer	(loc, numComponents, GL_INT, m_inputStride, ptr);
   1120 			else if (scalarType == glu::TYPE_UINT)	gl.vertexAttribIPointer	(loc, numComponents, GL_UNSIGNED_INT, m_inputStride, ptr);
   1121 		}
   1122 	}
   1123 
   1124 	// Setup viewport.
   1125 	gl.viewport(viewportX, viewportY, viewportW, viewportH);
   1126 
   1127 	// Setup program.
   1128 	gl.useProgram(m_program->getProgram());
   1129 
   1130 	gl.uniform4fv(gl.getUniformLocation(m_program->getProgram(), "u_scale"),	1, tcu::Vec4(0.01f).getPtr());
   1131 	gl.uniform4fv(gl.getUniformLocation(m_program->getProgram(), "u_bias"),		1, tcu::Vec4(0.5f).getPtr());
   1132 
   1133 	// Enable query.
   1134 	gl.beginQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, *primitiveQuery);
   1135 	GLU_EXPECT_NO_ERROR(gl.getError(), "glBeginQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN)");
   1136 
   1137 	// Draw.
   1138 	{
   1139 		int		offset		= 0;
   1140 		bool	tfEnabled	= true;
   1141 
   1142 		gl.clear(GL_COLOR_BUFFER_BIT);
   1143 
   1144 		gl.beginTransformFeedback(getTransformFeedbackPrimitiveMode(m_primitiveType));
   1145 
   1146 		for (const DrawCall* call = first; call != end; call++)
   1147 		{
   1148 			// Pause or resume transform feedback if necessary.
   1149 			if (call->transformFeedbackEnabled != tfEnabled)
   1150 			{
   1151 				if (call->transformFeedbackEnabled)
   1152 					gl.resumeTransformFeedback();
   1153 				else
   1154 					gl.pauseTransformFeedback();
   1155 				tfEnabled = call->transformFeedbackEnabled;
   1156 			}
   1157 
   1158 			gl.drawArrays(m_primitiveType, offset, call->numElements);
   1159 			offset += call->numElements;
   1160 		}
   1161 
   1162 		// Resume feedback before finishing it.
   1163 		if (!tfEnabled)
   1164 			gl.resumeTransformFeedback();
   1165 
   1166 		gl.endTransformFeedback();
   1167 		GLU_EXPECT_NO_ERROR(gl.getError(), "render");
   1168 	}
   1169 
   1170 	gl.endQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN);
   1171 	GLU_EXPECT_NO_ERROR(gl.getError(), "glEndQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN)");
   1172 
   1173 	// Check and log query status right after submit
   1174 	{
   1175 		deUint32 available = GL_FALSE;
   1176 		gl.getQueryObjectuiv(*primitiveQuery, GL_QUERY_RESULT_AVAILABLE, &available);
   1177 		GLU_EXPECT_NO_ERROR(gl.getError(), "glGetQueryObjectuiv()");
   1178 
   1179 		log << TestLog::Message << "GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN status after submit: " << (available != GL_FALSE ? "GL_TRUE" : "GL_FALSE") << TestLog::EndMessage;
   1180 	}
   1181 
   1182 	// Compare result buffers.
   1183 	for (int bufferNdx = 0; bufferNdx < (int)m_outputBuffers.size(); bufferNdx++)
   1184 	{
   1185 		deUint32		buffer		= m_outputBuffers[bufferNdx];
   1186 		int				stride		= m_bufferStrides[bufferNdx];
   1187 		int				size		= stride*numOutputs;
   1188 		int				guardSize	= stride*BUFFER_GUARD_MULTIPLIER;
   1189 		const void*		bufPtr		= DE_NULL;
   1190 
   1191 		// Bind buffer for reading.
   1192 		gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, buffer);
   1193 		bufPtr = gl.mapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, size+guardSize, GL_MAP_READ_BIT);
   1194 		GLU_EXPECT_NO_ERROR(gl.getError(), "mapping buffer");
   1195 
   1196 		// Verify all output variables that are written to this buffer.
   1197 		for (vector<Output>::const_iterator out = m_transformFeedbackOutputs.begin(); out != m_transformFeedbackOutputs.end(); out++)
   1198 		{
   1199 			if (out->bufferNdx != bufferNdx)
   1200 				continue;
   1201 
   1202 			int inputOffset		= 0;
   1203 			int	outputOffset	= 0;
   1204 
   1205 			// Process all draw calls and check ones with transform feedback enabled.
   1206 			for (const DrawCall* call = first; call != end; call++)
   1207 			{
   1208 				if (call->transformFeedbackEnabled)
   1209 				{
   1210 					const deUint8*	inputPtr	= &inputData[0] + inputOffset*m_inputStride;
   1211 					const deUint8*	outputPtr	= (const deUint8*)bufPtr + outputOffset*stride;
   1212 
   1213 					if (!compareTransformFeedbackOutput(log, m_primitiveType, *out, call->numElements, inputPtr, m_inputStride, outputPtr, stride))
   1214 					{
   1215 						outputsOk = false;
   1216 						break;
   1217 					}
   1218 				}
   1219 
   1220 				inputOffset		+= call->numElements;
   1221 				outputOffset	+= call->transformFeedbackEnabled ? getTransformFeedbackOutputCount(m_primitiveType, call->numElements) : 0;
   1222 			}
   1223 		}
   1224 
   1225 		// Verify guardband.
   1226 		if (!verifyGuard((const deUint8*)bufPtr + size, guardSize))
   1227 		{
   1228 			log << TestLog::Message << "Error: Transform feedback buffer overrun detected" << TestLog::EndMessage;
   1229 			outputsOk = false;
   1230 		}
   1231 
   1232 		gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
   1233 	}
   1234 
   1235 	// Check status after mapping buffers.
   1236 	{
   1237 		const bool	mustBeReady		= !m_outputBuffers.empty(); // Mapping buffer forces synchronization.
   1238 		const int	expectedCount	= computeTransformFeedbackPrimitiveCount(m_primitiveType, first, end);
   1239 		deUint32	available		= GL_FALSE;
   1240 		deUint32	numPrimitives	= 0;
   1241 
   1242 		gl.getQueryObjectuiv(*primitiveQuery, GL_QUERY_RESULT_AVAILABLE, &available);
   1243 		gl.getQueryObjectuiv(*primitiveQuery, GL_QUERY_RESULT, &numPrimitives);
   1244 		GLU_EXPECT_NO_ERROR(gl.getError(), "glGetQueryObjectuiv()");
   1245 
   1246 		if (!mustBeReady && available == GL_FALSE)
   1247 		{
   1248 			log << TestLog::Message << "ERROR: GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN result not available after mapping buffers!" << TestLog::EndMessage;
   1249 			queryOk = false;
   1250 		}
   1251 
   1252 		log << TestLog::Message << "GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN = " << numPrimitives << TestLog::EndMessage;
   1253 
   1254 		if ((int)numPrimitives != expectedCount)
   1255 		{
   1256 			log << TestLog::Message << "ERROR: Expected " << expectedCount << " primitives!" << TestLog::EndMessage;
   1257 			queryOk = false;
   1258 		}
   1259 	}
   1260 
   1261 	// Clear transform feedback state.
   1262 	gl.bindTransformFeedback(GL_TRANSFORM_FEEDBACK, 0);
   1263 	for (int bufNdx = 0; bufNdx < (int)m_outputBuffers.size(); bufNdx++)
   1264 	{
   1265 		gl.bindBuffer		(GL_TRANSFORM_FEEDBACK_BUFFER, 0);
   1266 		gl.bindBufferBase	(GL_TRANSFORM_FEEDBACK_BUFFER, bufNdx, 0);
   1267 	}
   1268 
   1269 	// Read back rendered image.
   1270 	glu::readPixels(m_context.getRenderContext(), viewportX, viewportY, frameWithTf.getAccess());
   1271 
   1272 	// Render without transform feedback.
   1273 	{
   1274 		int offset = 0;
   1275 
   1276 		gl.clear(GL_COLOR_BUFFER_BIT);
   1277 
   1278 		for (const DrawCall* call = first; call != end; call++)
   1279 		{
   1280 			gl.drawArrays(m_primitiveType, offset, call->numElements);
   1281 			offset += call->numElements;
   1282 		}
   1283 
   1284 		GLU_EXPECT_NO_ERROR(gl.getError(), "render");
   1285 		glu::readPixels(m_context.getRenderContext(), viewportX, viewportY, frameWithoutTf.getAccess());
   1286 	}
   1287 
   1288 	// Compare images with and without transform feedback.
   1289 	imagesOk = tcu::pixelThresholdCompare(log, "Result", "Image comparison result", frameWithoutTf, frameWithTf, tcu::RGBA(1, 1, 1, 1), tcu::COMPARE_LOG_ON_ERROR);
   1290 
   1291 	if (imagesOk)
   1292 		m_testCtx.getLog() << TestLog::Message << "Rendering result comparison between TF enabled and TF disabled passed." << TestLog::EndMessage;
   1293 	else
   1294 		m_testCtx.getLog() << TestLog::Message << "ERROR: Rendering result comparison between TF enabled and TF disabled failed!" << TestLog::EndMessage;
   1295 
   1296 	return outputsOk && imagesOk && queryOk;
   1297 }
   1298 
   1299 // Test cases.
   1300 
   1301 class PositionCase : public TransformFeedbackCase
   1302 {
   1303 public:
   1304 	PositionCase (Context& context, const char* name, const char* desc, deUint32 bufferType, deUint32 primitiveType)
   1305 		: TransformFeedbackCase(context, name, desc, bufferType, primitiveType)
   1306 	{
   1307 		m_progSpec.addTransformFeedbackVarying("gl_Position");
   1308 	}
   1309 };
   1310 
   1311 class PointSizeCase : public TransformFeedbackCase
   1312 {
   1313 public:
   1314 	PointSizeCase (Context& context, const char* name, const char* desc, deUint32 bufferType, deUint32 primitiveType)
   1315 		: TransformFeedbackCase(context, name, desc, bufferType, primitiveType)
   1316 	{
   1317 		m_progSpec.addTransformFeedbackVarying("gl_PointSize");
   1318 	}
   1319 };
   1320 
   1321 class BasicTypeCase : public TransformFeedbackCase
   1322 {
   1323 public:
   1324 	BasicTypeCase (Context& context, const char* name, const char* desc, deUint32 bufferType, deUint32 primitiveType, glu::DataType type, glu::Precision precision, Interpolation interpolation)
   1325 		: TransformFeedbackCase(context, name, desc, bufferType, primitiveType)
   1326 	{
   1327 		m_progSpec.addVarying("v_varA", glu::VarType(type, precision), interpolation);
   1328 		m_progSpec.addVarying("v_varB", glu::VarType(type, precision), interpolation);
   1329 
   1330 		m_progSpec.addTransformFeedbackVarying("v_varA");
   1331 		m_progSpec.addTransformFeedbackVarying("v_varB");
   1332 	}
   1333 };
   1334 
   1335 class BasicArrayCase : public TransformFeedbackCase
   1336 {
   1337 public:
   1338 	BasicArrayCase (Context& context, const char* name, const char* desc, deUint32 bufferType, deUint32 primitiveType, glu::DataType type, glu::Precision precision, Interpolation interpolation)
   1339 		: TransformFeedbackCase(context, name, desc, bufferType, primitiveType)
   1340 	{
   1341 		if (glu::isDataTypeMatrix(type) || m_bufferMode == GL_SEPARATE_ATTRIBS)
   1342 		{
   1343 			// \note For matrix types we need to use reduced array sizes or otherwise we will exceed maximum attribute (16)
   1344 			//		 or transform feedback component count (64).
   1345 			//		 On separate attribs mode maximum component count per varying is 4.
   1346 			m_progSpec.addVarying("v_varA", glu::VarType(glu::VarType(type, precision), 1), interpolation);
   1347 			m_progSpec.addVarying("v_varB", glu::VarType(glu::VarType(type, precision), 2), interpolation);
   1348 		}
   1349 		else
   1350 		{
   1351 			m_progSpec.addVarying("v_varA", glu::VarType(glu::VarType(type, precision), 3), interpolation);
   1352 			m_progSpec.addVarying("v_varB", glu::VarType(glu::VarType(type, precision), 4), interpolation);
   1353 		}
   1354 
   1355 		m_progSpec.addTransformFeedbackVarying("v_varA");
   1356 		m_progSpec.addTransformFeedbackVarying("v_varB");
   1357 	}
   1358 };
   1359 
   1360 class ArrayElementCase : public TransformFeedbackCase
   1361 {
   1362 public:
   1363 	ArrayElementCase (Context& context, const char* name, const char* desc, deUint32 bufferType, deUint32 primitiveType, glu::DataType type, glu::Precision precision, Interpolation interpolation)
   1364 		: TransformFeedbackCase(context, name, desc, bufferType, primitiveType)
   1365 	{
   1366 		m_progSpec.addVarying("v_varA", glu::VarType(glu::VarType(type, precision), 3), interpolation);
   1367 		m_progSpec.addVarying("v_varB", glu::VarType(glu::VarType(type, precision), 4), interpolation);
   1368 
   1369 		m_progSpec.addTransformFeedbackVarying("v_varA[1]");
   1370 		m_progSpec.addTransformFeedbackVarying("v_varB[0]");
   1371 		m_progSpec.addTransformFeedbackVarying("v_varB[3]");
   1372 	}
   1373 };
   1374 
   1375 class RandomCase : public TransformFeedbackCase
   1376 {
   1377 public:
   1378 	RandomCase (Context& context, const char* name, const char* desc, deUint32 bufferType, deUint32 primitiveType, deUint32 seed)
   1379 		: TransformFeedbackCase	(context, name, desc, bufferType, primitiveType)
   1380 		, m_seed				(seed)
   1381 	{
   1382 	}
   1383 
   1384 	void init (void)
   1385 	{
   1386 		// \note Hard-coded indices and hackery are used when indexing this, beware.
   1387 		static const glu::DataType typeCandidates[] =
   1388 		{
   1389 			glu::TYPE_FLOAT,
   1390 			glu::TYPE_FLOAT_VEC2,
   1391 			glu::TYPE_FLOAT_VEC3,
   1392 			glu::TYPE_FLOAT_VEC4,
   1393 			glu::TYPE_INT,
   1394 			glu::TYPE_INT_VEC2,
   1395 			glu::TYPE_INT_VEC3,
   1396 			glu::TYPE_INT_VEC4,
   1397 			glu::TYPE_UINT,
   1398 			glu::TYPE_UINT_VEC2,
   1399 			glu::TYPE_UINT_VEC3,
   1400 			glu::TYPE_UINT_VEC4,
   1401 
   1402 			glu::TYPE_FLOAT_MAT2,
   1403 			glu::TYPE_FLOAT_MAT2X3,
   1404 			glu::TYPE_FLOAT_MAT2X4,
   1405 
   1406 			glu::TYPE_FLOAT_MAT3X2,
   1407 			glu::TYPE_FLOAT_MAT3,
   1408 			glu::TYPE_FLOAT_MAT3X4,
   1409 
   1410 			glu::TYPE_FLOAT_MAT4X2,
   1411 			glu::TYPE_FLOAT_MAT4X3,
   1412 			glu::TYPE_FLOAT_MAT4
   1413 		};
   1414 
   1415 		static const glu::Precision precisions[] =
   1416 		{
   1417 			glu::PRECISION_LOWP,
   1418 			glu::PRECISION_MEDIUMP,
   1419 			glu::PRECISION_HIGHP
   1420 		};
   1421 
   1422 		static const Interpolation interpModes[] =
   1423 		{
   1424 			INTERPOLATION_FLAT,
   1425 			INTERPOLATION_SMOOTH,
   1426 			INTERPOLATION_CENTROID
   1427 		};
   1428 
   1429 		const int	maxAttributeVectors					= 16;
   1430 //		const int	maxTransformFeedbackComponents		= 64; // \note It is enough to limit attribute set size.
   1431 		bool		isSeparateMode						= m_bufferMode == GL_SEPARATE_ATTRIBS;
   1432 		int			maxTransformFeedbackVars			= isSeparateMode ? 4 : maxAttributeVectors;
   1433 		const float	arrayWeight							= 0.3f;
   1434 		const float	positionWeight						= 0.7f;
   1435 		const float	pointSizeWeight						= 0.1f;
   1436 		const float	captureFullArrayWeight				= 0.5f;
   1437 
   1438 		de::Random	rnd									(m_seed);
   1439 		bool		usePosition							= rnd.getFloat() < positionWeight;
   1440 		bool		usePointSize						= rnd.getFloat() < pointSizeWeight;
   1441 		int			numAttribVectorsToUse				= rnd.getInt(1, maxAttributeVectors - 1/*position*/ - (usePointSize ? 1 : 0));
   1442 
   1443 		int			numAttributeVectors					= 0;
   1444 		int			varNdx								= 0;
   1445 
   1446 		// Generate varyings.
   1447 		while (numAttributeVectors < numAttribVectorsToUse)
   1448 		{
   1449 			int						maxVecs		= isSeparateMode ? de::min(2 /*at most 2*mat2*/, numAttribVectorsToUse-numAttributeVectors) : numAttribVectorsToUse-numAttributeVectors;
   1450 			const glu::DataType*	begin		= &typeCandidates[0];
   1451 			const glu::DataType*	end			= begin + (maxVecs >= 4 ? 21 :
   1452 														   maxVecs >= 3 ? 18 :
   1453 														   maxVecs >= 2 ? (isSeparateMode ? 13 : 15) : 12);
   1454 
   1455 			glu::DataType			type		= rnd.choose<glu::DataType>(begin, end);
   1456 			glu::Precision			precision	= rnd.choose<glu::Precision>(&precisions[0], &precisions[0]+DE_LENGTH_OF_ARRAY(precisions));
   1457 			Interpolation			interp		= glu::getDataTypeScalarType(type) == glu::TYPE_FLOAT
   1458 												? rnd.choose<Interpolation>(&interpModes[0], &interpModes[0]+DE_LENGTH_OF_ARRAY(interpModes))
   1459 												: INTERPOLATION_FLAT;
   1460 			int						numVecs		= glu::isDataTypeMatrix(type) ? glu::getDataTypeMatrixNumColumns(type) : 1;
   1461 			int						numComps	= glu::getDataTypeScalarSize(type);
   1462 			int						maxArrayLen	= de::max(1, isSeparateMode ? 4/numComps : maxVecs/numVecs);
   1463 			bool					useArray	= rnd.getFloat() < arrayWeight;
   1464 			int						arrayLen	= useArray ? rnd.getInt(1, maxArrayLen) : 1;
   1465 			std::string				name		= "v_var" + de::toString(varNdx);
   1466 
   1467 			if (useArray)
   1468 				m_progSpec.addVarying(name.c_str(), glu::VarType(glu::VarType(type, precision), arrayLen), interp);
   1469 			else
   1470 				m_progSpec.addVarying(name.c_str(), glu::VarType(type, precision), interp);
   1471 
   1472 			numAttributeVectors	+= arrayLen*numVecs;
   1473 			varNdx				+= 1;
   1474 		}
   1475 
   1476 		// Generate transform feedback candidate set.
   1477 		vector<string> tfCandidates;
   1478 
   1479 		if (usePosition)	tfCandidates.push_back("gl_Position");
   1480 		if (usePointSize)	tfCandidates.push_back("gl_PointSize");
   1481 
   1482 		for (int ndx = 0; ndx < varNdx /* num varyings */; ndx++)
   1483 		{
   1484 			const Varying& var = m_progSpec.getVaryings()[ndx];
   1485 
   1486 			if (var.type.isArrayType())
   1487 			{
   1488 				const bool captureFull = rnd.getFloat() < captureFullArrayWeight;
   1489 
   1490 				if (captureFull)
   1491 					tfCandidates.push_back(var.name);
   1492 				else
   1493 				{
   1494 					const int numElem = var.type.getArraySize();
   1495 					for (int elemNdx = 0; elemNdx < numElem; elemNdx++)
   1496 						tfCandidates.push_back(var.name + "[" + de::toString(elemNdx) + "]");
   1497 				}
   1498 			}
   1499 			else
   1500 				tfCandidates.push_back(var.name);
   1501 		}
   1502 
   1503 		// Pick random selection.
   1504 		vector<string> tfVaryings(de::min((int)tfCandidates.size(), maxTransformFeedbackVars));
   1505 		rnd.choose(tfCandidates.begin(), tfCandidates.end(), tfVaryings.begin(), (int)tfVaryings.size());
   1506 		rnd.shuffle(tfVaryings.begin(), tfVaryings.end());
   1507 
   1508 		for (vector<string>::const_iterator var = tfVaryings.begin(); var != tfVaryings.end(); var++)
   1509 			m_progSpec.addTransformFeedbackVarying(var->c_str());
   1510 
   1511 		TransformFeedbackCase::init();
   1512 	}
   1513 
   1514 private:
   1515 	deUint32 m_seed;
   1516 };
   1517 
   1518 } // TransformFeedback
   1519 
   1520 using namespace TransformFeedback;
   1521 
   1522 TransformFeedbackTests::TransformFeedbackTests (Context& context)
   1523 	: TestCaseGroup(context, "transform_feedback", "Transform feedback tests")
   1524 {
   1525 }
   1526 
   1527 TransformFeedbackTests::~TransformFeedbackTests (void)
   1528 {
   1529 }
   1530 
   1531 void TransformFeedbackTests::init (void)
   1532 {
   1533 	static const struct
   1534 	{
   1535 		const char*		name;
   1536 		deUint32		mode;
   1537 	} bufferModes[] =
   1538 	{
   1539 		{ "separate",		GL_SEPARATE_ATTRIBS		},
   1540 		{ "interleaved",	GL_INTERLEAVED_ATTRIBS	}
   1541 	};
   1542 
   1543 	static const struct
   1544 	{
   1545 		const char*		name;
   1546 		deUint32		type;
   1547 	} primitiveTypes[] =
   1548 	{
   1549 		{ "points",			GL_POINTS			},
   1550 		{ "lines",			GL_LINES			},
   1551 		{ "triangles",		GL_TRIANGLES		}
   1552 
   1553 		// Not supported by GLES3.
   1554 //		{ "line_strip",		GL_LINE_STRIP		},
   1555 //		{ "line_loop",		GL_LINE_LOOP		},
   1556 //		{ "triangle_fan",	GL_TRIANGLE_FAN		},
   1557 //		{ "triangle_strip",	GL_TRIANGLE_STRIP	}
   1558 	};
   1559 
   1560 	static const glu::DataType basicTypes[] =
   1561 	{
   1562 		glu::TYPE_FLOAT,
   1563 		glu::TYPE_FLOAT_VEC2,
   1564 		glu::TYPE_FLOAT_VEC3,
   1565 		glu::TYPE_FLOAT_VEC4,
   1566 		glu::TYPE_FLOAT_MAT2,
   1567 		glu::TYPE_FLOAT_MAT2X3,
   1568 		glu::TYPE_FLOAT_MAT2X4,
   1569 		glu::TYPE_FLOAT_MAT3X2,
   1570 		glu::TYPE_FLOAT_MAT3,
   1571 		glu::TYPE_FLOAT_MAT3X4,
   1572 		glu::TYPE_FLOAT_MAT4X2,
   1573 		glu::TYPE_FLOAT_MAT4X3,
   1574 		glu::TYPE_FLOAT_MAT4,
   1575 		glu::TYPE_INT,
   1576 		glu::TYPE_INT_VEC2,
   1577 		glu::TYPE_INT_VEC3,
   1578 		glu::TYPE_INT_VEC4,
   1579 		glu::TYPE_UINT,
   1580 		glu::TYPE_UINT_VEC2,
   1581 		glu::TYPE_UINT_VEC3,
   1582 		glu::TYPE_UINT_VEC4
   1583 	};
   1584 
   1585 	static const glu::Precision precisions[] =
   1586 	{
   1587 		glu::PRECISION_LOWP,
   1588 		glu::PRECISION_MEDIUMP,
   1589 		glu::PRECISION_HIGHP
   1590 	};
   1591 
   1592 	static const struct
   1593 	{
   1594 		const char*		name;
   1595 		Interpolation	interp;
   1596 	} interpModes[] =
   1597 	{
   1598 		{ "smooth",		INTERPOLATION_SMOOTH	},
   1599 		{ "flat",		INTERPOLATION_FLAT		},
   1600 		{ "centroid",	INTERPOLATION_CENTROID	}
   1601 	};
   1602 
   1603 	// .position
   1604 	{
   1605 		tcu::TestCaseGroup* positionGroup = new tcu::TestCaseGroup(m_testCtx, "position", "gl_Position capture using transform feedback");
   1606 		addChild(positionGroup);
   1607 
   1608 		for (int primitiveType = 0; primitiveType < DE_LENGTH_OF_ARRAY(primitiveTypes); primitiveType++)
   1609 		{
   1610 			for (int bufferMode = 0; bufferMode < DE_LENGTH_OF_ARRAY(bufferModes); bufferMode++)
   1611 			{
   1612 				string name = string(primitiveTypes[primitiveType].name) + "_" + bufferModes[bufferMode].name;
   1613 				positionGroup->addChild(new PositionCase(m_context, name.c_str(), "", bufferModes[bufferMode].mode, primitiveTypes[primitiveType].type));
   1614 			}
   1615 		}
   1616 	}
   1617 
   1618 	// .point_size
   1619 	{
   1620 		tcu::TestCaseGroup* pointSizeGroup = new tcu::TestCaseGroup(m_testCtx, "point_size", "gl_PointSize capture using transform feedback");
   1621 		addChild(pointSizeGroup);
   1622 
   1623 		for (int primitiveType = 0; primitiveType < DE_LENGTH_OF_ARRAY(primitiveTypes); primitiveType++)
   1624 		{
   1625 			for (int bufferMode = 0; bufferMode < DE_LENGTH_OF_ARRAY(bufferModes); bufferMode++)
   1626 			{
   1627 				string name = string(primitiveTypes[primitiveType].name) + "_" + bufferModes[bufferMode].name;
   1628 				pointSizeGroup->addChild(new PointSizeCase(m_context, name.c_str(), "", bufferModes[bufferMode].mode, primitiveTypes[primitiveType].type));
   1629 			}
   1630 		}
   1631 	}
   1632 
   1633 	// .basic_type
   1634 	{
   1635 		tcu::TestCaseGroup* basicTypeGroup = new tcu::TestCaseGroup(m_testCtx, "basic_types", "Basic types in transform feedback");
   1636 		addChild(basicTypeGroup);
   1637 
   1638 		for (int bufferModeNdx = 0; bufferModeNdx < DE_LENGTH_OF_ARRAY(bufferModes); bufferModeNdx++)
   1639 		{
   1640 			tcu::TestCaseGroup* modeGroup	= new tcu::TestCaseGroup(m_testCtx, bufferModes[bufferModeNdx].name, "");
   1641 			deUint32			bufferMode	= bufferModes[bufferModeNdx].mode;
   1642 			basicTypeGroup->addChild(modeGroup);
   1643 
   1644 			for (int primitiveTypeNdx = 0; primitiveTypeNdx < DE_LENGTH_OF_ARRAY(primitiveTypes); primitiveTypeNdx++)
   1645 			{
   1646 				tcu::TestCaseGroup* primitiveGroup	= new tcu::TestCaseGroup(m_testCtx, primitiveTypes[primitiveTypeNdx].name, "");
   1647 				deUint32			primitiveType	= primitiveTypes[primitiveTypeNdx].type;
   1648 				modeGroup->addChild(primitiveGroup);
   1649 
   1650 				for (int typeNdx = 0; typeNdx < DE_LENGTH_OF_ARRAY(basicTypes); typeNdx++)
   1651 				{
   1652 					glu::DataType		type		= basicTypes[typeNdx];
   1653 					bool				isFloat		= glu::getDataTypeScalarType(type) == glu::TYPE_FLOAT;
   1654 
   1655 					for (int precNdx = 0; precNdx < DE_LENGTH_OF_ARRAY(precisions); precNdx++)
   1656 					{
   1657 						glu::Precision precision = precisions[precNdx];
   1658 
   1659 						string name = string(glu::getPrecisionName(precision)) + "_" + glu::getDataTypeName(type);
   1660 						primitiveGroup->addChild(new BasicTypeCase(m_context, name.c_str(), "", bufferMode, primitiveType, type, precision, isFloat ? INTERPOLATION_SMOOTH : INTERPOLATION_FLAT));
   1661 					}
   1662 				}
   1663 			}
   1664 		}
   1665 	}
   1666 
   1667 	// .array
   1668 	{
   1669 		tcu::TestCaseGroup* arrayGroup = new tcu::TestCaseGroup(m_testCtx, "array", "Capturing whole array in TF");
   1670 		addChild(arrayGroup);
   1671 
   1672 		for (int bufferModeNdx = 0; bufferModeNdx < DE_LENGTH_OF_ARRAY(bufferModes); bufferModeNdx++)
   1673 		{
   1674 			tcu::TestCaseGroup* modeGroup	= new tcu::TestCaseGroup(m_testCtx, bufferModes[bufferModeNdx].name, "");
   1675 			deUint32			bufferMode	= bufferModes[bufferModeNdx].mode;
   1676 			arrayGroup->addChild(modeGroup);
   1677 
   1678 			for (int primitiveTypeNdx = 0; primitiveTypeNdx < DE_LENGTH_OF_ARRAY(primitiveTypes); primitiveTypeNdx++)
   1679 			{
   1680 				tcu::TestCaseGroup* primitiveGroup	= new tcu::TestCaseGroup(m_testCtx, primitiveTypes[primitiveTypeNdx].name, "");
   1681 				deUint32			primitiveType	= primitiveTypes[primitiveTypeNdx].type;
   1682 				modeGroup->addChild(primitiveGroup);
   1683 
   1684 				for (int typeNdx = 0; typeNdx < DE_LENGTH_OF_ARRAY(basicTypes); typeNdx++)
   1685 				{
   1686 					glu::DataType		type		= basicTypes[typeNdx];
   1687 					bool				isFloat		= glu::getDataTypeScalarType(type) == glu::TYPE_FLOAT;
   1688 
   1689 					for (int precNdx = 0; precNdx < DE_LENGTH_OF_ARRAY(precisions); precNdx++)
   1690 					{
   1691 						glu::Precision precision = precisions[precNdx];
   1692 
   1693 						string name = string(glu::getPrecisionName(precision)) + "_" + glu::getDataTypeName(type);
   1694 						primitiveGroup->addChild(new BasicArrayCase(m_context, name.c_str(), "", bufferMode, primitiveType, type, precision, isFloat ? INTERPOLATION_SMOOTH : INTERPOLATION_FLAT));
   1695 					}
   1696 				}
   1697 			}
   1698 		}
   1699 	}
   1700 
   1701 	// .array_element
   1702 	{
   1703 		tcu::TestCaseGroup* arrayElemGroup = new tcu::TestCaseGroup(m_testCtx, "array_element", "Capturing single array element in TF");
   1704 		addChild(arrayElemGroup);
   1705 
   1706 		for (int bufferModeNdx = 0; bufferModeNdx < DE_LENGTH_OF_ARRAY(bufferModes); bufferModeNdx++)
   1707 		{
   1708 			tcu::TestCaseGroup* modeGroup	= new tcu::TestCaseGroup(m_testCtx, bufferModes[bufferModeNdx].name, "");
   1709 			deUint32			bufferMode	= bufferModes[bufferModeNdx].mode;
   1710 			arrayElemGroup->addChild(modeGroup);
   1711 
   1712 			for (int primitiveTypeNdx = 0; primitiveTypeNdx < DE_LENGTH_OF_ARRAY(primitiveTypes); primitiveTypeNdx++)
   1713 			{
   1714 				tcu::TestCaseGroup* primitiveGroup	= new tcu::TestCaseGroup(m_testCtx, primitiveTypes[primitiveTypeNdx].name, "");
   1715 				deUint32			primitiveType	= primitiveTypes[primitiveTypeNdx].type;
   1716 				modeGroup->addChild(primitiveGroup);
   1717 
   1718 				for (int typeNdx = 0; typeNdx < DE_LENGTH_OF_ARRAY(basicTypes); typeNdx++)
   1719 				{
   1720 					glu::DataType		type		= basicTypes[typeNdx];
   1721 					bool				isFloat		= glu::getDataTypeScalarType(type) == glu::TYPE_FLOAT;
   1722 
   1723 					for (int precNdx = 0; precNdx < DE_LENGTH_OF_ARRAY(precisions); precNdx++)
   1724 					{
   1725 						glu::Precision precision = precisions[precNdx];
   1726 
   1727 						string name = string(glu::getPrecisionName(precision)) + "_" + glu::getDataTypeName(type);
   1728 						primitiveGroup->addChild(new ArrayElementCase(m_context, name.c_str(), "", bufferMode, primitiveType, type, precision, isFloat ? INTERPOLATION_SMOOTH : INTERPOLATION_FLAT));
   1729 					}
   1730 				}
   1731 			}
   1732 		}
   1733 	}
   1734 
   1735 	// .interpolation
   1736 	{
   1737 		tcu::TestCaseGroup* interpolationGroup = new tcu::TestCaseGroup(m_testCtx, "interpolation", "Different interpolation modes in transform feedback varyings");
   1738 		addChild(interpolationGroup);
   1739 
   1740 		for (int modeNdx = 0; modeNdx < DE_LENGTH_OF_ARRAY(interpModes); modeNdx++)
   1741 		{
   1742 			Interpolation		interp		= interpModes[modeNdx].interp;
   1743 			tcu::TestCaseGroup*	modeGroup	= new tcu::TestCaseGroup(m_testCtx, interpModes[modeNdx].name, "");
   1744 
   1745 			interpolationGroup->addChild(modeGroup);
   1746 
   1747 			for (int precNdx = 0; precNdx < DE_LENGTH_OF_ARRAY(precisions); precNdx++)
   1748 			{
   1749 				glu::Precision precision = precisions[precNdx];
   1750 
   1751 				for (int primitiveType = 0; primitiveType < DE_LENGTH_OF_ARRAY(primitiveTypes); primitiveType++)
   1752 				{
   1753 					for (int bufferMode = 0; bufferMode < DE_LENGTH_OF_ARRAY(bufferModes); bufferMode++)
   1754 					{
   1755 						string name = string(glu::getPrecisionName(precision)) + "_vec4_" + primitiveTypes[primitiveType].name + "_" + bufferModes[bufferMode].name;
   1756 						modeGroup->addChild(new BasicTypeCase(m_context, name.c_str(), "", bufferModes[bufferMode].mode, primitiveTypes[primitiveType].type, glu::TYPE_FLOAT_VEC4, precision, interp));
   1757 					}
   1758 				}
   1759 			}
   1760 		}
   1761 	}
   1762 
   1763 	// .random
   1764 	{
   1765 		tcu::TestCaseGroup* randomGroup = new tcu::TestCaseGroup(m_testCtx, "random", "Randomized transform feedback cases");
   1766 		addChild(randomGroup);
   1767 
   1768 		for (int bufferModeNdx = 0; bufferModeNdx < DE_LENGTH_OF_ARRAY(bufferModes); bufferModeNdx++)
   1769 		{
   1770 			tcu::TestCaseGroup* modeGroup	= new tcu::TestCaseGroup(m_testCtx, bufferModes[bufferModeNdx].name, "");
   1771 			deUint32			bufferMode	= bufferModes[bufferModeNdx].mode;
   1772 			randomGroup->addChild(modeGroup);
   1773 
   1774 			for (int primitiveTypeNdx = 0; primitiveTypeNdx < DE_LENGTH_OF_ARRAY(primitiveTypes); primitiveTypeNdx++)
   1775 			{
   1776 				tcu::TestCaseGroup* primitiveGroup	= new tcu::TestCaseGroup(m_testCtx, primitiveTypes[primitiveTypeNdx].name, "");
   1777 				deUint32			primitiveType	= primitiveTypes[primitiveTypeNdx].type;
   1778 				modeGroup->addChild(primitiveGroup);
   1779 
   1780 				for (int ndx = 0; ndx < 10; ndx++)
   1781 				{
   1782 					deUint32 seed = deInt32Hash(bufferMode) ^ deInt32Hash(primitiveType) ^ deInt32Hash(ndx);
   1783 					primitiveGroup->addChild(new RandomCase(m_context, de::toString(ndx+1).c_str(), "", bufferMode, primitiveType, seed));
   1784 				}
   1785 			}
   1786 		}
   1787 	}
   1788 }
   1789 
   1790 } // Functional
   1791 } // gles3
   1792 } // deqp
   1793